将 Datatable 转换为通用 IEnumerable<T>
Convert Datatable to generic IEnumerable<T>
我正在尝试从 DataTable
转换为 IEnumerable<T>
。但是我得到的是 IEnumerable<DataRow>
:
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandTimeout = int.MaxValue;
cmd.CommandText = sqlCommand;
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
tbl.Load(reader);
var res = tbl.AsEnumerable().ToList(); // IEnumerable<DataRow>:
}
}
我想做的是:
protected async Task<IEnumerable<T>> QuerySqlCmdReadRows<T>(string sqlCommand)
{
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandTimeout = int.MaxValue;
cmd.CommandText = sqlCommand;
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
tbl.Load(reader);
return tbl.AsEnumerable().ToList();
}
}
}
是否可以像我在 Entity Framework 中那样获得 IEnumerable<T>
?
var studentList = ctx.SqlQuery("Select * from Students")
.ToList<Student>();
您可以创建一个扩展方法来为您转换它。鉴于您的查询属性与通用 T
类型的属性相匹配,您可以使用反射来执行它!示例(见代码注释):
public static class DataTableExtensions
{
public static IEnumerable<T> ToGenericList<T>(this DataTable dataTable)
{
var properties = typeof(T).GetProperties().Where(x => x.CanWrite).ToList();
var result = new List<T>();
// loop on rows
foreach (DataRow row in dataTable.Rows)
{
// create an instance of T generic type.
var item = Activator.CreateInstance<T>();
// loop on properties and columns that matches properties
foreach (var prop in properties)
foreach (DataColumn column in dataTable.Columns)
if (prop.Name == column.ColumnName)
{
// Get the value from the datatable cell
object value = row[column.ColumnName];
// Set the value into the object
prop.SetValue(item, value);
break;
}
result.Add(item);
}
return result;
}
}
假设您有这样的模型:
public class Student
{
public int Id { get; set; }
public string Code { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// other possible properties
}
您可以像这样使用扩展方法:
protected async Task<IEnumerable<T>> QuerySqlCmdReadRows<T>(string sqlCommand)
{
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandText = sqlCommand;
DataTable dtResult = new DataTable();
using (var reader = await cmd.ExecuteReaderAsync())
dtResult.Load(reader);
return dtResult.ToGenericList<T>();
}
}
}
// just and sample
var students = QuerySqlCmdReadRows<Students>("select Id, Code, FirstName, LastName from Students");
这是我将 DataTable
转换为 IEnumerable<T>
的实现。它复制任何具有匹配 属性 或字段名称的列。
首先,一些扩展用于处理 MemberInfo
作为 PropertyInfo
或 FieldInfo
的父级:
public class MemberInfoExt {
public static bool GetCanWrite(this MemberInfo member) {
switch (member) {
case FieldInfo mfi:
return true;
case PropertyInfo mpi:
return mpi.CanWrite;
default:
throw new ArgumentException("MemberInfo must be if type FieldInfo or PropertyInfo", nameof(member));
}
}
public static void SetValue(this MemberInfo member, object destObject, object value) {
switch (member) {
case FieldInfo mfi:
mfi.SetValue(destObject, value);
break;
case PropertyInfo mpi:
mpi.SetValue(destObject, value);
break;
case MethodInfo mi:
mi.Invoke(destObject, new object[] { value });
break;
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo or MethodInfo", nameof(member));
}
}
}
利用这些,你可以写一个DataTable
扩展方法:
public class DataTableExt {
public static IEnumerable<T> ToIEnumerable<T>(this DataTable dt) where T : new() {
var props = typeof(T).GetPropertiesOrFields()
.Where(mi => dt.Columns.Contains(mi.Name) && mi.GetCanWrite())
.ToList();
foreach (var row in dt.AsEnumerable()) {
var aT = new T();
foreach (var p in props)
p.SetValue(aT, row[p.Name]);
yield return aT;
}
}
}
并使用它将 DataTable
转换为特定类型。
也可以将 DataTable
转换为 IEnumerable<anon>
,其中 anon
是一个匿名对象(或模拟),但它的价值值得怀疑,因为它需要创建一个匿名对象只能通过反射使用的运行时对象。
我正在尝试从 DataTable
转换为 IEnumerable<T>
。但是我得到的是 IEnumerable<DataRow>
:
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandTimeout = int.MaxValue;
cmd.CommandText = sqlCommand;
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
tbl.Load(reader);
var res = tbl.AsEnumerable().ToList(); // IEnumerable<DataRow>:
}
}
我想做的是:
protected async Task<IEnumerable<T>> QuerySqlCmdReadRows<T>(string sqlCommand)
{
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandTimeout = int.MaxValue;
cmd.CommandText = sqlCommand;
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
tbl.Load(reader);
return tbl.AsEnumerable().ToList();
}
}
}
是否可以像我在 Entity Framework 中那样获得 IEnumerable<T>
?
var studentList = ctx.SqlQuery("Select * from Students")
.ToList<Student>();
您可以创建一个扩展方法来为您转换它。鉴于您的查询属性与通用 T
类型的属性相匹配,您可以使用反射来执行它!示例(见代码注释):
public static class DataTableExtensions
{
public static IEnumerable<T> ToGenericList<T>(this DataTable dataTable)
{
var properties = typeof(T).GetProperties().Where(x => x.CanWrite).ToList();
var result = new List<T>();
// loop on rows
foreach (DataRow row in dataTable.Rows)
{
// create an instance of T generic type.
var item = Activator.CreateInstance<T>();
// loop on properties and columns that matches properties
foreach (var prop in properties)
foreach (DataColumn column in dataTable.Columns)
if (prop.Name == column.ColumnName)
{
// Get the value from the datatable cell
object value = row[column.ColumnName];
// Set the value into the object
prop.SetValue(item, value);
break;
}
result.Add(item);
}
return result;
}
}
假设您有这样的模型:
public class Student
{
public int Id { get; set; }
public string Code { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// other possible properties
}
您可以像这样使用扩展方法:
protected async Task<IEnumerable<T>> QuerySqlCmdReadRows<T>(string sqlCommand)
{
using (var con = new SqlConnection(Connection.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandText = sqlCommand;
DataTable dtResult = new DataTable();
using (var reader = await cmd.ExecuteReaderAsync())
dtResult.Load(reader);
return dtResult.ToGenericList<T>();
}
}
}
// just and sample
var students = QuerySqlCmdReadRows<Students>("select Id, Code, FirstName, LastName from Students");
这是我将 DataTable
转换为 IEnumerable<T>
的实现。它复制任何具有匹配 属性 或字段名称的列。
首先,一些扩展用于处理 MemberInfo
作为 PropertyInfo
或 FieldInfo
的父级:
public class MemberInfoExt {
public static bool GetCanWrite(this MemberInfo member) {
switch (member) {
case FieldInfo mfi:
return true;
case PropertyInfo mpi:
return mpi.CanWrite;
default:
throw new ArgumentException("MemberInfo must be if type FieldInfo or PropertyInfo", nameof(member));
}
}
public static void SetValue(this MemberInfo member, object destObject, object value) {
switch (member) {
case FieldInfo mfi:
mfi.SetValue(destObject, value);
break;
case PropertyInfo mpi:
mpi.SetValue(destObject, value);
break;
case MethodInfo mi:
mi.Invoke(destObject, new object[] { value });
break;
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo or MethodInfo", nameof(member));
}
}
}
利用这些,你可以写一个DataTable
扩展方法:
public class DataTableExt {
public static IEnumerable<T> ToIEnumerable<T>(this DataTable dt) where T : new() {
var props = typeof(T).GetPropertiesOrFields()
.Where(mi => dt.Columns.Contains(mi.Name) && mi.GetCanWrite())
.ToList();
foreach (var row in dt.AsEnumerable()) {
var aT = new T();
foreach (var p in props)
p.SetValue(aT, row[p.Name]);
yield return aT;
}
}
}
并使用它将 DataTable
转换为特定类型。
也可以将 DataTable
转换为 IEnumerable<anon>
,其中 anon
是一个匿名对象(或模拟),但它的价值值得怀疑,因为它需要创建一个匿名对象只能通过反射使用的运行时对象。