目录
前言
最近在捣鼓DataTable,弄到了类型转换,既然弄了,那就整个记录。有不足之处,请多多指教。我看了一下目前的转换方式基本上都大差不差,基本上都是通过反射来操作的。本文介绍的两种方式也都是利用反射来完成的。两种方式都写成的通用类,仅供参考。
想法
两者的区别
- DataTable 内存中的数据表 一个二维表
- List<model>泛型数组 这里面存放的是一个一个的被对象化的数据模型
个人想法
- 其实也可以写一个类,把DataTable转换成 List<Dictionary<string, object>>(),但是并不太建议,我感觉也不太方便。
- 我比较推荐利用反射来弄,相对通用。
- 以下方法中的T为自己定义的类,其中的属性需要与数据库对应
完整代码
-
方式一
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
namespace GCT.TestInterface
{
public static class DataTableHelper
{
/// <summary>
/// DataTable转成List
/// </summary>
public static List<T> ToDataList<T>(this DataTable dt)
{
var list = new List<T>();
//创建一个属性的列表,并赋值
var plist = new List<PropertyInfo>(typeof(T).GetProperties());
if (dt == null || dt.Rows.Count == 0)
{
return null;
}
foreach (DataRow item in dt.Rows)
{
//实例化泛型对象
T s = Activator.CreateInstance<T>();
//遍历dataTable中的列集合
for (int i = 0; i < dt.Columns.Count; i++)
{
//获取属性和DataTable的列名称相同的属性(PropertyInfo)
PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
//判断是否存在
if (info != null)
{
try
{
//判断是否为空
if (!Convert.IsDBNull(item[i]))
{
object v = null;
//判断属性是否包含可空
if (info.PropertyType.ToString().Contains("System.Nullable"))
{
//类型转换
v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType));
}
else
{
//类型转换
v = Convert.ChangeType(item[i], info.PropertyType);
}
//赋值
info.SetValue(s, v, null);
}
}
catch (Exception ex)
{
throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
}
}
}
list.Add(s);
}
return list;
}
/// <summary>
/// DataTable转成实体对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
public static T ToDataEntity<T>(this DataTable dt)
{
T s = Activator.CreateInstance<T>();
if (dt == null || dt.Rows.Count == 0)
{
return default(T);
}
var plist = new List<PropertyInfo>(typeof(T).GetProperties());
for (int i = 0; i < dt.Columns.Count; i++)
{
PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
if (info != null)
{
try
{
if (!Convert.IsDBNull(dt.Rows[0][i]))
{
object v = null;
if (info.PropertyType.ToString().Contains("System.Nullable"))
{
v = Convert.ChangeType(dt.Rows[0][i], Nullable.GetUnderlyingType(info.PropertyType));
}
else
{
v = Convert.ChangeType(dt.Rows[0][i], info.PropertyType);
}
info.SetValue(s, v, null);
}
}
catch (Exception ex)
{
throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
}
}
}
return s;
}
/// <summary>
/// List转成DataTable
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="entities">实体集合</param>
public static DataTable ToDataTable<T>(List<T> entities)
{
//判断List的状态
if (entities == null || entities.Count == 0)
{
return null;
}
//新建一个DataTable
var result = new DataTable();
//获取实体类型数据
var type = typeof(T);
//遍历实体类型数据
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
//获取属性类型
var propertyType = property.PropertyType;
//判断是否存在,是否可为空
if (propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
propertyType = propertyType.GetGenericArguments()[0];
}
//添加列
result.Columns.Add(property.Name, propertyType);
}
foreach (var entity in entities)
{
//创建一个具有相同架构的表格行
DataRow row = result.NewRow();
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
//填充数据
row[property.Name] = property.GetValue(entity) ?? DBNull.Value;
}
//添加行
result.Rows.Add(row);
}
return result;
}
}
}
-
方式二
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
namespace GCT.TestInterface
{
public static class DataTableHelper
{
/// <summary>
/// 利用反射将Datatable转换为List<T>对象
/// </summary>
/// <typeparam name="T">集合</typeparam>
/// <param name="dt"> datatable对象</param>
/// <returns></returns>
public static List<T> ToDataList<T>(this DataTable dt) where T : new()
{
//定义集合
List<T> ts = new List<T>();
//遍历dataTable中的数据行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
//这里也有两种写法,可以先获取模型的属性数组,也先遍历再获取指定值的属性,看自己喜好采用
#region 获得此模型的公共属性
////获得此模型的公共属性
PropertyInfo[] propertys = t.GetType().GetProperties();
//遍历该对象的所有属性
foreach (PropertyInfo pi in propertys)
{
string tempName = pi.Name;
//检查datatable是否包含此列(列名==对象的属性名)
//判断此属性是否有setter,这个啥意思呢,就是我们的实体层的{get;set;}如果我们的实体有了set方法,就说明可以赋值!
if (!dt.Columns.Contains(tempName) && !pi.CanWrite) continue;
object value = dr[tempName];//取值
if (value == DBNull.Value) continue; //如果非空,则赋给对象的属性
pi.SetValue(t, ConvertHelper.HackType(value, pi.PropertyType), null);
}
#endregion
#region 先遍历再获取指定的
//遍历dataTable列集合
foreach (var c in dt.Columns)
{
//读取值
object value = dr[c.ToString()];
//判断是否存在
if (value != DBNull.Value)
{
//获取指定值的属性
var p = t.GetType().GetProperty(c.ToString());
if (p != null)
{
//对象赋值
p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
}
}
}
#endregion
//对象添加到泛型集合中
ts.Add(t);
}
return ts;
}
/// <summary>
/// DataTable转成实体对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static T ToDataEntity<T>(this DataTable dt) where T : new()
{
if (dt.Rows.Count > 1)
{
throw new Exception("");
}
//遍历行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
//遍历列
foreach (var c in dt.Columns)
{
//获取指定值
object value = dr[c.ToString()];
if (value != DBNull.Value)
{
//获取公共属性
var p = t.GetType().GetProperty(c.ToString());
if (p != null)
{
p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
}
}
}
return t;
}
return default(T);
}
}
}
-
类型转换
用方式二有时候会报类型转换的错误,因此也提供了两种转换方式
/// <summary>
/// 类型转换
/// </summary>
public static class ConvertHelper
{
#region 方式一
public static object HackType(object value, Type conversionType)
{
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
return null;
System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
conversionType = nullableConverter.UnderlyingType;
}
return Convert.ChangeType(value, conversionType);
}
#endregion 方式一
#region 方式二
public static object ChangeType(object obj, Type conversionType)
{
return ChangeType(obj, conversionType, System.Threading.Thread.CurrentThread.CurrentCulture);
}
public static object ChangeType(object obj, Type conversionType, IFormatProvider provider)
{
#region Nullable
Type nullableType = Nullable.GetUnderlyingType(conversionType);
if (nullableType != null)
{
if (obj == null)
{
return null;
}
return Convert.ChangeType(obj, nullableType, provider);
}
#endregion Nullable
if (typeof(Enum).IsAssignableFrom(conversionType))
{
return Enum.Parse(conversionType, obj.ToString());
}
return Convert.ChangeType(obj, conversionType, provider);
}
#endregion 方式二
}