[英]Convert Datatable to generic IEnumerable<T>
我正在嘗試從DataTable
轉換為IEnumberable<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
是匿名對象(或模擬),但這是有問題的價值,因為它需要在運行時創建一個只能通過反射使用的匿名對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.