本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

阅读目录

本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

介绍

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

起因

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

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

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

代码

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

TransformUtil工具类主要就3个方法

一:ConvertDataTableToModel:

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

  1. /// <summary>
  2. /// 将DB中改动的内容同步到泛型集合中
  3. /// </summary>
  4. /// <typeparam name="T">类型</typeparam>
  5. /// <param name="source">dt源</param>
  6. /// <param name="destinationArray">目标Model集合</param>
  7. /// <returns></returns>
  8. public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray)
  9. where T : class
  10. {
  11. if (source == null || destinationArray == null || source.PrimaryKey == null || source.PrimaryKey.Count() <= )
  12. return false;
  13.  
  14. DataTable dtChange = source.GetChanges();
  15. if (dtChange == null)
  16. return false;
  17.  
  18. List<string> keys = new List<string>();
  19. foreach (var item in source.PrimaryKey)
  20. {
  21. keys.Add(item.ColumnName);
  22. }
  23.  
  24. return ConvertDataTableToModel(source, destinationArray, keys);
  25. }

二:ConvertDataTableToModel重载:

  1. /// <summary>
  2. /// 同步table里改动的数据到泛型集合里去(新增,修改,删除)
  3. /// </summary>
  4. /// <typeparam name="T">类型</typeparam>
  5. /// <param name="source">dt源</param>
  6. /// <param name="destinationArray">目标Model集合</param>
  7. /// <param name="keyColumnArray">主键集合</param>
  8. /// <returns></returns>
  9. public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray, List<string> keyColumnArray)
  10. where T : class
  11. {
  12. if (source == null || destinationArray == null || source.Rows.Count == || keyColumnArray == null || keyColumnArray.Count == )
  13. return false;
  14.  
  15. Type modeType = destinationArray.GetType().GetGenericArguments()[];//模型类型
  16. PropertyInfo[] ppInfoArray = modeType.GetProperties();//公共属性集合
  17. List<PropertyInfo> listPPInfo = ppInfoArray.ToList();//方便查询
  18. //关键列
  19. List<PropertyInfo> keyPIArray = listPPInfo.FindAll(x => keyColumnArray.Contains(x.Name));
  20.  
  21. List<T> listToDelete = new List<T>();
  22. //新增的数据
  23. DataRow[] drAddArray = source.Select("", "", DataViewRowState.Added);
  24.  
  25. object objItem = modeType.Assembly.CreateInstance(modeType.FullName);
  26. foreach (DataRow dr in drAddArray)
  27. {
  28. destinationArray.Add((T)objItem);
  29. foreach (System.Reflection.PropertyInfo pi in listPPInfo)
  30. {
  31. pi.SetValue(destinationArray[destinationArray.Count - ], dr[pi.Name], null);
  32. }
  33. }
  34. //修改和删除的数据
  35. DataView dvForOP = new DataView(source);
  36. dvForOP.RowStateFilter = DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent;
  37.  
  38. foreach (DataRowView drv in dvForOP)
  39. {
  40. for (int i = ; i < destinationArray.Count; i++)
  41. {
  42. bool blIsTheRow = true;
  43. //找出关键列对应的行
  44. foreach (System.Reflection.PropertyInfo pInfo in keyPIArray)
  45. {
  46. object okey = pInfo.GetValue(destinationArray[i], null);
  47. if (okey == null)
  48. continue;
  49. if (drv[pInfo.Name].ToString() != okey.ToString())
  50. {
  51. blIsTheRow = false;
  52. break;
  53. }
  54. }
  55. if (!blIsTheRow)//非本行
  56. continue;
  57. //根据行状态同步赋值
  58. switch (drv.Row.RowState)
  59. {
  60. case DataRowState.Modified:
  61. {
  62. foreach (System.Reflection.PropertyInfo pi in listPPInfo)
  63. {
  64. if (keyPIArray.Contains(pi))//主键列不更新
  65. continue;
  66. pi.SetValue(destinationArray[i], drv[pi.Name], null);
  67. }
  68. } break;
  69. case DataRowState.Deleted:
  70. {
  71. listToDelete.Add(destinationArray[i]);
  72. } break;
  73. }
  74. }
  75. }
  76.  
  77. for (int i = ; i < listToDelete.Count; i++)
  78. {
  79. destinationArray.Remove(listToDelete[i]);
  80. }
  81.  
  82. return true;
  83. }

