linq 如何将DataTable转换为类Object?

pftdvrlh  于 2023-03-15  发布在  其他
关注(0)|答案(6)|浏览(181)

我已经开发了一个应用程序,它在任何地方都返回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<Class1>
以便我可以返回服务堆栈中的对象并继续操作。

kcwpcxri

kcwpcxri1#

初始化数据表:

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();
rks48beu

rks48beu2#

Amit,我已经使用了一种方法来实现这一点,更少的编码和更有效的方式。
但它使用Linq。
我把它贴在这里,因为也许答案有助于其他SO。

下面的DAL代码将datatable对象转换为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]);                
    }

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

cgh8pdjw

cgh8pdjw3#

看着这个,我意识到:它是从一种对象到另一种对象;基本上我们是在做适当的反射。
有适当的方法来构造不同字段之间的关系,但给予类定义是做的,这可以很容易地由Newtonsoft. Json完成
进程:数据集/数据表(序列化)==〉Json(反序列化)==〉目标对象列表在本例中作为OP,只需执行以下操作:

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

现在DataTable被序列化为纯字符串。然后执行以下操作:

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

现在,您应该有了List,其中所有DataTable行都是单独的对象。

ego6inou

ego6inou4#

它是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
jhkqcmku

jhkqcmku5#

用json convert做这个是不是很贵?但是至少你有一个2行的解决方案和它的泛型。不管你的datatable包含的字段比object类多还是少:

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
j91ykkif

j91ykkif6#

到2023年,一个更简单,更少的代码

public class ClassName
{
   public int Id { get; set; }
   public String FirstName { get; set; }
   public String LastName { get; set; }
}

对于类对象List

DataTable dt = new DataTable();

var _objectList = JArray.FromObject(dt).ToObject<List<Venues>>();

对于类对象

DataTable dt = new DataTable();

var _object = JArray.FromObject(dt)[].ToObject<Venues>();

相关问题