簡體   English   中英

將數據表轉換為通用 IEnumerable<T>

[英]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作為PropertyInfoFieldInfo的父級處理的幾個擴展:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM