在机房重构的时候,我们经常会把DataTable表中的数据转成泛型。可能我们个人开发的时候觉得没有必要,可是当我们合作开发的时候 ,由于前端并不知道后端的SQL语句怎么写的,所以也不知道数据表中的内容是什么,前端知道的只是一个方法名。所以这时候,把数据从后端传到前端之前,先把后端获得的数据表先转成泛型,就比较方便了。
可是,代码具体怎么写呢?
1. 首先就是在命名空间中先引用 System.Reflection 命名空间,因为利用反射可以获取实体对象的属性。
2. 接下来就是具体的代码。
//where T : new() 是对T的一种类型约束,此约束规定T必须具有无参构造函数
public static List<T> ConvertToList<T>(DataTable dt) where T : new()
{
//定义一个list集合
List<T> list = new List<T>();
//定义一个临时变量,用来存储属性名
string tempName = string.Empty;
//实例化一个对象
T t = new T();
//获得T的所有属性
PropertyInfo[] propertyInfos = t.GetType().GetProperties();
foreach (DataRow dr in dt.Rows)
{
foreach (PropertyInfo pi in propertyInfos)
{
//将属性名赋给临时变量
tempName = pi.Name;
//如果表的列名包含属性名
if (dt.Columns.Contains(tempName))
{
//如果此属性不可写(有无setter),则跳过检查下一个属性
if (!pi.CanWrite) continue;
//获得表中的字段值
object value = dr[tempName];
//如果表中非空,则赋给属性值
if (value != DBNull.Value)
{
pi.SetValue(t, value, null);
}
}
}
list.Add(t);
}
return list;
}
但是由于类中方法的参数都是实体对象,所以在类之间传递数据都是通过实体来传递的。有时候我们需要把DataTable表中的数据转成相应的对象,再传给下一个方法。那怎么办呢?在DAL层中将表中的数据项挨个转换成实体相对应的属性?可以是可以,但是如果数据字段太多的话,那就太麻烦了。所以我们可以借鉴上面的代码,只把方法的返回类型改成 T 就可以了。
public static T ConvertToEntity<T>(DataTable dt) where T : new()
{
//定义一个变量,用来接收属性名
string tempType = string.Empty;
T t = new T();
//获得T的所有属性
PropertyInfo[] propertyInfos = t.GetType().GetProperties();
foreach (DataRow dr in dt.Rows)
{
foreach (PropertyInfo pi in propertyInfos)
{
//将属性名赋值给临时变量
tempType = pi.Name;
//如果表的列名不包含此属性,则跳过检查下一条属性
if (!dt.Columns.Contains(tempType)) continue;
//如果此属性可写
if (pi.CanWrite)
{
object value = dr[tempType];
//如果表中的字段值不为空,则赋值
if (value != DBNull.Value)
{
pi.SetValue(t, value, null);
}
}
}
}
return t;
}
下面举一个例子,比如要获取 BasicDataInfoInfo 表中的一条数据。
public BasicdataInfo SelectBasicdataInfo()
{
//实例化D层
IDAL.IBasicdataInfoDAL basicdataInfoDAL = Factory.Factory.CreateBasicdataInfoDAL();
//获取BasicdataInfo的信息
DataTable dt = basicdataInfoDAL.SelectBasicdataInfo();
//将表转成相应的实体
BasicdataInfo basicdataInfo = CommonMethodBLL.ConvertToEntity<BasicdataInfo>(dt);
return basicdataInfo;
}