手寫ORM入門篇(一)

王景林的部落格發表於2019-06-15

物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現物件導向程式語言裡不同型別系統的資料之間的轉換 [1]  。從效果上說,它其實是建立了一個可在程式語言裡使用的--“虛擬物件資料庫”。

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

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

簡單的說:ORM相當於中繼資料。具體到產品上,例如ADO.NET Entity Framework。DLINQ中實體類的屬性[Table]就算是一種中繼資料。

BaseModel示例程式碼:

    public class BaseModel
    {
        /// <summary>
        /// 描述所有表的非自動主鍵GUID
        /// </summary>
        public string Id { set; get; }
    }

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         T Find<T>(string id) where T : BaseModel;
4         List<T> FindAll<T>() where T : BaseModel;
5         bool Add<T>(T t) where T : BaseModel;
6         bool Update<T>(T t) where T : BaseModel;
7         bool Delete<T>(T t) where T : BaseModel;
8     }

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     }

 

相關文章