@[TOC] (c#中datatable转实体)
什么是databtable
DataTable表示内存中数据的一个表,是一个后台数据源和前台显示之间的适配器。
使用时需要引入命名空间
using System.Data;
DataTable table = new DataTable("Demo");
table.Columns.Add("ID",typeof(int));//ID列
table.Columns.Add("Name", typeof(string));//Name列
table.Columns.Add("Age", typeof(int));//Age列
table.Rows.Add(new object[] { 1, "李", 20 });//第一行(与列想对应)
table.Rows.Add(new object[] { 2,"张",21});//第二行
//获取表试图
DataView dataView = table.DefaultView;
//利用Sort属性,排序
dataView.Sort = "ID DESC";//ID倒序
dataView.ToTable();//创建为新的表格
以上就是创建了一个datatable实例,其实就是数据表结构。
在开发中我们需要根据实体进行数据的操作,操作数据库需要我们创建一个与表结构的列名相对应的实体。
public class Student()
{
public int ID{set;get;}
public string Name{get;set;}
public string Age{get;set;}
}
datatable与实体的相互转换
int ID = (int)dt.Rows[0][0]; //这行是将datatable转成实体,datatable包含行和列,前一个0是第一行,后一个0表示第一列,
//这里还可以使用数据库的列名来识别,int ID = (int)dt.Rows[0]["ID"]; 在实际开发中很多时候是循环赋值的。涉及到大数据时容易眼花,导致数据错误。
string Name=dt.Rows[0][1].ToString();
string Age=dt.Rows[0][2].ToString();
使用映射自动转实体
在面向大数据时,我们可以使用关系映射自动映射,能够避免错误,还能提高开发效率。这里涉及到反射的知识。
public class TableHelpher
{
/// <summary>
/// 填充对象列表:用DataTable填充实体类
/// </summary>
public static List<T> FillModels<T>(DataTable dt) where T: new()
{
/*在C#中,泛型的使用非常广泛,为了泛型调用安全,经常需要对所使用的类型进行约束。
在对泛型的约束中,最常使用的关键字有where 和 new。
其中where关键字是约束所使用的泛型,该泛型必须是where后面的类,或者继承自该类。
new()说明所使用的泛型,必须具有无参构造函数,这是为了能够正确的初始化对象*/
if (dt == null || dt.Rows.Count == 0)
{
return null;
}
List<T> modelList = new List<T>();
var properties = typeof(T).GetProperties();//这里使用泛型,能够支持不同对象的映射取值
foreach (DataRow dr in dt.Rows)
{
T model = (T)Activator.CreateInstance(typeof(T));
/*
使用与指定参数匹配程度最高的构造函数来创建指定类型的实例。
使用Activator.CreateInstance 的实际作用是什么呢?
是因为 想创建一个方法 方法中传入一个类的名称 然后就能返回一个这个类的实例 ,这样的做法让程序有更高的拓展性,
*/
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
var propertyInfo = properties.FirstOrDefault(x => x.GetCustomAttribute<ModelFiledHelper>().DisplayName.Contains(dr.Table.Columns[i].ColumnName));
/*propertyInfo变量接收转换的实体字段名
FirstOrDefault:取序列中满足条件的第一个元素,如果没有元素满足条件,则返回默认值
GetCustomAttribute:检索应用于类型的成员的自定义属性的数组。参数指定成员、要搜索的自定义属性的类型以及是否搜索成员的祖先。*/
if (propertyInfo != null && dr[i] != DBNull.Value)
try
{
propertyInfo.SetValue(model, dr[i], null);
/*为字段赋值*/
}
catch (Exception)
{
}
}
modelList.Add(model);
}
return modelList;
}
public static T FillModel<T>(DataRow dr) where T : new ()
{
if (dr == null)
{
return default(T);
}
T model = new T();
var properties = typeof(T).GetProperties();
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
var propertyInfo = properties.FirstOrDefault(x => x.GetCustomAttribute<ModelFiledHelper>().DisplayName.Contains(dr.Table.Columns[i].ColumnName));
if (propertyInfo != null && dr[i] != DBNull.Value)
try
{
propertyInfo.SetValue(model, dr[i], null);
}
catch (Exception)
{
}
}
return model;
}
//这里使用c#的特性
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Common.Common
{
public class ModelFiledHelper : Attribute
{
public string[] DisplayName { get; private set; }
public ModelFiledHelper(params string[] displayName)
{
DisplayName = displayName;
}
//使用构造函数初始化赋值。
}
}
//在这里我们在实体中添加特性标识
public class Student()
{
[ModelFiledHelper("ID")]
public int ID{set;get;}
[ModelFiledHelper("Name")]
public string Name{get;set;}
[ModelFiledHelper("Age")]
public string Age{get;set;}
}
DataTable dt = new DataTable("Demo");//这里对应上边创建的datatable
List<Student> viewList = new List<Student>();//这里声明数组接收多条数据
if (dt != null && dt.Rows.Count > 0)
{
var models = TableHelpher.FillModels<Student>(dt);
models.ForEach(x => viewList.Add(x));
}
这种转换类型的方法能够在数据量多的时候不至于弄得混乱。但是相对于一些ORM框架来说,这种方法就显得微不足道了,但是大多数的ORM框架也都是采用反射这种方式的。总之只有在积累了非常多的知识才能明白大道至简的道理。