• 多年前写的DataTable与实体类的转换,已放github


    阅读目录

    介绍

     很多年前一直使用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], "张三");
            }
        }
    复制代码

    测试结果如下:

    两个测试用例均通过。

    GitHub

    https://github.com/sinodzh/TransformDTAndModel

  • 相关阅读:
    IOS开发-cell的动态高度
    IOS开发-视频,音频,录音简单总结
    cocoapods的安装及注意事项
    CUICatalog: Invalid asset name supplied: (null) _configureCellForDisplay:forIndexPath
    IOS开发—数据库的使用
    IOS开发-键盘通知自定义键盘
    IOS开发-手势简单使用及手势不响应处理办法
    IOS开发-UITextField代理常用的方法总结
    Linux Shell 编程学习笔记
    Java的进程内缓存框架:EhCache
  • 原文地址:https://www.cnblogs.com/xieyulin/p/7070272.html
Copyright © 2020-2023  润新知