多年前写的DataTable与实体类的转换

介绍

介绍

很多年前一直使用Ado.net,后来慢慢转型到其他的orm,在转型过程中,有意向将两者的模型结合起来,利用DataTable中的行状态完善一些mvc中的数据控制作用。现在把它放出来,留个纪念。

起因

很多年前,对Ado.net这块了解较深,当时公司也有一套框架,将Ado.net做成了ORMapping,所以,当时对DataTable的操作很是熟练。

 DataTable中的行状态很好的和界面的数据后者操作进行了关联,比如新增,修改,取消,删除等,都能在DataTable中的行状态对应起来,然后那个orm框架就自动根据不同的行状态生成sql语句,也是比较方便。

后来,技术一直在进步,也使用过EF,使用过java移植过来的Nhibernate,这样对实体类的操作越来越多,当时就产生了这样一个想法,界面绑定DataTable,然后数据的变动通过这些新的orm工具持久化起来,于是就做了这个工具类。

代码

  因为是工具类,代码结构比较简单。如图:

TransformUtil工具类主要就3个方法。

一:ConvertDataTableToModel:

主要将DataTable中改动的内容同步到实体类集合中

/// <summary>
        /// 将DB中改动的内容同步到泛型集合中
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="source">dt源</param>
        /// <param name="destinationArray">目标Model集合</param>
        /// <returns></returns>
        public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray)
            where T : class
        {
            if (source == null || destinationArray == null || source.PrimaryKey == null || source.PrimaryKey.Count() <= 0)
                return false;

            DataTable dtChange = source.GetChanges();
            if (dtChange == null)
                return false;

            List<string> keys = new List<string>();
            foreach (var item in source.PrimaryKey)
            {
                keys.Add(item.ColumnName);
            }

            return ConvertDataTableToModel(source, destinationArray, keys);
        }
二:ConvertDataTableToModel重载:
/// <summary>
        /// 同步table里改动的数据到泛型集合里去(新增,修改,删除)
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="source">dt源</param>
        /// <param name="destinationArray">目标Model集合</param>
        /// <param name="keyColumnArray">主键集合</param>
        /// <returns></returns>
        public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray, List<string> keyColumnArray)
            where T : class
        {
            if (source == null || destinationArray == null || source.Rows.Count == 0 || keyColumnArray == null || keyColumnArray.Count == 0)
                return false;

            Type modeType = destinationArray.GetType().GetGenericArguments()[0];//模型类型
            PropertyInfo[] ppInfoArray = modeType.GetProperties();//公共属性集合
            List<PropertyInfo> listPPInfo = ppInfoArray.ToList();//方便查询
            //关键列
            List<PropertyInfo> keyPIArray = listPPInfo.FindAll(x => keyColumnArray.Contains(x.Name));

            List<T> listToDelete = new List<T>();
            //新增的数据
            DataRow[] drAddArray = source.Select("", "", DataViewRowState.Added);

            object objItem = modeType.Assembly.CreateInstance(modeType.FullName);
            foreach (DataRow dr in drAddArray)
            {
                destinationArray.Add((T)objItem);
                foreach (System.Reflection.PropertyInfo pi in listPPInfo)
                {
                    pi.SetValue(destinationArray[destinationArray.Count - 1], dr[pi.Name], null);
                }
            }
            //修改和删除的数据
            DataView dvForOP = new DataView(source);
            dvForOP.RowStateFilter = DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent;

            foreach (DataRowView drv in dvForOP)
            {
                for (int i = 0; i < destinationArray.Count; i++)
                {
                    bool blIsTheRow = true;
                    //找出关键列对应的行
                    foreach (System.Reflection.PropertyInfo pInfo in keyPIArray)
                    {
                        object okey = pInfo.GetValue(destinationArray[i], null);
                        if (okey == null)
                            continue;
                        if (drv[pInfo.Name].ToString() != okey.ToString())
                        {
                            blIsTheRow = false;
                            break;
                        }
                    }
                    if (!blIsTheRow)//非本行
                        continue;
                    //根据行状态同步赋值
                    switch (drv.Row.RowState)
                    {
                        case DataRowState.Modified:
                            {
                                foreach (System.Reflection.PropertyInfo pi in listPPInfo)
                                {
                                    if (keyPIArray.Contains(pi))//主键列不更新
                                        continue;
                                    pi.SetValue(destinationArray[i], drv[pi.Name], null);
                                }
                            } break;
                        case DataRowState.Deleted:
                            {
                                listToDelete.Add(destinationArray[i]);
                            } break;
                    }
                }
            }

            for (int i = 0; i < listToDelete.Count; i++)
            {
                destinationArray.Remove(listToDelete[i]);
            }

            return true;
        }

