手寫ORM入門篇(一)

對象關係映射(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程序技術,用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換 。從效果上說,它實際上是建立了一個可在編程語言裏使用的--「虛擬對象數據庫」。sql

面向對象是從軟件工程基本原則(如耦合、聚合、封裝)的基礎上發展起來的,而關係數據庫則是從數學理論發展而來的,兩套理論存在顯著的區別。爲了解決這個不匹配的現象,對象關係映射技術應運而生。數據庫

對象關係映射(Object-Relational Mapping)提供了概念性的、易於理解的模型化數據的方法。ORM方法論基於三個核心原則: 簡單:以最基本的形式建模數據。 傳達性:數據庫結構被任何人都能理解的語言文檔化。 精確性:基於數據模型建立正確標準化的結構。 典型地,建模者經過收集來自那些熟悉應用程序但不熟練的數據建模者的人的信息開發信息模型。建模者必須可以用非技術企業專家能夠理解的術語在概念層次上與數據結構進行通信。建模者也必須能以簡單的單元分析信息,對樣本數據進行處理。ORM專門被設計爲改進這種聯繫。編程

簡單的說:ORM至關於中繼數據。具體到產品上,例如ADO.NET Entity Framework。DLINQ中實體類的屬性[Table]就算是一種中繼數據。數據結構

BaseModel示例代碼:

1     public class BaseModel
2     {
3         /// <summary>
4         /// 全部實體的父類,非自增主鍵GUID
5         /// </summary>
6         public string Id { set; get; }
7     }

User示例代碼:

 1     public class User : BaseModel
 2     {
 3         public string Account { get; set; }
 4 
 5         public string Password { get; set; }
 6 
 7         public string Name { get; set; }
 8 
 9         public int Sex { get; set; }
10 
11         public int Status { get; set; }
12 
13         public string BizCode { get; set; }
14 
15         public DateTime CreateTime { get; set; }
16 
17         public string CrateId { get; set; }
18 
19         public string TypeName { get; set; }
20 
21         public string TypeId { get; set; }
22 
23     }

IBaseDAL示例代碼:

 1     public interface IBaseDAL
 2     {
 3         /// <summary>
 4         /// 根據主鍵返回一個實體
 5         /// </summary>
 6         /// <typeparam name="T"></typeparam>
 7         /// <param name="id"></param>
 8         /// <returns></returns>
 9         T Find<T>(string id) where T : BaseModel;
10 
11         /// <summary>
12         /// 返回一個List<Medel>實體集合
13         /// </summary>
14         /// <typeparam name="T"></typeparam>
15         /// <returns></returns>
16         List<T> FindAll<T>() where T : BaseModel;
17 
18         /// <summary>
19         /// 添加一條記錄
20         /// </summary>
21         /// <typeparam name="T"></typeparam>
22         /// <param name="t"></param>
23         /// <returns></returns>
24         bool Add<T>(T t) where T : BaseModel;
25 
26         /// <summary>
27         /// 更新一個實體
28         /// </summary>
29         /// <typeparam name="T"></typeparam>
30         /// <param name="t"></param>
31         /// <returns></returns>
32         bool Update<T>(T t) where T : BaseModel;
33 
34         /// <summary>
35         /// 刪除一條記錄
36         /// </summary>
37         /// <typeparam name="T"></typeparam>
38         /// <param name="t"></param>
39         /// <returns></returns>
40         bool Delete<T>(T t) where T : BaseModel;
41     }

BaseDAL示例代碼

  1     /// <summary>
  2     /// 泛型方法添加BaseModel約束,全部實體類必須有一個非自增的主鍵Id,Id的值爲隨機的GUID,
  3     /// </summary>
  4     public class BaseDAL : IBaseDAL
  5     {
  6         /// <summary>
  7         /// 數據庫鏈接字符串
  8         /// </summary>
  9         private static string ConnectionString = ConfigurationManager.ConnectionStrings["OpenAuthDB"].ConnectionString;
 10 
 11         public bool Add<T>(T t) where T : BaseModel
 12         {
 13             Type type = t.GetType();
 14             string columnStr = string.Join(",", type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => $"[{p.Name}]"));
 15             string valueStr = string.Join(",", type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => $"@{p.Name}"));
 16             var parameterList = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => new SqlParameter($"@{p.Name}", p.GetValue(t) ?? DBNull.Value));
 17             string sqlStr = $"Insert Into [{type.Name}] ({columnStr}) values ({valueStr})";
 18             using (SqlConnection conn = new SqlConnection(ConnectionString))
 19             {
 20                 SqlCommand command = new SqlCommand(sqlStr, conn);
 21                 command.Parameters.AddRange(parameterList.ToArray());
 22                 conn.Open();
 23                 //若是Id是自增的,在sql後面增長個 Select @@Identity; command.ExecuteScalar,新增後把Id拿出來.
 24                 return command.ExecuteNonQuery() > 0;
 25             }
 26         }
 27 
 28         public bool Delete<T>(T t) where T : BaseModel
 29         {
 30             //獲取T的類型
 31             Type type = typeof(T);
 32             var parameter = new SqlParameter("Id", type.GetProperty("Id").GetValue(t) ?? DBNull.Value);
 33             string strSql = $"DELETE FROM [{type.Name}] WHERE Id = @Id";
 34             using (SqlConnection conn = new SqlConnection(ConnectionString))
 35             {
 36                 SqlCommand command = new SqlCommand(strSql, conn);
 37                 command.Parameters.Add(parameter);
 38                 conn.Open();
 39                 var iRes = command.ExecuteNonQuery();
 40                 return iRes > 0 ? true : false;
 41             }
 42         }
 43 
 44         public List<T> FindAll<T>() where T : BaseModel
 45         {
 46             Type type = typeof(T);
 47             string sqlStr = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}]";
 48             List<T> list = new List<T>();
 49             using (SqlConnection conn = new SqlConnection(ConnectionString))
 50             {
 51                 SqlCommand command = new SqlCommand(sqlStr, conn);
 52                 conn.Open();
 53                 var reader = command.ExecuteReader();
 54                 while (reader.Read())
 55                 {
 56                     list.Add(this.Trans<T>(type, reader));
 57                 }
 58             }
 59             return list;
 60         }
 61 
 62         public T Find<T>(string id) where T : BaseModel
 63         {
 64             Type type = typeof(T);
 65             string sql = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}] WHERE ID = '{id}' ";
 66             object oObject = Activator.CreateInstance(type);
 67             using (SqlConnection conn = new SqlConnection(ConnectionString))
 68             {
 69                 SqlCommand command = new SqlCommand(sql, conn);
 70                 conn.Open();
 71                 var reader = command.ExecuteReader();
 72                 if (reader.Read())
 73                     return this.Trans<T>(type, reader);
 74                 else
 75                     return default(T);
 76             }
 77         }
 78 
 79         public bool Update<T>(T t) where T : BaseModel
 80         {
 81             Type type = typeof(T);
 82             StringBuilder sb = new StringBuilder();
 83             sb.Append($"UPDATE [{type.Name}] SET ");
 84             var propArray = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
 85             var propArrayLen = propArray.Count();
 86             for (int i = 0; i < propArrayLen; i++)
 87             {
 88                 var propertiesName = propArray[i].Name;
 89                 if (i != propArrayLen - 1)
 90                     sb.Append($"{propertiesName} = @{propertiesName}, ");
 91                 else
 92                     sb.Append($" {propertiesName} = @{propertiesName} ");
 93             }
 94             #region 使用foreach的寫法
 95             //foreach (var properties in propArray)
 96             //{
 97             //    var propertiesName = properties.Name;
 98             //    if (i != propArrayLen)
 99             //        sb.Append($"{propertiesName} = @{propertiesName}, ");
100             //    else
101             //        sb.Append($" {propertiesName} = @{propertiesName} ");
102             //    i++;
103             //}
104             #endregion
105             sb.Append($" Where Id = @Id;");
106             var parameterList = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => new SqlParameter($"@{p.Name}", p.GetValue(t) ?? DBNull.Value));
107             using (SqlConnection conn = new SqlConnection(ConnectionString))
108             {
109                 SqlCommand command = new SqlCommand(sb.ToString(), conn);
110                 command.Parameters.AddRange(parameterList.ToArray());
111                 conn.Open();
112                 return command.ExecuteNonQuery() > 0;
113             }
114         }
115 
116         #region Private Method
117         private T Trans<T>(Type type, SqlDataReader reader)
118         {
119             object oObject = Activator.CreateInstance(type);
120             foreach (var properties in type.GetProperties())
121             {
122                 properties.SetValue(oObject, reader[properties.Name] ?? DBNull.Value);
123             }
124             return (T)oObject;
125         }
126         #endregion
127     }

 方法調用示例代碼:

 1         static void Main(string[] args)
 2         {
 3             BaseDAL baseDAL = new BaseDAL();
 4             {
 5                 List<User> users = baseDAL.FindAll<User>();
 6                 var b = baseDAL.Delete<User>(new User() {
 7                     Id = "de8be521-f1ec-4483-b124-0be342890507"
 8                 });
 9             }
10             {
11                 var b = baseDAL.Add<User>(new User
12                 {
13                     Id = Guid.NewGuid().ToString() ,
14                     Name = "zs",
15                     Sex = 0,
16                     Status = 1,
17                     BizCode = "1234567",
18                     CrateId = "123456",
19                     TypeId = "123456",
20                     TypeName = "admin",
21                     CreateTime = DateTime.Now,
22                     Account = "wjl",
23                     Password = "123456"
24                 });
25                 var s = baseDAL.Update<User>(new User
26                 {
27                     Id = "4955d7e0-808f-4d50-af66-285e2a18966e",
28                     Name = "zs",
29                     Sex = 0,
30                     Status = 1,
31                     BizCode = "test value",
32                     CrateId = "test value",
33                     TypeId = "test value",
34                     TypeName = "test value",
35                     CreateTime = DateTime.Now,
36                     Account = "test value",
37                     Password = "test value"
38                 });
39             }
40             Console.ReadLine();
41         }

 至此,常規的CRUD已基本完成,咱們不用再去關注複雜的sql,只須要操做實體類便可。app

相關文章
相關標籤/搜索