惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
宝玉的分享
宝玉的分享
量子位
博客园 - 叶小钗
博客园_首页
Know Your Adversary
Know Your Adversary
S
Schneier on Security
罗磊的独立博客
C
Cyber Attacks, Cyber Crime and Cyber Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Simon Willison's Weblog
Simon Willison's Weblog
美团技术团队
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
Hacker News: Ask HN
Hacker News: Ask HN
Application and Cybersecurity Blog
Application and Cybersecurity Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Latest
Security Latest
月光博客
月光博客
Spread Privacy
Spread Privacy
C
Cybersecurity and Infrastructure Security Agency CISA
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
C
CERT Recently Published Vulnerability Notes
Last Week in AI
Last Week in AI
Attack and Defense Labs
Attack and Defense Labs
NISL@THU
NISL@THU
H
Hacker News: Front Page
N
News and Events Feed by Topic
小众软件
小众软件
T
Threatpost
V2EX - 技术
V2EX - 技术
T
Tailwind CSS Blog
阮一峰的网络日志
阮一峰的网络日志
Project Zero
Project Zero
L
LINUX DO - 热门话题
Apple Machine Learning Research
Apple Machine Learning Research
C
CXSECURITY Database RSS Feed - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
P
Privacy International News Feed
Latest news
Latest news
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
AWS News Blog
AWS News Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog

博客园 - sobaby

Sql Server的两个小技巧 用vue.js重构订单计算页面 用vue.js实现购物车功能 一步步实现自己的ORM(五) 一步步实现自己的ORM(四) 将Object转换成Dictionary方法 一步步实现自己的ORM(二) 一步步实现自己的ORM(一) 修复Windows XP服务扩展视图显示空白 ASP.NET MVC :MVC页面验证与授权 一起学习MVC(4)-entity SQL语句 一起学习MVC(3)-搭建项目 一起学习MVC(2)-数据库设计 一起学习MVC(1)-搭建开发环境 什么是工作流 学习WWF中 关于回调函数 ASP.net:水晶报表的5种表格设计模式 ASP.NET 安全认证(一):如何运用 Form 表单认证
一步步实现自己的ORM(三)
sobaby · 2015-03-20 · via 博客园 - sobaby

章节列表:

一步步实现自己的ORM(一)

一步步实现自己的ORM(二)

通过前面两篇文章,我们大致了解了ORM的基本原理,是通过Attribute+反射获取表的基本信息,再用表名和字段名拼接成SQL语句。而前面我们只是完成了CRUD部分的CUD,还没完成读取(Retrieve)操作,今天就来完成这个R操作。我们先看下平时写实体类转换代码是怎么写的:

        static List<User> ToObject1()
        {
            SqlDataReader reader = null;
            List<User> list = new List<User>();
            while (reader.Read())
            {
                User user = new User();
                if (reader["UserId"] != null)
                    user.UserId = (int)reader["UserId"];

                if (reader["Email"] != null)
                    user.Email = (string)reader["Email"];

                if (reader["CreatedTime"] != null)
                    user.CreatedTime = (DateTime)reader["CreatedTime"];

                list.Add(user);
            }
            return list;
        }

经常写DataReader对象转换成实体类的童鞋们,WHILE循环里的内容是根据实体类的不同代码而有所不同,循环外的代码则是固定不变的,现在我们要把变化的代码抽离出来,我们还是请出明星--反射。

在前面章节我们都是用反射读取实体类里的,比如typeof(User).GetProperty("UserId").GetValue(obj,null),有GetValue肯定也有SetValue,我们看下SetValue的定义:

public virtual void SetValue(
    Object obj,
    Object value,
    Object[] index
)

obj:将设置其属性值的对象。

value:新的属性值。

index : 索引化属性的可选索引值。 对于非索引化属性,该值应为 null。 

示例代码:

            User user = new User();
            typeof(User).GetProperty("UserId").SetValue(user, 10, null);
            Console.WriteLine(user.UserId);

输出结果我就不贴图了,是“10”。

HOHO,我们开始构建代码,步骤如下:

  1. new 实体类对象

  2. 反射类的属性,然后用SetValue给实体类属性赋值

具体代码如下:

            string sql = "select * from tb_users";
            SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
            conn.Open();

           var cmd =  conn.CreateCommand();
           cmd.CommandText = sql;

            SqlDataReader reader = cmd.ExecuteReader();
            List<User> list = new List<User>();
            var type = typeof(User);
            var properties = type.GetProperties();
            while (reader.Read())
            {
                User user = new User();
                for (int i = 0; i < properties.Length; i++)
                {
                    var pi = properties[i];
                    if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
                        pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
                }

                list.Add(user);
            }

            foreach (var item in list)
            {
                Console.WriteLine("UserId:{0},Email:{1},CreatedTime:{2}", item.UserId, item.Email, item.CreatedTime);
            }