三:ConvertModelToDataTable:

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

  1. /// <summary>
  2. /// 将泛型集合类转换成DataTable
  3. /// </summary>
  4. /// <typeparam name="T">集合项类型</typeparam>
  5. /// <param name="sourceArray">集合</param>
  6. /// <param name="propertyNameArray">需要返回的列的列名,如需返回所有列,此参数传入null值</param>
  7. /// <returns>数据集(表)</returns>
  8. public static DataTable ConvertModelToDataTable<T>(IList<T> sourceArray, params string[] propertyNameArray)
  9. where T:class
  10. {
  11. List<string> propertyNameList = new List<string>();
  12. if (propertyNameArray != null)
  13. propertyNameList.AddRange(propertyNameArray);
  14.  
  15. DataTable result = new DataTable();
  16. //获取结构
  17. Type[] typeArr = sourceArray.GetType().GetGenericArguments();
  18. if (typeArr.Length == )
  19. return result;
  20.  
  21. PropertyInfo[] propertys = typeArr[].GetProperties();
  22. foreach (PropertyInfo pi in propertys)
  23. {
  24. if (propertyNameList.Count == )
  25. {
  26. result.Columns.Add(pi.Name, pi.PropertyType);
  27. }
  28. else
  29. {
  30. if (propertyNameList.Contains(pi.Name))
  31. result.Columns.Add(pi.Name, pi.PropertyType);
  32. }
  33. }
  34. for (int i = ; i < sourceArray.Count; i++)
  35. {
  36. ArrayList tempList = new ArrayList();
  37. foreach (PropertyInfo pi in propertys)
  38. {
  39. if (propertyNameList.Count == )
  40. {
  41. object obj = pi.GetValue(sourceArray[i], null);
  42. tempList.Add(obj);
  43. }
  44. else
  45. {
  46. if (propertyNameList.Contains(pi.Name))
  47. {
  48. object obj = pi.GetValue(sourceArray[i], null);
  49. tempList.Add(obj);
  50. }
  51. }
  52. }
  53. object[] array = tempList.ToArray();
  54. result.LoadDataRow(array, true);
  55. }
  56.  
  57. return result;
  58. }

四:ConvertDataViewToModel:

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

  1. /// <summary>
  2. /// 将视图转换成泛型集合
  3. /// </summary>
  4. /// <typeparam name="T">类型</typeparam>
  5. /// <param name="dataView">视图</param>
  6. /// <param name="model">泛型实例</param>
  7. /// <returns></returns>
  8. public static List<T> ConvertDataViewToModel<T>(DataView dataView, T model)
  9. where T:class
  10. {
  11. List<T> listReturn = new List<T>();
  12. Type modelType = model.GetType();
  13. DataTable dt = dataView.Table;
  14. //获取model所有类型
  15. PropertyInfo[] modelProperties = modelType.GetProperties();
  16.  
  17. //遍历所有行,逐行添加对象
  18. for (int i = ; i < dt.Rows.Count; i++)
  19. {
  20. object obj = modelType.Assembly.CreateInstance(modelType.FullName);
  21. listReturn.Add((T)obj);
  22. //遍历model所有属性
  23. foreach (PropertyInfo pi in modelProperties)
  24. {
  25. //遍历所有列
  26. foreach (DataColumn col in dt.Columns)
  27. {
  28. //如果列数据类型与model的数据类型相同、名称相同
  29. if (col.DataType == pi.PropertyType
  30. && col.ColumnName == pi.Name)
  31. {
  32. pi.SetValue(obj, dt.Rows[i][col.ColumnName], null);
  33. }
  34. }
  35. }
  36. }
  37.  
  38. return listReturn;
  39. }

UnitTest

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

  1. [TestMethod]
  2. public void TestConvertDataTableToModel()
  3. {
  4. DataTable dt = new DataTable();
  5. dt.Columns.Add("Id", typeof(string));
  6. dt.Columns.Add("Name", typeof(string));
  7. dt.Columns.Add("Address", typeof(string));
  8. dt.PrimaryKey = new DataColumn[] { dt.Columns[] };
  9.  
  10. dt.Rows.Add("", "张三", "武汉市");
  11. dt.Rows.Add("", "李四", "北京市");
  12. dt.AcceptChanges();
  13. dt.Rows.Add("", "王五", "深圳市");
  14.  
  15. List<People> allPeople = new List<People>();
  16.  
  17. TransformUtil.ConvertDataTableToModel<People>(dt, allPeople);
  18.  
  19. //断言是不是只有一个数据,平且是只是修改状态的王五这个人
  20. Assert.AreEqual(allPeople.Count, );
  21. Assert.AreEqual(allPeople[].Name, "王五");
  22. }
  1. [TestMethod]
  2. public void TestConvertModelToDataTable()
  3. {
  4. List<People> allPeople = new List<People>()
  5. {
  6. new People(){ Id="", Name="张三", Address ="武汉市"},
  7. new People(){ Id="", Name="李四", Address ="北京市"},
  8. new People(){ Id="", Name="王五", Address ="深圳市"}
  9. };
  10.  
  11. DataTable dt = TransformUtil.ConvertModelToDataTable<People>(allPeople, null);
  12.  
  13. //断言是不是有3行数据,数据的列有3列,第1列是不是Id,第一行第二列是不是张三
  14. Assert.AreEqual(dt.Rows.Count, );
  15. Assert.AreEqual(dt.Columns.Count, );
  16. Assert.AreEqual(dt.Columns[].ColumnName, "Id");
  17. Assert.AreEqual(dt.Rows[][], "张三");
  18. }
  19. }

