實體框架一個基本的功能就是要與數據庫交互,與數據庫交互當然可以利用現有的一些基本技術,比如dotnet的ADO.Net等。這里有幾個要點:
????? 1)要封裝底層的數據庫交互通道,這個可以利用現有的數據庫訪問技術,比如ADO.Net。
????? 2)構造與數據庫交互的SQL語句,比如新增,刪除,修改,查詢等.做得比較好的,需要支持關聯查詢等。當然能做到AEF中的ESQL那樣,還是有點難度。
下面是一個實例,這里我只構造插入語句,并實現現數據庫插入實體的功能示意(底層數據庫訪問封裝這里不講,這個有很多例子)。
為了簡單起見,我們假設實體類的類名就是數據庫里對應表的表名,實體的屬性對應數據庫表里的字段,下面就是代碼:
~~~
?????? //實體類。
?????? public class AModel
?????? {
?????????? public string Field1{get;set;}
?????????? public string Field2 { get; set; }
?????????? public int age { get; set; }
?????????? public string Name { get; set; }
?????? }
?????? /// <summary>
?????? /// SQL語句執行,可以采用普通類,也可以采用抽象接口,便于不同數據庫的訪問.
?????? /// </summary>
?????? public static? class DatabaseHelper
?????? {
?????????? public static void ExecuteSQL(string strSQL, SqlParameter[] Params)
?????????? {
?????????????? ;//......................
?????????? }
?????? }
?????? /// <summary>
?????? /// 實體數據庫基本操作,這里只是模擬實體插入數據庫的情形,其它的操作其實類似,更新的話可以采用關鍵字做條件,沖突檢查字段也可包含在條件里面.
?????? /// </summary>
?????? public static class DbOperation
?????? {
?????????? public static void InsertModel<T>(T Model)
?????????? {
???????????????//這里的sql語句及參數構造結果可以采取緩存方式,沒必要每次都去構造,以減少性能損失。
?????????????? Dictionary<string,string> thePP = new Dictionary<string,string>();
?????????????? Dictionary<string, SqlDbType> thePT = new Dictionary<string, SqlDbType>();
?????????????? string theSQL = SQLBuilderHelper.BuilderInsertSQL<T>(thePP,thePT);
?????????????? List<SqlParameter> theParams = new List<SqlParameter>();
?????????????? foreach (var item in thePP)
?????????????? {
?????????????????? SqlParameter theP = new SqlParameter();
?????????????????? theP.SqlDbType = thePT[item.Key];
?????????????????? theP.ParameterName = item.Value;
?????????????????? theP.Value = GetPropertyValue(Model, item.Key);
?????????????????? theParams.Add(theP);
?????????????? }
?????????????? DatabaseHelper.ExecuteSQL(theSQL.ToString(), theParams.ToArray());
?????????? }
???????????//根據屬性名獲取屬性值,可以單獨放在一個輔助類里。
?????????? private static object GetPropertyValue<T>(T Model, string PropertyName)
?????????? {
?????????????? Type theType = Model.GetType();
?????????????? PropertyInfo pi = theType.GetProperty(PropertyName);
?????????????? return pi.GetValue(Model, null);
?????????? }
?????? }
?????? /// <summary>
?????? /// SQL及參數構建器,這里構造sql語句的時候,**在這里,默認類名就是數據庫表名,屬性名就是數據庫字段名。但在實際構造這種框架的時候,可以采用元屬性或者配置文件來實現這個功能**。比如linqtosql,DbContext就采用元屬性,AEF,Hibernate就是采用xml格式的配置文件,但這些東西都是為了更好更準確的構造sql語句.構造這種
?????? ///sql語? 句??? 需要知道的包括表名,字段名,字段類型,語言類型與字段類型間的對照等。
?????? /// </summary>
?????? public class SQLBuilderHelper
?????? {
?????????? public static string BuilderInsertSQL<T>(Dictionary<string, string> PropertyAndParams,Dictionary<string,SqlDbType> thePAndDBType)
?????????? {
?????????????? Type theType = typeof(T);
?????????????? PropertyInfo[] theProperties = theType.GetProperties();
?????????????? StringBuilder theSQL1 = new StringBuilder();
?????????????? StringBuilder theSQL2 = new StringBuilder();
?????????????? PropertyAndParams.Clear();
?????????????? //其實這里也可以利用元屬性來覺得哪些需要屬性需要插入,哪些屬性只能讀取之類的判斷,以及更新模式(對數字類型是賦值更新還是增量更新)等。
?????????????? foreach (var p in theProperties)
?????????????? {
?????????????????? if (theSQL1.ToString() == "")
?????????????????? {
?????????????????????? theSQL1.Append(p.Name.ToUpper());
?????????????????????? theSQL2.Append("@" + p.Name.ToUpper());
?????????????????? }
?????????????????? else
?????????????????? {
?????????????????????? theSQL1.Append(","+p.Name.ToUpper());
?????????????????????? theSQL2.Append(",@" + p.Name.ToUpper());
?????????????????? }
?????????????????? PropertyAndParams.Add(p.Name, "@" + p.Name.ToUpper());
?????????????????? thePAndDBType.Add(p.Name, GetDbType(p.PropertyType));
?????????????? }
?????????????? return "INSERT INTO " + theType.Name.ToUpper() + "(" + theSQL1.ToString() + ") VALUES(" + theSQL2.ToString() + ")";
?????????? }
???????????//C#類型與數據庫類型的對照可以通過Map文件完成,也可以通過元屬性完成,個人覺得元屬性的利用比較好,雖然說元屬性不是很靈活,
?????????? //但減少了構造的文件依賴,??????? 在大型的項目中其實是有好處的,至少是便于管理的。
?????????? private static SqlDbType GetDbType(Type type)
?????????? {
?????????????? if (type == typeof(int))
?????????????? {
?????????????????? return SqlDbType.Int;
?????????????? }
?????????????? return SqlDbType.NVarChar;
?????????? }
?????? }
~~~
有的時候我們將實體對象稱之為概念模型,而對象在數據庫里的存儲結構稱之為物理模型,在這兩個模型之間存在著一種映射關系(概念名稱與物理名稱的映射,對象屬性與字段名之間的映射,以及對象之間關系的映射),這其實就是所謂的ORM(對象關系模型)。上面的例子這種映射是利用命名規范來完成,實際上做的時候可以采用配置文件或者元屬性來完成,對于大項目時,配置文件的管理本身也會成為一個問題,因此我覺得用元屬性數據來進行會比較好。
上面的實現只是一個簡單的示例,實際做的時候需考慮得東西會比較多,比如需要封裝數據庫差異(底層訪問差異,sql語句方言),實體與數據庫之間的對照(map),SQL語句及參數緩存問題(沒必要每次都構造)等,但不管怎么說,基本的原理還是一樣的,關鍵技術主要是反射機制的應用。
下一篇,將介紹實體管理的功能,比如緩存,加載,新增,刪除等....