之前在自定義ORMapping——關系表轉換為實體或實體集合對象中提到過ORMapping的東西,在那片博客中也有ORMapping實現的一個簡單思路,當時只實現了關系表轉換為實體或實體集合這個功能,沒有實現動態生成SQL這個部分,本片博客就是完善之前的那片博客,實現動態生成SQL語句這麼一個功能。
1、創建兩個自定義特性,分別為表特性和字段特性,目的就是給相應的實體類的類名和屬性名,打上相應的特性,從而創建類名和表名,屬性和表字段名之間的對應關系
2、創建一個特性解析類,用來解析,這個實體類和表之間的對應關系,即獲得這種對應關系
3、創建相應常量類和枚舉,常量類用來生成相應的各種運算符或者排序時的關鍵字,枚舉用來說明,生成字段對應的value是否需要添加引號
4、創建相應的where,order生成器類,用來添加相應的條件
5、創建一個整合類,將上面說的那些東西,整個為一個整體,生成相應的SQL語句,並且執行,並將返回的DataTable轉換為集合對象
下面的每塊內容就是相應的實現
a、自定義特性的定義
///b、自定義特性的使用,使用在具體的一個實體類上,具體如下:/// 自定義字段特性 /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)] public class ORFieldMappingAttribute : Attribute { ////// 屬性和字段的對應 /// /// 字段名稱 /// 是否自增 /// 有沒有逗號 public ORFieldMappingAttribute(string strFieldName, bool IsAutoIncreate = false, ORFieldValueHaveCommaEnum ORFieldValueHaveCommaEnum = ORFieldValueHaveCommaEnum.True) { this.strFieldName = strFieldName; this.ORFieldValueHaveCommaEnum = ORFieldValueHaveCommaEnum; this.IsAutoIncreate = IsAutoIncreate; } public string strFieldName { get; set; } public ORFieldValueHaveCommaEnum ORFieldValueHaveCommaEnum { get; set; } public bool IsAutoIncreate { get; set; } } ////// 自定義表特性 /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class ORTableMappingAttribute : Attribute { ////// 類名和表明的對應 /// /// 表名 public ORTableMappingAttribute(string strTableName) { this.strTableName = strTableName; } public string strTableName { get; set; } }
[ORTableMapping("T_Users")] public class User { [ORFieldMapping("Id",true,ORFieldValueHaveCommaEnum.False)] public int UserId { get; set; } [ORFieldMapping("Name",false,ORFieldValueHaveCommaEnum.True)] public string UserName { get; set; } [ORFieldMapping("Sex", false, ORFieldValueHaveCommaEnum.True)] public string UserSex { get; set; } [ORFieldMapping("Address", false, ORFieldValueHaveCommaEnum.True)] public string Addr { get; set; } [ORFieldMapping("Contents", false, ORFieldValueHaveCommaEnum.True)] public string Content { get; set; } }
a、解析自定義特性類的代碼如下
///該類是在生成SQL語句時使用的,只要你的實體類用上相應的特性,只要你把這個類型傳遞給這個解析類,他就可以給你解決出該類的類名和屬性名,與數據庫中的表名和字段名的對應關系/// 獲得實體的表名 /// /// 實體的type對象 ///實體對象對應的表名 public static string GetTableName() { T obj = new T(); Type type = obj.GetType(); string strTableName=""; object[] Attarrs = type.GetCustomAttributes(false); for (int i = 0; i < Attarrs.Length; i++) { if (Attarrs[i] is ORTableMappingAttribute) { ORTableMappingAttribute attribute = Attarrs[i] as ORTableMappingAttribute; strTableName = attribute.strTableName; } } return strTableName; } ////// 獲得實體屬性對應的字段,並給字段賦值 /// /// 實體的type對象 ///字典:key=字段名;value=字段值 public static DictionaryGetFieldName(T obj) { Dictionary dic = new Dictionary (); Type type = obj.GetType(); PropertyInfo[] pis = type.GetProperties(); for (int i = 0; i < pis.Length; i++) { object[] Attarrs = pis[i].GetCustomAttributes(false); for (int j = 0; j < Attarrs.Length; j++) { if (Attarrs[j] is ORFieldMappingAttribute) { ORFieldMappingAttribute fn = Attarrs[j] as ORFieldMappingAttribute; if (fn.IsAutoIncreate != true) { if (fn.ORFieldValueHaveCommaEnum.ToString() == "True") { dic.Add(fn.strFieldName, "'" + pis[i].GetValue(obj, null).ToString() + "'"); } else { dic.Add(fn.strFieldName, pis[i].GetValue(obj, null).ToString()); } } } } } return dic; } }
定義如下常量和枚舉類型
///定義這些常量和枚舉是為了幫助我們生成相應SQL語句時,使用/// 邏輯運算符 /// public class LogicOperatorConst { public const string And = "and"; public const string Or = "or"; public const string None = ""; } ////// 字段的排序方向定義 /// public class FieldSortConst { public const string Asc = "asc"; public const string Desc = "desc"; } ////// 比較運算符 /// public class CompareOperationConst { //條件項的運算符常量定義 public const string EqualTo = "="; public const string GreaterThanOrEqualTo = ">="; public const string GreaterThan = ">"; public const string LessThanOrEqualTo = "<="; public const string LessThan = "<"; public const string NotEqualTo = "<>"; public const string Like = "LIKE"; public const string Is = "IS"; public const string In = "IN"; } ////// 是否有單引號 /// public enum ORFieldValueHaveCommaEnum { False = 0, True = 1 };
public abstract class SqlClauseBuilder { //便於之後的擴展:ToSqlString(ISqlBuilder sqlBuilder) public abstract string ToSqlString(); } ///使用這些對象幫助我們生成相應的SQL語句中的where和order部分,當然,也可以定義其他的/// 拼接Where後的條件語句 /// public class WhereSqlClauseBuilder : SqlClauseBuilder { private DictionarydicSqlConditions = new Dictionary (); /// /// 添加條件 /// /// 字段名 /// 字段值 /// 比較運算符 /// 連接符(and or none) public void Append(string strFieldName, string strFieldValue, string strCompareOperation = CompareOperationConst.EqualTo, string strLogicOperation = LogicOperatorConst.None) { SqlConditionItem item = new SqlConditionItem(); item.SetOperationItem(strFieldName, strFieldValue, strCompareOperation); dicSqlConditions.Add(item, strLogicOperation); } ////// 生成Sql語句 /// ///public override string ToSqlString() { StringBuilder sb = new StringBuilder(); foreach (var item in dicSqlConditions) { sb.Append(item.Key.GetOperationItem() + " " + item.Value); } return sb.ToString(); } } /// /// 單個where項 /// public class SqlConditionItem { private string strFieldName; private string strFieldValue; private string strCompareOperation; ////// 以字符串的形式獲得條件 /// ///單個條件的字符串 public string GetOperationItem() { StringBuilder sb = new StringBuilder(); sb.Append(" " + strFieldName + " " + strCompareOperation + " " + strFieldValue); return sb.ToString(); } ////// 賦值 /// /// 字段名 /// 字段值 /// 比較運算符 public void SetOperationItem(string strFieldName, string strFieldValue, string strCompareOperation) { this.strFieldName = strFieldName; this.strCompareOperation = strCompareOperation; this.strFieldValue = strFieldValue; } } ////// 拼接OrderBy後的條件語句 /// public class OrderBySqlClauseBuilder : SqlClauseBuilder { private DictionarydicOrderConditions = new Dictionary (); public void AppendItem(string strDataField, string strFieldSort = FieldSortConst.Asc) { if (dicOrderConditions.Count > 0) { dicOrderConditions.Add(", " + strDataField, strFieldSort); } else { dicOrderConditions.Add(strDataField, strFieldSort); } } public override string ToSqlString() { StringBuilder sb = new StringBuilder(); foreach (var item in dicOrderConditions) { sb.Append(item.Key + " " + item.Value); } return sb.ToString(); } }
整合類是將上述運用起來形成的一個整體,從而實現增刪該查這些功能,具體如下
public class DataManagerwhere T : class,new() { #region 增加 /// /// 添加 /// /// 實體對象 ///SQL語句 public static int Add(T obj) { StringBuilder sb = new StringBuilder(); string strTableName = GetTableName(); string strFieldNames; string strFieldValues; GetInsertFieldAndValue(obj, out strFieldNames, out strFieldValues); sb.AppendFormat("insert into {0}({1}) values({2})", strTableName, strFieldNames, strFieldValues); return SQLHelper.GetInstance().ExecuteNonQuery(sb.ToString(), CommandType.Text); } #endregion #region 刪除 ////// 全部刪除 /// /// 這個類型的對象 ///操作影響行數 public static int Delete(T obj) { return Delete(obj, null); } ////// 帶有條件的刪除 /// /// 被刪除對象 /// 條件 ///操作影響行數 public static int Delete(T obj, ActionwhereSqlClauseBuilder) { StringBuilder sb = new StringBuilder(); string strTableName = GetTableName(); WhereSqlClauseBuilder w = new WhereSqlClauseBuilder(); if (whereSqlClauseBuilder != null) { whereSqlClauseBuilder(w); sb.AppendFormat("delete from {0} where {1}", strTableName, w.ToSqlString()); } else { sb.AppendFormat("delete from {0}", strTableName); } return SQLHelper.GetInstance().ExecuteNonQuery(sb.ToString(), CommandType.Text); } #endregion #region 查詢 /// /// 無條件,無排序的查詢 /// /// lambda表達式 ///集合 public static ListLoad() { return Load(null,null); } /// /// 有條件,無排序的查詢 /// /// lambda表達式 ///集合 public static ListLoad(Action whereSqlClauseBuilder) { return Load(whereSqlClauseBuilder, null); } /// /// 無條件,有排序的查詢 /// /// lambda表達式 ///集合 public static ListLoad(Action orderBySqlClauseBuilder) { return Load(null, orderBySqlClauseBuilder); } /// /// 有條件,有排序的查詢 /// /// whereSqlClauseBuilder /// orderBySqlClauseBuilder ///集合 public static ListLoad(Action whereSqlClauseBuilder, Action orderBySqlClauseBuilder) { StringBuilder sb = new StringBuilder(); string strTableName = GetTableName(); WhereSqlClauseBuilder w = new WhereSqlClauseBuilder(); OrderBySqlClauseBuilder o = new OrderBySqlClauseBuilder(); if (whereSqlClauseBuilder != null) { whereSqlClauseBuilder(w); sb.AppendFormat("select * from {0} where {1}", strTableName, w.ToSqlString()); } else { sb.AppendFormat("select * from {0}", strTableName); } if (orderBySqlClauseBuilder != null) { orderBySqlClauseBuilder(o); sb.Append(" order by " + w.ToSqlString()); } DataTable dt = SQLHelper.GetInstance().ExecuteQuery(sb.ToString(), CommandType.Text); return ORMapping.ToList (dt); } #endregion #region 修改 /// /// 更新 /// /// 更新的對象 /// 條件 ///public static int Update(T obj, Action whereSqlClauseBuilder = null) { StringBuilder sb = new StringBuilder(); string strTableName = GetTableName(); string strFieldValues; GetUpdateFieldAndValue(obj, out strFieldValues); WhereSqlClauseBuilder w = new WhereSqlClauseBuilder(); if (whereSqlClauseBuilder != null) { whereSqlClauseBuilder(w); sb.AppendFormat("update {0} set {1} Where {2}", strTableName, strFieldValues, w.ToSqlString()); } else { sb.AppendFormat("update {0} set {1}", strTableName, strFieldValues); } return SQLHelper.GetInstance().ExecuteNonQuery(sb.ToString(), CommandType.Text); } #endregion #region 內部方法 //獲得表名 private static string GetTableName() { T obj = new T(); string strTableName = AttributeManager .GetTableName(); return strTableName; } //insert所用的字段名和相應值 private static void GetInsertFieldAndValue(T obj, out string strFieldNames, out string strFieldValues) { Dictionary dic = AttributeManager .GetFieldName(obj); strFieldNames = ""; strFieldValues = ""; foreach (var item in dic) { strFieldNames = strFieldNames + "," + item.Key; strFieldValues = strFieldValues + "," + item.Value; } if (strFieldNames.Length > 0) { strFieldNames = strFieldNames.Substring(1); strFieldValues = strFieldValues.Substring(1); } } //insert所用的字段名和相應值 private static void GetUpdateFieldAndValue(T obj, out string strFieldNameAndValue) { Dictionary dic = AttributeManager .GetFieldName(obj); strFieldNameAndValue = ""; foreach (var item in dic) { strFieldNameAndValue = strFieldNameAndValue + item.Key + " = " + item.Value + " ,"; } if (strFieldNameAndValue.Length > 0) { strFieldNameAndValue = strFieldNameAndValue.Substring(0, strFieldNameAndValue.Length-1); } } #endregion }
static void Main(string[] args) { //Father father1 = DataManager.Load().First(); List father2 = DataManager .Load(p => { p.Append("Id", "2", CompareOperationConst.EqualTo, LogicOperatorConst.None); }); //List sonList = father1.ListSon; User user = new User() {UserName="青山111",UserSex="男111", Addr="地址", Content="內容" }; #region Table轉換為實體 //DataTable dt = new DataTable("T_Users"); //dt.Columns.Add(new DataColumn("Id", typeof(string))); //dt.Columns.Add(new DataColumn("Name", typeof(string))); //dt.Columns.Add(new DataColumn("Sex", typeof(string))); ////1、創建行 //DataRow dr = dt.NewRow(); ////2、賦值行 //dr["Id"] = "10040242041"; //dr["Name"] = "青山"; //dr["Sex"] = "青山"; //dt.Rows.Add(dr); //List userList = ORMapping.ToList (dt); #endregion #region insert語句 int insertCount = DataManager .Add(user); #endregion #region delete刪除 int intDelete1 = DataManager .Delete(user); int intDelete2 = DataManager .Delete(user, p => { p.Append("Id", "1", CompareOperationConst.EqualTo, LogicOperatorConst.And); p.Append("Name", "qingshan", CompareOperationConst.Like, LogicOperatorConst.Or); p.Append("Sex", "男", CompareOperationConst.Like, LogicOperatorConst.None); }); #endregion #region select語句 List userList1 = DataManager .Load(); List userList2 = DataManager .Load(p => { p.Append("Id", "2", CompareOperationConst.EqualTo, LogicOperatorConst.And); p.Append("Name", "女", CompareOperationConst.Like, LogicOperatorConst.None); }); #endregion #region update語句 int intUpdateCount1 = DataManager .Update(user); int intUpdateCount2 = DataManager .Update(user, p => { p.Append("Id", "1", CompareOperationConst.EqualTo, LogicOperatorConst.And); p.Append("Name", "qingshan", CompareOperationConst.Like, LogicOperatorConst.Or); p.Append("Sex", "男", CompareOperationConst.Like, LogicOperatorConst.None); }); #endregion Console.ReadKey(); }
自定義ORMapping,主要完成兩個功能,第一:SQL語句的生成和執行;第二:DataTable轉換為相應的集合,本片博客和之前的那篇博客只是簡單的完成了這個功能,具體的代碼大家可以在這裡下載。