测试结果如下:

两个测试用例均通过。

GitHub

https://github.com/sinodzh/TransformDTAndModel

本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

多年前写的DataTable与实体类的转换,已放github的更多相关文章

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

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

  2. DataTable与实体类的转换

    多年前写的DataTable与实体类的转换,已放github 阅读目录 介绍 起因 代码 UnitTest GitHub 介绍 很多年前一直使用Ado.net,后来慢慢转型到其他的orm,在转型过程中 ...

  3. DataTable与实体类互相转换

    /// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T"& ...

  4. 【转】DataTable与实体类互相转换

    原文地址:https://www.cnblogs.com/marblemm/p/7084797.html /// <summary> /// DataTable与实体类互相转换 /// & ...

  5. DataTable转实体类

    /// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T"& ...

  6. DataTable和实体类通过反射相互转换

    using System.Runtime.Serialization; using System.Data; using System.Reflection; using System.Collect ...

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

    在开发中可能会遇到这几种情况 1.EF或LINQ查询出来的匿名对象在其它地方调用不方便,又懒的手动建实体类 2.通过datatable反射实体需要先建一个类 ,头痛 3.通过SQL语句返回的实体也需要 ...

  8. 我写了一个java实体类,implements了Serializable接口,然后我如何让serialversionUID自动生成

    写了一个java实体类,implements了Serializable接口,让serialversionUID自动生成方法: 1.点击类旁边的警告符号: 2.选择Add generated seria ...

  9. C# DataTable 转 实体类

    C# 中查询结果DataTable转实体类: 比如:List<RtmInterview> rtmList = GetDataById( id); public List<RtmInt ...

随机推荐

  1. SNAT,是源地址转换,其作用是将ip数据包的源地址转换成另外一个地址

    SNAT,可能有人觉得奇怪,好好的为什么要进行ip地址转换啊,为了弄懂这个问题,我们要看一下局域网用户上公网的原理,假设内网主机A(192.168.2.8)要和外网主机B(61.132.62.131) ...

  2. soap缓存问题

    问题描述: ws提供方在原有基础上增加了一个方法,通过php的soap扩展硬是获取不到该方法,提示,该方法不存在. 问题跟节: soap缓存问题,导致无法获取最新的ws文件信息 解决办法: 1.直接在 ...

  3. Java集合源码分析(一)

    Java集合工具包位于Java.util包下,包含了很多常用的数据结构,如数组.链表.栈.队列.集合.哈希表等.学习Java集合框架下大致可以分为如下五个部分:List列表.Set集合.Map映射.迭 ...

  4. Linux命令速查手册,超详细Linux命令教程

    一.常用命令速查 ls cd pwd cat more less tail head cp scp mv mkdir rmdir touch rm ps kill top free clear tre ...

  5. jenkins 邮件配置

    jenkins 自带一个邮件的通知的功能,但是自带的邮件通知功能,有点简单不能自定义信息,所以我们安装邮件插件Email-ext plugin.1.首先在系统管理-插件管理-安装Email-ext p ...

  6. Ionic 今天发布了Windows 桌面版的IDE Ionic Lab

    Ionic简介: Ionic 是一个强大的 HTML5 应用程序开发框架,号称 Advanced HTML5 Hybrid Mobile AppFramework 是 AngularJS 移动端解决方 ...

  7. Mega Dropdown - 带子分类的响应式下拉菜单

    当你在开发一个内容很多的 Web 项目的时候,最具挑战性的部分之一是为了如果更方便用户浏览这些内容.我们都能想到的一个例子是 Amazon,无限的类别以及它们的子类别.Mega Dropdown 是带 ...

  8. Scroll Depth – 衡量页面滚动的 Google 分析插件

    Scroll Depth 是一个小型的 Google Analytics(谷歌分析)插件,可以让你衡量用户在页面上滚动了多远.它可以监控 25%.50%.75% 和 100% 四个滚动点,并发送谷歌分 ...

  9. CSS盒子模型

    2016-10-22 <css入门经典>第6章 1.每个HTML元素对应于一个显示盒子,但不是所有的元素都显示在屏幕上. 2.HTML元素显示为CSS显示盒子的真正方法称为"可视 ...

  10. CSS常用样式(三)

    一.2D变换 1.transform   设置或检索对象的转换 取值: none::以一个含六值的(a,b,c,d,e,f)变换矩阵的形式指定一个2D变换,相当于直接应用一个[a,b,c,d,e,f] ...