DataSet、DataTable与List<实体类>相互转换类:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Repast.General
{
class ModelHandler<T> where T : new()
{
#region (DataSet、DataTable)数据转换成实体类
/// <summary>
/// 填充对象列表:用DataSet的第一个表填充实体类
/// </summary>
/// <param name="ds">DataSet</param>
/// <returns></returns>
public List<T> FillModel(DataSet ds)
{
if (ds == null || ds.Tables[0] == null || ds.Tables[0].Rows.Count == 0)
{
return null;
}
else
{
return FillModel(ds.Tables[0]);
}
}
/// <summary>
/// 填充对象列表:用DataSet的第index个表填充实体类
/// </summary>
public List<T> FillModel(DataSet ds, int index)
{
if (ds == null || ds.Tables.Count <= index || ds.Tables[index].Rows.Count == 0)
{
return null;
}
else
{
return FillModel(ds.Tables[index]);
}
}
/// <summary>
/// 填充对象列表:用DataTable填充实体类
/// </summary>
public List<T> FillModel(DataTable dt)
{
if (dt == null || dt.Rows.Count == 0)
{
return null;
}
List<T> modelList = new List<T>();
foreach (DataRow dr in dt.Rows)
{
//T model = (T)Activator.CreateInstance(typeof(T));
T model = new T();
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
PropertyInfo propertyInfo = model.GetType().GetProperty(dr.Table.Columns[i].ColumnName);
if (propertyInfo != null && dr[i] != DBNull.Value)
{
Type Typeof = propertyInfo.PropertyType; //这里是获取实体类字段属性
propertyInfo.SetValue(model, Convert.ChangeType(dr[i], Typeof), null); //然后用 changetype方法进行转换,因为dr[i]获取到的都是string类型,需要进行转换
}
}
modelList.Add(model);
}
return modelList;
}
/// <summary>
/// 填充对象:用DataRow填充实体类
/// </summary>
public T FillModel(DataRow dr)
{
if (dr == null)
{
return default(T);
}
//T model = (T)Activator.CreateInstance(typeof(T));
T model = new T();
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
PropertyInfo propertyInfo = model.GetType().GetProperty(dr.Table.Columns[i].ColumnName);
if (propertyInfo != null && dr[i] != DBNull.Value)
propertyInfo.SetValue(model, dr[i], null);
}
return model;
}
#endregion
#region 实体类转换成数据(DataSet、DataTable)
/// <summary>
/// 实体类转换成DataSet
/// </summary>
/// <param name="modelList">实体类列表</param>
/// <returns></returns>
public DataSet FillDataSet(List<T> modelList)
{
if (modelList == null || modelList.Count == 0)
{
return null;
}
else
{
DataSet ds = new DataSet();
ds.Tables.Add(FillDataTable(modelList));
return ds;
}
}
/// <summary>
/// 实体类转换成DataTable
/// </summary>
/// <param name="modelList">实体类列表</param>
/// <returns></returns>
public DataTable FillDataTable(List<T> modelList)
{
if (modelList == null || modelList.Count == 0)
{
return null;
}
DataTable dt = CreateData(modelList[0]);
foreach (T model in modelList)
{
DataRow dataRow = dt.NewRow();
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
{
dataRow[propertyInfo.Name] = propertyInfo.GetValue(model, null);
}
dt.Rows.Add(dataRow);
}
return dt;
}
/// <summary>
/// 根据实体类得到表结构
/// </summary>
/// <param name="model">实体类</param>
/// <returns></returns>
private DataTable CreateData(T model)
{
DataTable dataTable = new DataTable(typeof(T).Name);
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
{
dataTable.Columns.Add(new DataColumn(propertyInfo.Name, propertyInfo.PropertyType));
}
return dataTable;
}
#endregion
}
}
//此代码转自http://blog.sina.com.cn/s/blog_722ced7c0100m5p6.html
调用实例:
//Menu表对应的实体字段
public int Id { get; set; }
public string Number { get; set; }
public string Name { get; set; }
public string CostPrice { get; set; }
public string SellPrice { get; set; }
public Nullable<int> StyleId { get; set; }
public int Status { get; set; }
public string Intro { get; set; }
public string Describe { get; set; }
public string Keywords { get; set; }
public Nullable<double> AverageGrade { get; set; }
public string Time { get; set; }
public Nullable<int> EmployeeId { get; set; }
public string MainImg { get; set; }
//执行sql语句并将结果集填充至DataSet
DataSet dataSet=GlobalFunAndVar.SqlDataAdapDS(sql);
//调用上面的将DataSet转换为List<Menu>实体集合
List<Menu> menus = menuModel.FillModel(dataSet);
正常来讲这段是没问题的可是当我运行项目的时候执行这段代码却报了类型转换的错:
Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=]]'。
经过进行断点得知是这句转换出的错:
在public List FillModel(DataTable dt)这个方法中的这句代码Convert.ChangeType(dr[i], Typeof), null)
大家可以看到我的这个表有几个字段的类型是比较特殊的,StyleId、AverageGrade 、EmployeeId这三个字段的类型都是Nullable<基本类型>。
Nullable类型作用:
值类型是没有null值的,比如int,DateTime,它们都有默认值。举个例子,在访问数据库时,会存在一定的问题,Person类有字段Age(int类型),Birthday(DateTime),如果没有给它们赋值,我们期望的是向数据库插入时,应该是null,而不是0和0001-01-01;同样从数据库取值时也是如此,如果数据值为null,我们也希望Age和Birthday的值能反应出来,如果不使用int?和DateTime?就做不到。
Nullable 类型(结构体)是System.Nullable<T> 这种结构体的实例,一个Nullable类型可以代表他的值类型的正确的范围,同时添加了为“空”的值。
这是因为我的数据库中给这几个字段设置的可为空值,所以C# Entity Framework在自动生成实体类的时候就会把基本类型可为空的字段设置成Nullable类型,所以在转换的时候就会出错。所以上面的转换代码如果不改进的话就报那样的错。解决办法就是在转换语句前加上:
if (Typeof.IsGenericType && Typeof.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
Typeof = Nullable.GetUnderlyingType(Typeof);
}
改进后的完整此方法代码为:
/// 填充对象列表:用DataTable填充实体类
/// </summary>
public List<T> FillModel(DataTable dt)
{
if (dt == null || dt.Rows.Count == 0)
{
return null;
}
List<T> modelList = new List<T>();
foreach (DataRow dr in dt.Rows)
{
//T model = (T)Activator.CreateInstance(typeof(T));
T model = new T();
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
PropertyInfo propertyInfo = model.GetType().GetProperty(dr.Table.Columns[i].ColumnName);
if (propertyInfo != null && dr[i] != DBNull.Value)
{
Type Typeof = propertyInfo.PropertyType; //这里是获取实体类字段属性
if (Typeof.IsGenericType && Typeof.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
Typeof = Nullable.GetUnderlyingType(Typeof);
}
propertyInfo.SetValue(model, Convert.ChangeType(dr[i], Typeof), null); //然后用 changetype方法进行转换,因为dr[i]获取到的都是string类型,需要进行转换
}
}
modelList.Add(model);
}
return modelList;
}
这时候再运行就不会报错了