利用泛型和反射,管理配置文件,把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()篇! 先看看他每天是在干什么 //好吧,很多重复的,只不过想表达项目里 ...
随机推荐
- Welcome-to-Swift-21协议(Protocols)
协议定义了一个方法的蓝图,属性和其他适合特定任务或功能的要求.协议实际上并不提供一个这些要求的实现,它只是描述了一个实现会是什么样子.协议可以通过一个类,结构或枚举提供这些要求的具体实现.满足要求的任 ...
- 内存分配(new/delete,malloc/free,allocator,内存池)
以下来源http://www.cnblogs.com/JCSU/articles/1051826.html 程序员们经常编写内存管理程序,往往提心吊胆.如果不想触雷,唯一的解决办法就是发现所有潜伏的地 ...
- 浅谈Linux下的五种I/O模型 两篇别人的博客
http://blog.csdn.net/sinat_34990639/article/details/52778562 http://www.cnblogs.com/chy2055/p/5220 ...
- UGUI 点击穿透问题
unity上 用 做游戏欢迎界面上通用的ui,然后导到游戏里面直接用,但发现游戏里面是用ngui的,点击ugui 的ui 会穿透过去 ngui会响应,原本模型的点击处理也会响应 我用的 unity 版 ...
- 【vijos1144】小胖守皇宫(树形DP)
描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫 ...
- JSTL <C:if></C:if> 和<C:ForEach></C:ForEach> 入门级~
一.<C:If>标签:条件判断语句 <c:if test="${objList.nodetype == 1}">上级节点</c:if> te ...
- PE+ 1.0 ( Pump Express Plus 1.0 )
Dialog iW1788 for PE+ 1.0 Dialog iW1680 for PE PE+1.0 for up to 15W battery, improve charging time, ...
- Linux 之 LNMP服务器搭建-Nginx
LNMP服务器搭建-Nginx 参考教程:[千峰教育] 系统版本: CentOS 6.8 关闭防火墙和Selinux service iptables stop setenforce 安装Nginx ...
- 用jQuery File Upload实现简单的文件上传
FORM中的代码: {# file_path #} <div class="form-group"> <label class="control-lab ...
- SPOJ GSS系列(数据结构维护技巧入门)
题目链接 GSS $GSS1$ 对于每个询问$l$, $r$,查询$a_{l}$, $a_{l+1}$, $a_{l+2}$, ..., $a_{r}$这个序列的最大字段和. 建立线段树,每个节点维护 ...