【问题标题】:How to convert DataTable to class Object?如何将 DataTable 转换为类 Object?
【发布时间】:2011-12-21 22:39:52
【问题描述】:

我已经开发了一个应用程序,它在任何地方都返回DataTable

现在我的客户想要转换(使用服务堆栈的某些部分),所以我需要在我的应用程序中返回 DTO (objects)

我不想更改我现有的存储过程,甚至不想尽可能多地使用 LINQ(我不太了解 LINQ)。

对于小功能,我可以使用 Linq 没问题。

我的问题是:如何将我的DataTable 更改为该类的对象?

示例代码如下:

string s = DateTime.Now.ToString();
DataTable dt = new DataTable();

dt.Columns.Add("id");
dt.Columns.Add("name");

for (int i = 0; i < 5000000; i++)
{
    DataRow dr = dt.NewRow();
    dr["id"] = i.ToString();
    dr["name"] = "name" + i.ToString();
    dt.Rows.Add(dr);

    dt.AcceptChanges();
}

List<Class1> clslist = new List<Class1>();

for (int i = 0; i < dt.Rows.Count; i++)
{
    Class1 cls = new Class1();
    cls.id = dt.Rows[i]["id"].ToString();
    cls.name = dt.Rows[i]["name"].ToString();
    clslist.Add(cls);
}

Response.Write(s);
Response.Write("<br>");
Response.Write(DateTime.Now.ToString());

我知道,以上方法比较耗时,我正在尝试寻找替代解决方案。

是否有任何替代方法(我猜是 LINQ to DataTable)直接将表的行转换为List&lt;Class1&gt;

这样我就可以在我的服务堆栈中返回对象并继续。

【问题讨论】:

  • 只是想补充一点,您在上面为从 DataTable 填充类所做的工作并不慢,事实上,只要我们有 DataTable 可以使用,linq 或其他任何东西都不会它更快,它可能会给你一个更简单的代码,它不会要求你编写一个循环而是实现它自己。

标签: c# asp.net .net linq datatable


【解决方案1】:

看着这个并意识到:它是从一种类型的对象到另一种类型的对象;基本上我们正在尝试进行适当的反思。

有适当的方法来构造不同字段之间的关系但是给类定义完成,可以通过Newtonsoft.Json轻松完成

进程:DataSet/DataTable(序列化)==> Json(反序列化)==> 目标对象列表 在这个作为 OP 的示例中,只需执行以下操作:

string serializeddt = JsonConvert.SerializeObject(dt, Formatting.Indented);

现在 DataTable 被序列化为纯字符串。 然后这样做:

List<Class1> clslist = JsonConvert.DeserializeObject<List<Class1>>(serialized, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

现在您应该拥有包含所有 DataTable 行的列表作为单独的对象。

【讨论】:

    【解决方案2】:

    通过 json convert 做这个是不是很贵?但至少您有一个 2 线解决方案及其通用解决方案。如果您的数据表包含比对象类更多或更少的字段,则无关紧要:

    Dim sSql = $"SELECT '{jobID}' AS ConfigNo, 'MainSettings' AS ParamName, VarNm AS ParamFieldName, 1 AS ParamSetId, Val1 AS ParamValue FROM StrSVar WHERE NmSp = '{sAppName} Params {jobID}'"
                Dim dtParameters As DataTable = DBLib.GetDatabaseData(sSql)
    
                Dim paramListObject As New List(Of ParameterListModel)()
    
                If (Not dtParameters Is Nothing And dtParameters.Rows.Count > 0) Then
                    Dim json = Newtonsoft.Json.JsonConvert.SerializeObject(dtParameters).ToString()
    
                    paramListObject = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of ParameterListModel))(json)
                End If
    

    【讨论】:

      【解决方案3】:

      是Vb.Net版本:

      Public Class Test
      Public Property id As Integer
      Public Property name As String
      Public Property address As String
      Public Property createdDate As Date
      

      结束类

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
      
          Dim x As Date = Now
      
          Debug.WriteLine("Begin: " & DateDiff(DateInterval.Second, x, Now) & "-" & Now)
      
          Dim dt As New DataTable
          dt.Columns.Add("id")
          dt.Columns.Add("name")
          dt.Columns.Add("address")
          dt.Columns.Add("createdDate")
      
          For i As Integer = 0 To 100000
              dt.Rows.Add(i, "name - " & i, "address - " & i, DateAdd(DateInterval.Second, i, Now))
          Next
      
          Debug.WriteLine("Datatable created: " & DateDiff(DateInterval.Second, x, Now) & "-" & Now)
      
      
          Dim items As IList(Of Test) = dt.AsEnumerable().[Select](Function(row) New _
                  Test With {
                              .id = row.Field(Of String)("id"),
                              .name = row.Field(Of String)("name"),
                              .address = row.Field(Of String)("address"),
                              .createdDate = row.Field(Of String)("createdDate")
                             }).ToList()
      
          Debug.WriteLine("List created: " & DateDiff(DateInterval.Second, x, Now) & "-" & Now)
      
          Debug.WriteLine("Complated")
      
      End Sub
      

      【讨论】:

        【解决方案4】:

        阿米特,我使用了一种方法来实现这一点,代码更少,效率更高。

        但它使用 Linq。

        我在这里发布它是因为也许答案可以帮助其他 SO。

        下面的 DAL 代码将数据表对象转换为 YourViewModel 列表,很容易理解。

        public static class DAL
        {
                public static string connectionString = ConfigurationManager.ConnectionStrings["YourWebConfigConnection"].ConnectionString;
        
                // function that creates a list of an object from the given data table
                public static List<T> CreateListFromTable<T>(DataTable tbl) where T : new()
                {
                    // define return list
                    List<T> lst = new List<T>();
        
                    // go through each row
                    foreach (DataRow r in tbl.Rows)
                    {
                        // add to the list
                        lst.Add(CreateItemFromRow<T>(r));
                    }
        
                    // return the list
                    return lst;
                }
        
                // function that creates an object from the given data row
                public static T CreateItemFromRow<T>(DataRow row) where T : new()
                {
                    // create a new object
                    T item = new T();
        
                    // set the item
                    SetItemFromRow(item, row);
        
                    // return 
                    return item;
                }
        
                public static void SetItemFromRow<T>(T item, DataRow row) where T : new()
                {
                    // go through each column
                    foreach (DataColumn c in row.Table.Columns)
                    {
                        // find the property for the column
                        PropertyInfo p = item.GetType().GetProperty(c.ColumnName);
        
                        // if exists, set the value
                        if (p != null && row[c] != DBNull.Value)
                        {
                            p.SetValue(item, row[c], null);
                        }
                    }
                }
        
                //call stored procedure to get data.
                public static DataSet GetRecordWithExtendedTimeOut(string SPName, params SqlParameter[] SqlPrms)
                {
                    DataSet ds = new DataSet();
                    SqlCommand cmd = new SqlCommand();
                    SqlDataAdapter da = new SqlDataAdapter();
                    SqlConnection con = new SqlConnection(connectionString);
        
                    try
                    {
                        cmd = new SqlCommand(SPName, con);
                        cmd.Parameters.AddRange(SqlPrms);
                        cmd.CommandTimeout = 240;
                        cmd.CommandType = CommandType.StoredProcedure;
                        da.SelectCommand = cmd;
                        da.Fill(ds);
                    }
                    catch (Exception ex)
                    {
                       return ex;
                    }
        
                    return ds;
                }
        }
        

        现在,传递和调用方法的方法如下。

            DataSet ds = DAL.GetRecordWithExtendedTimeOut("ProcedureName");
        
            List<YourViewModel> model = new List<YourViewModel>();
        
            if (ds != null)
            {
                //Pass datatable from dataset to our DAL Method.
                model = DAL.CreateListFromTable<YourViewModel>(ds.Tables[0]);                
            }      
        

        到目前为止,对于我的许多应用程序,我发现这是获取数据的最佳结构

        【讨论】:

        • 这不起作用。 dotnetfiddle.net/x5dtGA 还应该注意反射非常慢,不应该用于性能关键的代码。
        • @Almenon 如果您为数据表的列设置数据类型,它将起作用。关于性能问题,它是动态映射,因为我使用了反射,它会有点慢,但不会慢到你甚至不能用于映射。
        【解决方案5】:

        初始化数据表:

        DataTable dt = new DataTable(); 
        dt.Columns.Add("id", typeof(String)); 
        dt.Columns.Add("name", typeof(String)); 
        for (int i = 0; i < 5; i++)
        {
            string index = i.ToString();
            dt.Rows.Add(new object[] { index, "name" + index });
        }
        

        查询本身:

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

        【讨论】:

        • 对于我来说,我只需要将 IList 更改为 List,所以它会返回一个类的集合,在你的情况下它只是接口,没有区别。非常感谢
        • 不错,但是如果有一个类与 DB 中的字段名称相同,但我有 100 多个字段,是否有任何例程可以自动从类中选择字段并填充它?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 2016-10-19
        • 2012-06-03
        • 1970-01-01
        • 2016-08-15
        • 2017-04-07
        相关资源
        最近更新 更多