查看: 2844|回复: 0

[.NET源码] 利用泛型和反射,管理配置文件,把Model转换成数据行,并把数据行转换成Model

发表于 2018-3-23 08:00:05

使用场景:网站配置项目,为了便于管理,网站有几个Model类来管理配置文件,

比如ConfigWebsiteModel 用来管理基本信息

ConfigSeoModel 用来管理SEO信息

ConfigCacheModel 用来管理网站缓存信息

不用Model之间不能有重名属性字段

现在需要把他们储存到数据库中,并从数据库中读取出来转换成Model以便修改.不使用 List和Dictionary的原因是想利用MVC提供的强大数据自检能力.

核心类: 两个方法Load和Save Load传入T并返回T的实例 Save 传入T并储存到数据库

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Data;
  6. using System.Text;
  7. using ChengChenXu.Blog.Models;
  8. using System.Reflection;
  9. using System.Data.SqlClient;
  10. namespace ChengChenXu.Blog.DAL.SqlServer
  11. {
  12. public class ConfigModelDAL:IConfigModelDAL
  13. {
  14. private readonly string tableName = "blog_Config";//表名
  15. private readonly string columnKey = "c_Key";//key列名
  16. private readonly string columnValue = "c_Value";//Value列名
  17. private readonly string columnType = "c_Type";//Type列名
  18. /// <summary>
  19. /// 加载
  20. /// </summary>
  21. /// <typeparam name="T"></typeparam>
  22. /// <returns></returns>
  23. public T Load<T>()
  24. {
  25. //通过sqlhelper获取datatable
  26. string sql = "select * from " + tableName;
  27. DataTable dt = SqlHelper.ExecuteDataTable(sql);
  28. //不存在记录
  29. if (dt.Rows.Count == 0) return default(T);
  30. //表行转换成列 ,临时表
  31. DataTable temp = new DataTable();
  32. foreach (DataRow dr in dt.Rows)
  33. {
  34. //添加一列,设置列的数据类型
  35. DataColumn dc = new DataColumn();
  36. dc.ColumnName = dr[columnKey].ToString();
  37. //根据字符串设置数据类型
  38. dc.DataType = System.Type.GetType(dr[columnType].ToString());
  39. temp.Columns.Add(dc);
  40. //如果时第一列,添加一行
  41. int index = temp.Columns.Count - 1;
  42. if (temp.Rows.Count == 0) temp.Rows.Add();
  43. //如果不是第一例,则行必定已经存在,直接赋值
  44. temp.Rows[0][index] = dr[columnValue];
  45. }
  46. if (temp.Columns.Count == 0) return default(T);
  47. //把临时表转换成Model并返回
  48. return temp.Rows[0].ToModel<T>();
  49. }
  50. /// <summary>
  51. /// 保存
  52. /// </summary>
  53. /// <typeparam name="T"></typeparam>
  54. /// <param name="t"></param>
  55. public void Save<T>(T t)
  56. {
  57. //利用反射获取对象所有属性
  58. string attributeName = String.Empty;
  59. PropertyInfo[] propertys = t.GetType().GetProperties();
  60. //获取数据库配置表放到内存中,对比数据是否已经存在
  61. DataTable dt = new DataTable();
  62. if (propertys.Length > 0)
  63. {
  64. dt = SqlHelper.ExecuteDataTable("select * from "+tableName+"");
  65. //给表设置主键,方便查找.
  66. dt.PrimaryKey=new[] {(dt.Columns[columnKey])};
  67. }
  68. //依次保存对象属性到数据库
  69. foreach (PropertyInfo pi in propertys)
  70. {
  71. //获取属性值
  72. var a = pi.GetValue(t, null);
  73. //值为NULL跳出,不保存,进入下个循环
  74. if (a == null)
  75. {
  76. SqlHelper.ExecuteNonQuery("delete from "+tableName+" where "+columnKey+" ='"+pi.Name+"' ");
  77. continue;
  78. }
  79. //准备sql参数
  80. SqlParameter[] parameters = SqlHelper.CreatParameters(
  81. new string[] { "Key", "Value" ,"Type"},
  82. new object[] { pi.Name, a, a.GetType().ToString() }
  83. );
  84. //查找属性是否已经存在于数据库中
  85. if(dt.Rows.Contains(pi.Name))
  86. {
  87. //存在 更新属性
  88. SqlHelper.ExecuteNonQuery(
  89. "update " + tableName + " set " + columnValue + " = @Value , " + columnType + " = @Type where " + columnKey + " = @Key",
  90. parameters
  91. );
  92. }
  93. else
  94. {
  95. //不存在 插入属性
  96. SqlHelper.ExecuteNonQuery(
  97. "insert into " + tableName + " (" + columnKey + "," + columnValue + "," + columnType + ") values (@key,@value,@type) ",
  98. parameters
  99. );
  100. }
  101. }
  102. }
  103. }
  104. }
