利用泛型和反射,管理配置文件,把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的更多相关文章

  1. .NET基础篇——利用泛型与反射更新实体(ADO.NET Entity Framework)(转)

    自从ADO.NET Entity Framework面世以来,受到大家的热捧,它封装了大量代码生成的工具,用户只需要建立好实体之间的关系,系统就是会为用户自动成功了Add.Delete.CreateO ...

  2. 利用泛型抽取Dao层,加事务注解问题(java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType)

    想利用泛型抽取BaseDao层,简化操作时出现故障: @Transactional这个注解是能够继承的.于是就想写在抽取的BaseDao层上,让实现的类能够不用写@Transactional,就可开启 ...

  3. Java高质量代码之 — 泛型与反射

    在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用 ...

  4. DataReader,DataTable利用泛型填充实体类

    using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary ...

  5. 利用Java的反射与代理机制实现AOP

    在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP. 一.AOP概述 AOP(Aspe ...

  6. c#利用泛型集合,为自己偷偷懒。

    有人说"越懒"的程序员进步的越快!其实还挺有道理.亲身体验,从刚出来工作到现在,自己变"懒"了许多,但感觉写出来的代码确有了不少提升.刚开始啊,同样的代码,赋值 ...

  7. 利用StringList对象来管理这些动态生成的对象

    如果程序需要动态创建大量的对象,那么我们可以利用StringList对象来管理这些动态生成的对象.1.创建StringList对象:OBJ := TStringList.Create; 2.保存动态生 ...

  8. 应用Java泛型和反射导出CSV文件

    项目中有需求要把数据导出为CSV文件,因为不同的类有不同的属性,为了代码简单,应用Java的泛型和反射,写了一个函数,完成导出功能. public <T> void saveFile(Li ...

  9. Android高效率编码-findViewById()的蜕变-注解,泛型,反射

    Android高效率编码-findViewById()的蜕变-注解,泛型,反射 Android的老朋友findViewById()篇! 先看看他每天是在干什么 //好吧,很多重复的,只不过想表达项目里 ...

随机推荐

  1. 如何使用Python的logging模块

    几个学习连接: Python官方链接: https://docs.python.org/3.4/library/logging.html?highlight=logging 翻译(不过是2.3版本的) ...

  2. 【Luogu】P2254瑰丽华尔兹(堆优化DP)

    题目链接 我也不知道为什么脑子一抽就想了个堆优化……然后贼慢…… 因为上午听不懂wys的电音专场(快速傅立叶变换),然后就做了这么一道题. 首先朴素DP很sb都能秒出.就是枚举时刻.位置(两维)然后转 ...

  3. 基于css3翻牌效果

    <div class="map_block float_l lineItem"> <a href="javascript:;" class=& ...

  4. vue.js源码学习分享(七)

    var _Set; /* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) { // use ...

  5. C++ 回调函数的简单例子(转)

    原文转自 http://blog.csdn.net/wnlwcg/article/details/6930990# 1.调用端 // 下面的这个_stdcall很重要的 void _stdcall T ...

  6. 论epoll的实现

    论epoll的实现 上一篇博客 论select的实现 里面已经说了为什么 select 比较慢.poll 的实现和 select 类似,只是少了最大 fd 限制,如果有兴趣可以自己去看代码.我这里来简 ...

  7. hdu 4504(动态规划)

    威威猫系列故事——篮球梦 Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total ...

  8. 在centos7环境下建立MariaDB多实例

    环境全部基于vmware player 12 os: centos7 mariadb: mariadb-10.1.12-linux-x86_64.tar.gz 主要根据MariaDB给出的帮助文档,以 ...

  9. (1)Unity3d界面、入门

    项目视图 层级视图 属性视图 场景视图 游戏视图 调整u3d整体界面布局 1.查看和移动视图 快捷键Q 2.沿轴方向位移 快捷键W 3.沿轴向旋转 快捷键E 4.沿轴向缩放 快捷键R 5.自由调节小大 ...

  10. HTTP/1.1标准请求方法和状态码

    HTTP/1.1标准自从1999年制定以来至今仍然是一个应用广泛并且通行的标准 相关文档 RFC2616:Hypertext Transfer Protocol -- HTTP/1.1 在RFC658 ...