三:ConvertModelToDataTable:

将实体类集合转成DataTable。其中params这个参数比较有意思,大家可以去查下。

/// <summary>
        /// 将泛型集合类转换成DataTable
        /// </summary>
        /// <typeparam name="T">集合项类型</typeparam>
        /// <param name="sourceArray">集合</param>
        /// <param name="propertyNameArray">需要返回的列的列名,如需返回所有列,此参数传入null值</param>
        /// <returns>数据集(表)</returns>
        public static DataTable ConvertModelToDataTable<T>(IList<T> sourceArray, params string[] propertyNameArray)
            where T:class
        {
            List<string> propertyNameList = new List<string>();
            if (propertyNameArray != null)
                propertyNameList.AddRange(propertyNameArray);

            DataTable result = new DataTable();
            //获取结构
            Type[] typeArr = sourceArray.GetType().GetGenericArguments();
            if (typeArr.Length == 0)
                return result;

            PropertyInfo[] propertys = typeArr[0].GetProperties();
            foreach (PropertyInfo pi in propertys)
            {
                if (propertyNameList.Count == 0)
                {
                    result.Columns.Add(pi.Name, pi.PropertyType);
                }
                else
                {
                    if (propertyNameList.Contains(pi.Name))
                        result.Columns.Add(pi.Name, pi.PropertyType);
                }
            }
            for (int i = 0; i < sourceArray.Count; i++)
            {
                ArrayList tempList = new ArrayList();
                foreach (PropertyInfo pi in propertys)
                {
                    if (propertyNameList.Count == 0)
                    {
                        object obj = pi.GetValue(sourceArray[i], null);
                        tempList.Add(obj);
                    }
                    else
                    {
                        if (propertyNameList.Contains(pi.Name))
                        {
                            object obj = pi.GetValue(sourceArray[i], null);
                            tempList.Add(obj);
                        }
                    }
                }
                object[] array = tempList.ToArray();
                result.LoadDataRow(array, true);
            }

            return result;
        }

四:ConvertDataViewToModel:

将Dataview中所以内容转成实体。

/// <summary>
        /// 将视图转换成泛型集合
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="dataView">视图</param>
        /// <param name="model">泛型实例</param>
        /// <returns></returns>
        public static List<T> ConvertDataViewToModel<T>(DataView dataView, T model)
            where T:class
        {
            List<T> listReturn = new List<T>();
            Type modelType = model.GetType();
            DataTable dt = dataView.Table;
            //获取model所有类型
            PropertyInfo[] modelProperties = modelType.GetProperties();

            //遍历所有行,逐行添加对象
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                object obj = modelType.Assembly.CreateInstance(modelType.FullName);
                listReturn.Add((T)obj);
                //遍历model所有属性
                foreach (PropertyInfo pi in modelProperties)
                {
                    //遍历所有列
                    foreach (DataColumn col in dt.Columns)
                    {
                        //如果列数据类型与model的数据类型相同、名称相同
                        if (col.DataType == pi.PropertyType
                            && col.ColumnName == pi.Name)
                        {
                            pi.SetValue(obj, dt.Rows[i][col.ColumnName], null);
                        }
                    }
                }
            }

            return listReturn;
        }

UnitTest

这次的UntTest比较简单,覆盖率也不是100%,都快12点了,得休息了,就简单的弄了2个测试方法。如下:

[TestMethod]
        public void TestConvertDataTableToModel()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Id", typeof(string));
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Address", typeof(string));
            dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };

            dt.Rows.Add("0001", "张三", "武汉市");
            dt.Rows.Add("0002", "李四", "北京市");
            dt.AcceptChanges();
            dt.Rows.Add("0003", "王五", "深圳市");

            List<People> allPeople = new List<People>();

            TransformUtil.ConvertDataTableToModel<People>(dt, allPeople);

            //断言是不是只有一个数据,平且是只是修改状态的王五这个人
            Assert.AreEqual(allPeople.Count, 1);
            Assert.AreEqual(allPeople[0].Name, "王五");
        }
