章节列表:html
《一步步实现本身的ORM(一)》sql
《一步步实现本身的ORM(二)》ide
经过前面两篇文章,咱们大体了解了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循环里的内容是根据实体类的不一样代码而有所不一样,循环外的代码则是固定不变的,如今咱们要把变化的代码抽离出来,咱们仍是请出明星--反射。ui
在前面章节咱们都是用反射读取实体类里的,好比typeof(User).GetProperty("UserId").GetValue(obj,null),有GetValue确定也有SetValue,咱们看下SetValue的定义:spa
public virtual void SetValue( Object obj, Object value, Object[] index )
obj:将设置其属性值的对象。3d
value:新的属性值。code
index : 索引化属性的可选索引值。 对于非索引化属性,该值应为 null。 xml
示例代码:htm
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); }
运行结果:
下面一个问题来了,咱们看这一行代码
User user = new User();
难道咱们每次都要这么写这样的代码吗,能不能作一个通用的吗?这须要咱们用反射实例化一个类,咱们请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; }
最后咱们在增长以下方法:
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; }
下载代码:http://files.cnblogs.com/files/sobaby/ORM03.zip
EntityHelper里重复代码不少,并且采用反射效率很低,下一章就开始优化代码。