利用泛型和反射,管理配置文件,把Model转换成数据行,并把数据行转换成Model
利用泛型和反射,管理配置文件,把Model转换成数据行,并把数据行转换成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:97391519@qq.com /// 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
利用泛型和反射,管理配置文件,把Model转换成数据行,并把数据行转换成Model的更多相关文章
- .NET基础篇——利用泛型与反射更新实体(ADO.NET Entity Framework)(转)
自从ADO.NET Entity Framework面世以来,受到大家的热捧,它封装了大量代码生成的工具,用户只需要建立好实体之间的关系,系统就是会为用户自动成功了Add.Delete.CreateO ...
- 利用泛型抽取Dao层,加事务注解问题(java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType)
想利用泛型抽取BaseDao层,简化操作时出现故障: @Transactional这个注解是能够继承的.于是就想写在抽取的BaseDao层上,让实现的类能够不用写@Transactional,就可开启 ...
- Java高质量代码之 — 泛型与反射
在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用 ...
- DataReader,DataTable利用泛型填充实体类
using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary ...
- 利用Java的反射与代理机制实现AOP
在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP. 一.AOP概述 AOP(Aspe ...
- c#利用泛型集合,为自己偷偷懒。
有人说"越懒"的程序员进步的越快!其实还挺有道理.亲身体验,从刚出来工作到现在,自己变"懒"了许多,但感觉写出来的代码确有了不少提升.刚开始啊,同样的代码,赋值 ...
- 利用StringList对象来管理这些动态生成的对象
如果程序需要动态创建大量的对象,那么我们可以利用StringList对象来管理这些动态生成的对象.1.创建StringList对象:OBJ := TStringList.Create; 2.保存动态生 ...
- 应用Java泛型和反射导出CSV文件
项目中有需求要把数据导出为CSV文件,因为不同的类有不同的属性,为了代码简单,应用Java的泛型和反射,写了一个函数,完成导出功能. public <T> void saveFile(Li ...
- Android高效率编码-findViewById()的蜕变-注解,泛型,反射
Android高效率编码-findViewById()的蜕变-注解,泛型,反射 Android的老朋友findViewById()篇! 先看看他每天是在干什么 //好吧,很多重复的,只不过想表达项目里 ...
随机推荐
- Educational Codeforces Round 37 (Rated for Div. 2)
我的代码应该不会被hack,立个flag A. Water The Garden time limit per test 1 second memory limit per test 256 mega ...
- spring scope 属性的取值
Spring 容器是通过单例模式创建 Bean 对象的,也就是说,默认情况下,通过调用 ac.getBean("mybean")方法获得的对象都是同一个 mybean 对象 使用单 ...
- PHP杂技(二)
php array_merge($a,$b)与 $a+$b区别 array_merge 数字键名会被重新编号,what's '...' $data = [[1, 2], [3], [4, 5]]; v ...
- kmp-模板-hd-1711
p数组记录的是当该位置上失配的时候,跳到第几个进行继续匹配: /* 题意:给两个数串,求模板串第一此出现在源串中的位置,开头的位置:没有输出-1: 算法:kmp 先对字符串进行自匹配: 然后串间匹配: ...
- 飞行员配对方案问题(匈牙利算法+sort)
洛谷传送门 匈牙利算法+sort 没什么好说的. ——代码 #include <cstdio> #include <cstring> #include <algorith ...
- XML与DTD简介
(详细学习参考)https://blog.csdn.net/u013087513/article/details/52745509 XML约束之DTD的使用 (1)为什么要有约束? XML都是用户自定 ...
- Java面试题之Java反射的原理
什么是Java的反射? 在运行状态中,对于任意一个类,都能够知道这个类的属性和方法: 反射的作用? 如果给定一个类名,就可以通过反射机制来获取类的所有信息,也可以动态的创建对象和编译: 反射的原理? ...
- COGS728. [网络流24题] 最小路径覆盖问题
算法实现题8-3 最小路径覆盖问题(习题8-13) ´问题描述: 给定有向图G=(V,E).设P是G的一个简单路(顶点不相交)的集合.如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖.P中 ...
- 【CF505D】Mr. Kitayuta's Technology
题目大意: 在一个有向图中,有n个顶点,给出m对数字(u,v)表示顶点u和顶点v必须直接或者间接相连,让你构造一个这样的图,输出最少需要多少条边. 挖坑待填 官方题解链接:http://codefor ...
- 【BZOJ入门3189】 猜数字(数学,搜索)
Description 味味最近在玩猜数字的游戏,现在她也希望你来玩一下这个游戏.猜数字游戏的规则是这样的,告诉你一个正整数 n(2<=n<=11),然后味味心中会想一个 n 个数字组成的 ...