[TestMethod]
        public void TestConvertModelToDataTable()
        {
            List<People> allPeople = new List<People>()
            {
              new People(){ Id="0001", Name="张三", Address ="武汉市"},
              new People(){ Id="0002", Name="李四", Address ="北京市"},
              new People(){ Id="0003", Name="王五", Address ="深圳市"}
            };

            DataTable dt = TransformUtil.ConvertModelToDataTable<People>(allPeople, null);

            //断言是不是有3行数据,数据的列有3列,第1列是不是Id,第一行第二列是不是张三
            Assert.AreEqual(dt.Rows.Count, 3);
            Assert.AreEqual(dt.Columns.Count, 3);
            Assert.AreEqual(dt.Columns[0].ColumnName, "Id");
            Assert.AreEqual(dt.Rows[0][1], "张三");
        }
    }

测试结果如下:

两个测试用例均通过。

时间: 2024-11-14 10:24:54

多年前写的DataTable与实体类的转换的相关文章

DataTable与实体类互相转换

/// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T">实体类</typeparam> public class ModelHandler<T> where T : new() { #region DataTable转换成实体类 /// <summary> /// 填充对象列表:用DataSet的第一个表填充实体类 ///

DataTable转实体类

/// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T">实体类</typeparam> public class ModelHandler<T> where T : new() { #region DataTable转换成实体类 /// <summary> /// 填充对象列表:用DataSet的第一个表填充实体类 ///

.net 根据匿名类生成实体类,根据datatable生成实体类,根据sql生成实体类

在开发中可能会遇到这几种情况 1.EF或LINQ查询出来的匿名对象在其它地方调用不方便,又懒的手动建实体类 2.通过datatable反射实体需要先建一个类 ,头痛 3.通过SQL语句返回的实体也需要先建一个类 ,头痛 4.如果通过代码生成器要写模版,需要安装或者不想生成一堆不用的类 为了解决上面的不便之处,我封装了一个实体生成类,可以扔到程序里面任意调用 封装类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

C# DataTable 转 实体类

C# 中查询结果DataTable转实体类: 比如:List<RtmInterview> rtmList = GetDataById( id); public List<RtmInterview> GetDataById(string id) { List<RtmInterview> rtmList = new List<RtmInterview>(); bool ConnectionOpenHere = false; try { DataTable dt

使用 AutoMapper 映射 IDataReader、DataSet、DataTable 到实体类

AutoMapper是一个.NET的对象映射工具. 项目地址:https://github.com/AutoMapper/AutoMapper. 帮助文档:https://github.com/AutoMapper/AutoMapper/wiki 主要用途 领域对象与DTO之间的转换.数据库查询结果映射至实体对象. 这里主要说下使用 AutoMapper 将 IDataReader.DataSet.DataTable 转为实体的方法. 依赖文件:AutoMapper.dll.AutoMapper

反射DataTable转实体类

1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Reflection; 5 6 namespace Dll 7 { 8 public static class ToEntity 9 { 10 /// <summary> 11 /// 将DataTable转换成实体类 12 /// </summary> 13 /// <typeparam name=&

javabean 实体类的转换

1. spring 工具类 BeanUtils.copyProperties 简单的实体类之间的转换,不能copy Date类型,利用java反射的原理来进行属性的复制.如果两个实体的类的里面嵌套实体类的类型不一样,copy后实体类的变为原实体类的类型,当在此使用目标实体类的时候会发生类型的转化异常.2. MapStruct是一个代码生成器的工具类,简化了不同的Java Bean之间映射的处理,所以映射指的就是从一个实体变化成一个实体.在实际项目中,我们经常会将PO转DTO.DTO转PO等一些实

datatable与实体相互转换 反射

namespace Mall.Config{/// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T">实体类</typeparam> public class ModelHandler<T> where T : new() { #region DataTable转换成实体类 /// <summary> /// 填充对象列表:

实体类与DataTable互换

/// <summary> /// 实体类转换成DataTable /// </summary> /// <param name="modelList">实体类列表</param> /// <returns></returns> public DataTable FillDataTable(List<T> modelList) { if (modelList == null || modelList.C