使用場景:網站配置項目,為了便於管理,網站有幾個Model類來管理配置文件, 比如ConfigWebsiteModel 用來管理基本信息 ConfigSeoModel 用來管理SEO信息 ConfigCacheModel 用來管理網站緩存信息 不用Model之間不能有重名屬性欄位 現在需要把他們儲存 ...
使用場景:網站配置項目,為了便於管理,網站有幾個Model類來管理配置文件,
比如ConfigWebsiteModel 用來管理基本信息
ConfigSeoModel 用來管理SEO信息
ConfigCacheModel 用來管理網站緩存信息
不用Model之間不能有重名屬性欄位
現在需要把他們儲存到資料庫中,並從資料庫中讀取出來轉換成Model以便修改.不使用 List<T>和Dictionary<T,T>的原因是想利用MVC提供的強大數據自檢能力.
核心類: 兩個方法Load和Save Load<T t>傳入T並返回T的實例 Save 傳入T並儲存到資料庫
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; using System.Text; using ChengChenXu.Blog.Models; using System.Reflection; using System.Data.SqlClient; namespace ChengChenXu.Blog.DAL.SqlServer { public class ConfigModelDAL:IConfigModelDAL { private readonly string tableName = "blog_Config";//表名 private readonly string columnKey = "c_Key";//key列名 private readonly string columnValue = "c_Value";//Value列名 private readonly string columnType = "c_Type";//Type列名 /// <summary> /// 載入 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T Load<T>() { //通過sqlhelper獲取datatable string sql = "select * from " + tableName; DataTable dt = SqlHelper.ExecuteDataTable(sql); //不存在記錄 if (dt.Rows.Count == 0) return default(T); //表行轉換成列 ,臨時表 DataTable temp = new DataTable(); foreach (DataRow dr in dt.Rows) { //添加一列,設置列的數據類型 DataColumn dc = new DataColumn(); dc.ColumnName = dr[columnKey].ToString(); //根據字元串設置數據類型 dc.DataType = System.Type.GetType(dr[columnType].ToString()); temp.Columns.Add(dc); //如果時第一列,添加一行 int index = temp.Columns.Count - 1; if (temp.Rows.Count == 0) temp.Rows.Add(); //如果不是第一例,則行必定已經存在,直接賦值 temp.Rows[0][index] = dr[columnValue]; } if (temp.Columns.Count == 0) return default(T); //把臨時表轉換成Model並返回 return temp.Rows[0].ToModel<T>(); } /// <summary> /// 保存 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> public void Save<T>(T t) { //利用反射獲取對象所有屬性 string attributeName = String.Empty; PropertyInfo[] propertys = t.GetType().GetProperties(); //獲取資料庫配置表放到記憶體中,對比數據是否已經存在 DataTable dt = new DataTable(); if (propertys.Length > 0) { dt = SqlHelper.ExecuteDataTable("select * from "+tableName+""); //給表設置主鍵,方便查找. dt.PrimaryKey=new[] {(dt.Columns[columnKey])}; } //依次保存對象屬性到資料庫 foreach (PropertyInfo pi in propertys) { //獲取屬性值 var a = pi.GetValue(t, null); //值為NULL跳出,不保存,進入下個迴圈 if (a == null) { SqlHelper.ExecuteNonQuery("delete from "+tableName+" where "+columnKey+" ='"+pi.Name+"' "); continue; } //準備sql參數 SqlParameter[] parameters = SqlHelper.CreatParameters( new string[] { "Key", "Value" ,"Type"}, new object[] { pi.Name, a, a.GetType().ToString() } ); //查找屬性是否已經存在於資料庫中 if(dt.Rows.Contains(pi.Name)) { //存在 更新屬性 SqlHelper.ExecuteNonQuery( "update " + tableName + " set " + columnValue + " = @Value , " + columnType + " = @Type where " + columnKey + " = @Key", parameters ); } else { //不存在 插入屬性 SqlHelper.ExecuteNonQuery( "insert into " + tableName + " (" + columnKey + "," + columnValue + "," + columnType + ") values (@key,@value,@type) ", parameters ); } } } } }
上面類中用到了一個DataTable的擴展類 用於擴展DataRow的ToModle方法 代碼如下:
/// <summary> /// 類 說 明:給DataTable和DataRow擴展方法,直接轉換為對象集合或對象 /// 編 碼 人:程晨旭 /// 聯繫方式:Email:[email protected] /// Blog:http://chengchenxu.com /// 修改日期:2018-02-28 /// 補充說明:此擴展類可以極大的簡化操作,但是性能低下,大數據以及高性能要求下慎用. /// 此類如果放到asp.net的App_Code文件夾下會有編譯錯誤,放到其他地方則無此問題 /// </summary> using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; using System.Reflection; namespace ChengChenXu.Blog.DAL { internal static class DataTableExtensions { /// <summary> /// 把DataRow直接轉換成對應的實體對象,給DataRow添加一個擴展方法,方便使用. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dr"></param> /// <returns></returns> internal static T ToModel<T>(this DataRow dr) { T t = Activator.CreateInstance<T>(); // 利用反射獲得此模型的公共屬性 string attributeName = String.Empty; PropertyInfo[] propertys = t.GetType().GetProperties(); foreach (PropertyInfo pi in propertys) { attributeName = pi.Name; // 檢查DataTable是否包含此列 //此處要求DataRow的列名稱要和對象屬性名稱一致 //註意:此處大小寫不敏感 if (dr.Table.Columns.Contains(attributeName)) { // 判斷此屬性是否為只讀(不包含set構造) if (!pi.CanWrite) { continue; } //給屬性賦值 var value = dr[attributeName]; if (value != DBNull.Value) { pi.SetValue(t, value,null); } } } return t; } /// <summary> /// 將DataTable直接轉化為對象集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dt"></param> /// <returns></returns> internal static List<T> ToModelList<T>(this DataTable dt) { List<T> list = new List<T>(); //調用ToModel方法添加List for (int i = 0; i < dt.Rows.Count; i++) { T t = Activator.CreateInstance<T>(); t = dt.Rows[i].ToModel<T>(); list.Add(t); } return list; } } }
還用到了SqlHelper來進行資料庫的操作,這個很簡單,不在貼代碼了.
使用方法:
1 這四個屬性對應資料庫中的表名以及列名,可以自定義,例如下圖這樣.
private readonly string tableName = "blog_Config";//表名 private readonly string columnKey = "c_Key";//key列名 private readonly string columnValue = "c_Value";//Value列名 private readonly string columnType = "c_Type";//Type列名
key要設置為主鍵,類型都為varchar,長度視情況而定.
2 資料庫鏈接字元串都是sqlHelper類中定義,SqlHelper類參考文章:http://www.chengchenxu.com/Article/11/sqlhelper
3 創建一個Model進行Load和Save操作
public class ConfigSeoModel { [Display(Name = "Meta關鍵字")] public string KeyWord { get; set; } [Display(Name = "Meta描述")] public string Description { get; set; } } // ConfigModelDAL dal=new ConfigModelDAL(); //new 一個Model ConfigSeoModel model=new ConfigSeoModel(); model.KeyWord="關鍵字"; model.Description = "描述" //完成保存 dal.Save<ConfigSeoModel>(model); //讀取 ConfigSeoModel model = dal.Load<ConfigModel>();
本文為博主原創,轉載請保留出處:
http://www.chengchenxu.com/Article/24/fanxing