本文版权归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中改动的内容同步到实体类集合中

        /// <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() <= )
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 == || keyColumnArray == null || keyColumnArray.Count == )
return false; Type modeType = destinationArray.GetType().GetGenericArguments()[];//模型类型
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 - ], dr[pi.Name], null);
}
}
//修改和删除的数据
DataView dvForOP = new DataView(source);
dvForOP.RowStateFilter = DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent; foreach (DataRowView drv in dvForOP)
{
for (int i = ; 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 = ; 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 == )
return result; PropertyInfo[] propertys = typeArr[].GetProperties();
foreach (PropertyInfo pi in propertys)
{
if (propertyNameList.Count == )
{
result.Columns.Add(pi.Name, pi.PropertyType);
}
else
{
if (propertyNameList.Contains(pi.Name))
result.Columns.Add(pi.Name, pi.PropertyType);
}
}
for (int i = ; i < sourceArray.Count; i++)
{
ArrayList tempList = new ArrayList();
foreach (PropertyInfo pi in propertys)
{
if (propertyNameList.Count == )
{
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 = ; 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[] }; dt.Rows.Add("", "张三", "武汉市");
dt.Rows.Add("", "李四", "北京市");
dt.AcceptChanges();
dt.Rows.Add("", "王五", "深圳市"); List<People> allPeople = new List<People>(); TransformUtil.ConvertDataTableToModel<People>(dt, allPeople); //断言是不是只有一个数据,平且是只是修改状态的王五这个人
Assert.AreEqual(allPeople.Count, );
Assert.AreEqual(allPeople[].Name, "王五");
}
        [TestMethod]
public void TestConvertModelToDataTable()
{
List<People> allPeople = new List<People>()
{
new People(){ Id="", Name="张三", Address ="武汉市"},
new People(){ Id="", Name="李四", Address ="北京市"},
new People(){ Id="", Name="王五", Address ="深圳市"}
}; DataTable dt = TransformUtil.ConvertModelToDataTable<People>(allPeople, null); //断言是不是有3行数据,数据的列有3列,第1列是不是Id,第一行第二列是不是张三
Assert.AreEqual(dt.Rows.Count, );
Assert.AreEqual(dt.Columns.Count, );
Assert.AreEqual(dt.Columns[].ColumnName, "Id");
Assert.AreEqual(dt.Rows[][], "张三");
}
}

测试结果如下:

两个测试用例均通过。

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. Firemonkey 控件设定字型属性及颜色

    将控件 StyledSettings 的勾取消(如此才能自定样式及字型,如果勾选则依 Style 而定). 设定 TextSettings 里的 Font 属性. 使用代码寫法: CheckBox1. ...

  2. 【Effective Java】8、优先考虑类型安全的异构容器

    有的时候我们一个容器只有一个类型或几个类型并不能满足我们的要求,比如set中存放的元素类型都是同一种,map也就指定的两种 这里我们可以将键进行参数化,而不是将容器参数化,也就是我们可以给容器传一个键 ...

  3. 转【实战体验几种MySQLCluster方案】

    实战体验几种MySQLCluster方案 1.背景 MySQL的cluster方案有很多官方和第三方的选择,选择多就是一种烦恼,因此,我们考虑MySQL数据库满足下三点需求,考察市面上可行的解决方案: ...

  4. 如何让C#像JavaScript一样编程

    JavaScript是一门动态语言,可以动态的给对象添加属性和方法,非常方便.那么有没有一种方式可以让C#也具备动态添加属性和方法的能力,像Javascript一样进行编程? 下面就介绍一个很不错的框 ...

  5. 实例之JavaScript

    使用JavaScript实现5秒倒计时 <html> <head> <meta charset="utf-8"> <title>&l ...

  6. 【前端盲点】DOM事件流论证CSS盒模型是否具有厚度

    前言 很久没有扯淡了,我们今天来扯淡吧. 我今天思考了一个问题,我们页面的dom树到底是如何渲染的,而CSS盒模型与javascript是否有联系,于是便想到一个问题: CSS的盒模型具有厚度么??? ...

  7. Javascript Object、Function对象

    1.Object对象 原型对象 原型是对象的一个属性,也就是prototype属性,每个对象都有这个内部属性,而且他本身也是一个对象. <script type="text/javas ...

  8. Git正确的协作方式(很简单)

    最近部门有人书写了一篇很好的Git协作方式,操作也简单,分支能以保持一条干净的线进行协作开发.这里做个笔记,方便之后查看. PS:本文非原创. 原则 不过分相信自己,自己的修改,可能影响所有人 不过分 ...

  9. 原生JS:Date对象详细参考

    Date对象:基于1970年1月1日(世界标准时间)起的毫秒数 本文参考MDN做的详细整理,方便大家参考MDN 构造函数: new Date(); 依据系统设置的当前时间来创建一个Date对象. ne ...

  10. html5标签的改变

    1.新的文档类型声明 浏览器解析html模式是有两种模式,按照各自浏览器的定义渲染的页面叫“怪异模式”,而按照w3c组织统一的标准渲染叫“标准模式”.一般都是使用标准模式来保持网页兼容性,区分这两种模 ...