View Code

运行结果:

下面一个问题来了,我们看这一行代码

难道我们每次都要这么写这样的代码吗,能不能做一个通用的吗?这需要我们用反射实例化一个类,我们请Activator.CreateInstance帮忙创建实例,代码如下:

                var type = typeof(User);
                var user = Activator.CreateInstance(type);

创建实例和给属性赋值都动态完成,我稍稍修改下代码,只要传递SQL语句就可以返回集合。

        static List<T> GetEntityList<T>(string sql)
        {
            SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
            conn.Open();

            var cmd = conn.CreateCommand();
            cmd.CommandText = sql;

            SqlDataReader reader = cmd.ExecuteReader();
            List<T> list = new List<T>();
            var type = typeof(T);
            var properties = type.GetProperties();
            while (reader.Read())
            {
                var user = Activator.CreateInstance(type);
                for (int i = 0; i < properties.Length; i++)
                {
                    var pi = properties[i];
                    if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
                        pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
                }

                list.Add((T)user);
            }
            return list;
        }

View Code

最后我们在增加如下方法:

Get(object[] values) 根据主键获取实体类

GetList<T>(string where,string orderBy) 按条件查询实体类

        public static T Get<T>(object[] values)
        {
            var type = typeof(T);
            Dictionary<string, object> parameters = new Dictionary<string, object>();
            var properties = type.GetProperties();

            string tableName = string.Empty;
            TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true);
            if (tableAttrs.Length > 0)
            {
                tableName = tableAttrs[0].Name;
            }
            else
            {
                tableName = type.Name;
            }

            /*将所有的列放到集合里*/
            List<IdAttribute> columns = new List<IdAttribute>();
            for (int i = 0; i < properties.Length; i++)
            {
                var pi = properties[i];
                var attrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true);
                if (attrs.Length > 0)
                {
                    columns.Add(attrs[0]);
                }
            }
            if (columns.Count != values.Length)
                throw new ArgumentException("参数个数和主键数不一致");

            StringBuilder sql = new StringBuilder();
            sql.Append("SELECT * FROM [").Append(tableName).Append("] ").Append(" WHERE ");

            for (int i = 0; i < columns.Count; i++)
            {
                if (i > 0) //考虑到有多个主键
                    sql.Append(" AND ");

                sql.Append(columns[i].Name).Append("=").Append("@p").Append(i);

                /*参数*/
                parameters.Add("@p" + i, values[i]);
            }
            Console.WriteLine(sql);
            return GetEntityList<T>(sql.ToString(), parameters).FirstOrDefault();
        }
        public static List<T> GetList<T>(string where,string orderBy)
        {
            var type = typeof(T);
            Dictionary<string, object> parameters = new Dictionary<string, object>();
            var properties = type.GetProperties();

            string tableName = string.Empty;
            TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true);
            if (tableAttrs.Length > 0)
            {
                tableName = tableAttrs[0].Name;
            }
            else
            {
                tableName = type.Name;
            }


            StringBuilder sql = new StringBuilder();
            sql.Append("SELECT * FROM [").Append(tableName).Append("] ");
            if (string.IsNullOrEmpty(where))
                sql.Append(" WHERE ").Append(where);

            if (string.IsNullOrEmpty(orderBy))
                sql.Append(" Order By ").Append(orderBy);


            Console.WriteLine(sql);
            return GetEntityList<T>(sql.ToString(), parameters);
        }

        public static List<T> GetEntityList<T>(string sql, Dictionary<string, object> parameters)
        {
            SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
            conn.Open();

            var cmd = conn.CreateCommand();
            cmd.CommandText = sql;
            if (parameters != null && parameters.Count > 0)
            {
                foreach (var item in parameters)
                {
                    var pa = cmd.CreateParameter();
                    pa.ParameterName = item.Key;
                    pa.Value = item.Value ?? DBNull.Value;
                    cmd.Parameters.Add(pa);
                }
            }

            SqlDataReader reader = cmd.ExecuteReader();
            List<T> list = new List<T>();
            var type = typeof(T);
            var properties = type.GetProperties();
            while (reader.Read())
            {
                var user = Activator.CreateInstance(type);
                for (int i = 0; i < properties.Length; i++)
                {
                    var pi = properties[i];
                    if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
                        pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
                }

                list.Add((T)user);
            }
            return list;
        }

View Code

 下载代码:https://files.cnblogs.com/files/sobaby/ORM03.zip

EntityHelper里重复代码很多,而且采用反射效率很低,下一章就开始优化代码。