最近在研究ORM,嘗試着本身開發了一個簡單的ORM。我我的不喜歡EF由於跟不上EF升級太快了,再說公司裏還停留在c# 3.5時代,對於NHibernate配置太複雜看到就頭暈,就心生本身作一個ORM的念頭,如今把開發過程當中的點點滴滴記錄下來,供本身和新手參考,大神請直接忽略這篇文章。sql
ORM(object relation mapping)對象關係映射,經常使用來映射數據庫裏表、字段等信息。ORM的原理無非就是用配置文件、Attribute來映射數據關係。咱們一步步來來建立ORM,定義一個實體類,而後用反射得到類名(表名)、屬性(對應是字段名稱),例子以下:數據庫
CREATE TABLE [dbo].[User]( [UserId] [int] NOT NULL primary key, [Email] [nvarchar](100) NULL, [CreatedTime] [datetime] NULL )
在這裏我建立一張表,其中UserId是主鍵,爲何不定義成自增加的呢?請保留這個疑問,繼續看下去。表建立好了,下面就是定義一個類,以下:c#
public class User { public int UserId { get; set; } public string Email { get; set; } public DateTime CreatedTime { get; set; } }
如今咱們要對這個類寫一個INSERT操做,直接傳入User對象而後插入到數據庫。咱們要用系統自動構建SQL語句,不須要手寫SQL語句,在這咱們先分析下INSERT INTO SQL語句。app
INSERT INTO 表名 (字段1 ,字段2 ,字段3...) VALUES 值1, 值2, 值3...
咱們須要知道表名、字段名和值纔可以完成SQL拼接,怎麼獲得這些信息呢,萬能的反射該出場。 ide
string className = typeof(User).Name; Console.WriteLine("類名:{0}", className); Console.WriteLine("-----獲取屬性信息-----"); var properties = typeof(User).GetProperties(); foreach (var item in properties) { Console.WriteLine("屬性名:{0}",item.Name); } Console.WriteLine("-----end-----");
運行結果以下ui
LOOK,User類的信息都顯示出來了,屬性的值該如何顯示?也就是SQL語句的VALUE,仍是要靠萬能的反射,請看官門繼續往下看。spa
string className = typeof(User).Name; Console.WriteLine("類名:{0}", className); var properties = typeof(User).GetProperties(); User user = new User() { UserId = 123, Email = "abc@123.com", CreatedTime = DateTime.Now }; foreach (var item in properties) { Console.WriteLine("{0}:{1}", item.Name, item.GetValue(user, null)); }
類名、屬性名、屬性值咱們都獲得了,那下面要作的就是拼寫SQL語句了3d
public static void Main() { PritSql(new User() { UserId = 123, Email = "abc@123.com", CreatedTime = DateTime.Now }); } public static void PritSql(User user) { string className = typeof(User).Name; var properties = typeof(User).GetProperties(); StringBuilder sql = new StringBuilder(); sql.Append("INSERT INTO ").Append(className).Append("("); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; if (i > 0) sql.Append(","); sql.Append(pi.Name); } sql.Append(") VALUES ("); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; if (i > 0) sql.Append(","); sql.Append("'").Append(pi.GetValue(user,null)).Append("'"); } sql.Append(")"); Console.WriteLine(sql); }
爲避免SQL注入,我把SQL改爲參數的信息code
INSERT INTO 表名 (字段1 ,字段2 ,字段3...) VALUES @p1, @p2, @p3...
修改後的c#代碼對象
public static void Main() { PritParameterSql(new User() { UserId = 123, Email = "abc@123.com", CreatedTime = DateTime.Now }); } public static int PritParameterSql<T>(T user) { Dictionary<string, object> parameters = new Dictionary<string, object>(); string className = typeof(T).Name; var properties = typeof(T).GetProperties(); StringBuilder sql = new StringBuilder(); sql.Append("INSERT INTO [").Append(className).Append("]("); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; if (i > 0) sql.Append(","); sql.Append(pi.Name); } sql.Append(") VALUES ("); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; if (i > 0) sql.Append(","); sql.Append("@p").Append(i); parameters.Add("@p" + i, pi.GetValue(user, null)); } sql.Append(")"); Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); }
執行後的結果
還記得前面提到爲何UserId不設置成自增加嗎?由於這種單純的反射沒法識別哪一個是自增加字段,若是想用自增加主鍵怎麼辦?請看後續文章。