【问题标题】:Convert DataTable to List<T> where Class of List is Dynamic将 DataTable 转换为 List<T>,其中 List 的类是动态的
【发布时间】:2014-01-17 05:12:21
【问题描述】:

我正在从 C# 代码执行存储过程

private void DataToGrid()
{
    DataTable dt = new DataTable();
    string[,] aryPara = new string[,] 
    {{ "@pClassId", "10" } ,
    { "@pMediumId", "11" } ,
    { "@pStreamId", "12" } ,
    { "@pSessionId","13" } ,
    { "@pSectionId", "15" } ,
    { "@pShiftId", "16" } ,
    { "@pDateId", "17" } };

    dt = CallStoredProcedureUsingAdapterFillDataTabel("ssspAtdDailyattendance", aryPara);  
    DatagridView1.DataSource = dt;
}

public DataTable CallStoredProcedureUsingAdapterFillDataTabel(string StoredProcedureName, [Optional] string[,] aryParameters)
{
    SqlConnection con = new SqlConnection();
    con.ConnectionString = "Data Source=AIS-OCTACORE\SQLserver2008r2;Initial Catalog= SchoolSoulDataTest; integrated security=SSPI";
    con.open();
    SqlCommand lSQLCmd = new SqlCommand();
    SqlDataAdapter adp = new SqlDataAdapter();
    DataTable dt = new DataTable();
    lSQLCmd.CommandType = CommandType.StoredProcedure;
    lSQLCmd.CommandText = StoredProcedureName;
    lSQLCmd.CommandTimeout = 300;
    try
    {
        for (int i = 0; i < aryParameters.GetLength(0); i++)
        {
            lSQLCmd.Parameters.Add(new SqlParameter(aryParameters[i, 0], aryParameters[i, 1]));
        }
    }
    catch (Exception ex)
    {

    }
    lSQLCmd.Connection = con;
    adp.SelectCommand = lSQLCmd;
    adp.Fill(dt);
    clsConnectionClose();
    return dt;
}

其中ssspAtdDailyattendance 是一个动态存储过程,其中存储过程返回的数据具有可变数量的列。

现在我想将 DataTable dt 转换为 List&lt;T&gt; 但由于 dt 返回可变数量的列,因此 T 的类型不是固定的

所以我的问题是如何将dt 转换为List

【问题讨论】:

    标签: c# list datatable


    【解决方案1】:

    我建议您使用 Dapper,而不是自己编写和维护样板代码。 Dapper 支持 dynamic 对象。

    执行查询并将其映射到动态对象列表

    public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, 
    object param = null, SqlTransaction transaction = null, bool buffered = true)
    

    此方法将执行 SQL 并返回一个动态列表。

    示例用法:

    var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
    
    ((int)rows[0].A).IsEqualTo(1);    
    ((int)rows[0].B).IsEqualTo(2);    
    ((int)rows[1].A).IsEqualTo(3);   
    ((int)rows[1].B).IsEqualTo(4);
    

    网址:http://code.google.com/p/dapper-dot-net/

    NuGet:http://www.nuget.org/packages/Dapper/

    【讨论】:

    • 我不明白我这样做有多愚蠢,你能简单地写下你的代码
    • 只需使用 Dapper 执行您的存储过程,而不是自己直接使用 SqlCommand
    【解决方案2】:

    如果我理解你的问题,T 可以不止一种类型。

    例如,第一行可能是人,第二行是狗?或者您的意思是不同的类型,如字符串、整数、日期等(值类型)。

    无论如何,您都需要创建“T”实体来表示数据表中的数据并对其进行映射。

    您正在寻找的可能是一个映射器,例如 ValueInjector 或 Automapper。

    甚至map manually:

    This answer 这里展示了如何使用ValueInjector 将 DataTable 映射到类。它可以给你一个先机。

    我希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      @Douglas Jimenez 有一个相关问题。如果只有type 变化,这可以通过公共字段(或对象,如果没有公共字段)的接口和实现其他字段的不同类型轻松解决。构建列表时,您可以使用工厂来决定为行(或整个 DataTable)构建哪种类型,然后使用该行构建对象。

      但是,如果在编译时不知道类型,有很多解决方法:

      • 将 DLR 与 dynamic 关键字一起使用。
        • ExpandoObject 可以满足您的需求。
      • 使用哈希图(如Dictionary&lt;string, object&gt;
      • 使用Emit 框架发出类型。
        • 这个解决方案实际上很复杂,将引导您了解 CLR 的高级部分。不过,这确实很有效。
        • 如果你选择这条路,这个tutorial会对你有很大帮助。
        • 这对于您的需求可能矫枉过正

      可能还有其他解决方案。祝您选择的解决方案好运。

      【讨论】:

        【解决方案4】:

        根据sll 发布的答案,您可以使用类似,

        IList<Class1> items = dt.AsEnumerable().Select(row => 
            new Class1
                {
                    id = row.Field<string>("id"),
                    name = row.Field<string>("name")
                }).ToList();
        

        但由于您要求它可能包含不同的列,因此您可以拥有一个包含所有属性的通用类,并在获取列之前进行检查,

        public class Class1
        {
            private int id;
            public string name;
        
            public Class1(DataRow row)
            {
                id = (int)GetColumnValue(row, "id");
                name = (string)GetColumnValue(row, "name");
            }
        
            public object GetColumnValue(DataRow row, string column)
            {
                return row.Table.Columns.Contains(column) ? row[column] : null;
            }
        }
        

        然后你可以调用函数,

        IList<Class1> items = dt.AsEnumerable().Select(row => new Class1(row)).ToList();
        

        【讨论】:

          【解决方案5】:

          我遇到了这个问题,并使用了来自

          的代码

          http://musthaan.com/2016/01/18/datatable-to-dynamic-list/

          public static class HelperExtensions
          {
            public static List<dynamic> ToDynamic(this DataTable dt)
            {
              var dynamicDt = new List<dynamic>();
              foreach (DataRow row in dt.Rows)
              {
                dynamic dyn = new ExpandoObject();
                dynamicDt.Add(dyn);
                foreach (DataColumn column in dt.Columns)
                {
                   var dic = (IDictionary<string, object>)dyn;
                   dic[column.ColumnName] = row[column];
                }
              }
              return dynamicDt;
            }
          }
          

          【讨论】:

            猜你喜欢
            • 2011-01-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多