章節列表: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裏重複代碼不少,並且採用反射效率很低,下一章就開始優化代碼。