复制代码

上面类中用到了一个DataTable的扩展类 用于扩展DataRow的ToModle方法 代码如下:

  1. /// <summary>
  2. /// 类 说 明:给DataTable和DataRow扩展方法,直接转换为对象集合或对象
  3. /// 编 码 人:程晨旭
  4. /// 联系方式:Email:97391519@qq.com
  5. /// Blog:http://chengchenxu.com
  6. /// 修改日期:2018-02-28
  7. /// 补充说明:此扩展类可以极大的简化操作,但是性能低下,大数据以及高性能要求下慎用.
  8. /// 此类如果放到asp.net的App_Code文件夹下会有编译错误,放到其他地方则无此问题
  9. /// </summary>
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Web;
  14. using System.Data;
  15. using System.Reflection;
  16. namespace ChengChenXu.Blog.DAL
  17. {
  18. internal static class DataTableExtensions
  19. {
  20. /// <summary>
  21. /// 把DataRow直接转换成对应的实体对象,给DataRow添加一个扩展方法,方便使用.
  22. /// </summary>
  23. /// <typeparam name="T"></typeparam>
  24. /// <param name="dr"></param>
  25. /// <returns></returns>
  26. internal static T ToModel<T>(this DataRow dr)
  27. {
  28. T t = Activator.CreateInstance<T>();
  29. // 利用反射获得此模型的公共属性
  30. string attributeName = String.Empty;
  31. PropertyInfo[] propertys = t.GetType().GetProperties();
  32. foreach (PropertyInfo pi in propertys)
  33. {
  34. attributeName = pi.Name;
  35. // 检查DataTable是否包含此列
  36. //此处要求DataRow的列名称要和对象属性名称一致
  37. //注意:此处大小写不敏感
  38. if (dr.Table.Columns.Contains(attributeName))
  39. {
  40. // 判断此属性是否为只读(不包含set构造)
  41. if (!pi.CanWrite) { continue; }
  42. //给属性赋值
  43. var value = dr[attributeName];
  44. if (value != DBNull.Value)
  45. {
  46. pi.SetValue(t, value,null);
  47. }
  48. }
  49. }
  50. return t;
  51. }
  52. /// <summary>
  53. /// 将DataTable直接转化为对象集合
  54. /// </summary>
  55. /// <typeparam name="T"></typeparam>
  56. /// <param name="dt"></param>
  57. /// <returns></returns>
  58. internal static List<T> ToModelList<T>(this DataTable dt)
  59. {
  60. List<T> list = new List<T>();
  61. //调用ToModel方法添加List
  62. for (int i = 0; i < dt.Rows.Count; i++)
  63. {
  64. T t = Activator.CreateInstance<T>();
  65. t = dt.Rows[i].ToModel<T>();
  66. list.Add(t);
  67. }
  68. return list;
  69. }
  70. }
  71. }
复制代码

还用到了SqlHelper来进行数据库的操作,这个很简单,不在贴代码了.

使用方法:

1 这四个属性对应数据库中的表名以及列名,可以自定义,例如下图这样.

  1.      private readonly string tableName = "blog_Config";//表名
  2. private readonly string columnKey = "c_Key";//key列名
  3. private readonly string columnValue = "c_Value";//Value列名
  4. private readonly string columnType = "c_Type";//Type列名
复制代码

Screen Shot 2018-03-10 at 15.26.58 PM.png

key要设置为主键,类型都为varchar,长度视情况而定.

2 数据库链接字符串都是sqlHelper类中定义,SqlHelper类参考文章:http://www.chengchenxu.com/Article/11/sqlhelper

3 创建一个Model进行Load和Save操作

  1. public class ConfigSeoModel
  2. {
  3. [Display(Name = "Meta关键字")]
  4. public string KeyWord { get; set; }
  5. [Display(Name = "Meta描述")]
  6. public string Description { get; set; }
  7. }
  8. //
  9. ConfigModelDAL dal=new ConfigModelDAL();
  10. //new 一个Model
  11. ConfigSeoModel model=new ConfigSeoModel();
  12. model.KeyWord="关键字";
  13. model.Description = "描述"
  14. //完成保存
  15. dal.Save<ConfigSeoModel>(model);
  16. //读取
  17. ConfigSeoModel model = dal.Load<ConfigModel>();
复制代码


本文为博主原创,转载请保留出处:
http://www.chengchenxu.com/Article/24/fanxing





回复

使用道具 举报