我正在尝试从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>();
您可以创建一个扩展方法来为您转换它。假设查询中的属性与通用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;
}
}
您使用(我将其替换为使用async/await
功能:
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 = await cmd.ExecuteReaderAsync();
DataTable tbl = new DataTable();
tbl.Load(reader);
return tbl.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
是匿名对象(或模拟),但这具有可疑的价值,因为它需要在运行时创建匿名对象,该对象只能通过反射。