我正在尝试从DataTable
转换为IEnumberable<T>
。但是我得到的是IEnumberable<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(); // IEnumberable<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中一样获得IEnumberable?
var studentList = ctx.SqlQuery("Select * from Students")
.ToList<Student>();
答案 0 :(得分:2)
您可以创建一个扩展方法来为您转换它。假设查询中的属性与常规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");
答案 1 :(得分:2)
这是我将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
是一个匿名对象(或模拟),但这具有可疑的价值,因为它需要在以下位置创建一个匿名对象运行时,只能通过反射使用。