将数据表转换为通用IEnumerable

问题描述 投票:0回答:2

我正在尝试从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>();
c# generics datatable ado.net sqlcommand
2个回答
0
投票

您可以创建一个扩展方法来为您转换它。假设查询中的属性与通用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");

0
投票

这是我将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是匿名对象(或模拟),但这具有可疑的价值,因为它需要在运行时创建匿名对象,该对象只能通过反射。

© www.soinside.com 2019 - 2024. All rights reserved.