简体   繁体   中英

Convert DataTable to LINQ Anonymous Type

I want a function which takes in a datatable & returns a List (object is not DataRow) Eg. :

I know I can do this (but this requires column names to be known) :

        // Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode

        List<object> rtn = new List<object>();

        var x = from vals in dt.Select()
                select new
                {
                    Code = vals["Code"],
                    Description = vals["Description"],
                    ShortCode = vals["ShortCode"],
                };
        rtn.AddRange(x)

        return  rtn;

What i want is a generic version so that i can pass in any datatable & it will generate based on column names in the datatable.

Since the property names are not known at compile time and you want to use the data for JSON serialization, you can use the following to create a list of dictionary. If you use Newtonsoft JSON, then the serialization takes care of converting the key value pairs in a JSON object format.

IEnumerable<Dictionary<string,object>> result = dt.Select().Select(x => x.ItemArray.Select((a, i) => new { Name = dt.Columns[i].ColumnName, Value = a })
                                                                                   .ToDictionary(a => a.Name, a => a.Value));

In order to dynamically create properties so as to treat different dataTables with different set of Columns, we can use the System.Dynamic.ExpandoObject . It basically implements, IDictionary <string,object>. The format, which can easily be converted to JSON.

        int colCount = dt.Columns.Count;
        foreach (DataRow dr in dt.Rows)
        {
            dynamic objExpando = new System.Dynamic.ExpandoObject();
            var obj = objExpando as IDictionary<string, object>;

            for (int i = 0; i < colCount; i++)
            {
                string key = dr.Table.Columns[i].ColumnName.ToString();
                string val = dr[key].ToString();

                obj[key] = val;
            }
            rtn.Add(obj);
        }         

        String json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(rtn);

You can use the following generic function:-

private static List<T> ConvertDataTable<T>(DataTable dt)  
{  
   List<T> data = newList<T>();  
   foreach (DataRowrow in dt.Rows)  
   {  
      Titem = GetItem<T>(row);  
      data.Add(item);  
   }  
   return data;  
}  

private static TGetItem<T>(DataRow dr)  
{  
   Type temp = typeof(T);  
   T obj =Activator.CreateInstance<T>();  
   foreach (DataColumncolumn in dr.Table.Columns)  
   {  
      foreach (PropertyInfopro in temp.GetProperties())  
      {  
         if (pro.Name == column.ColumnName)  
         pro.SetValue(obj,dr[column.ColumnName], null);  
         else  
         continue;  
      }  
   }  
   return obj;  
}  

Please check my article , which has complete demonstration on how to use this generic method.

Here is the original question:

// Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode



    List<object> rtn = new List<object>();

        var x = from vals in dt.Select()
                select new
                {
                    Code = vals["Code"],
                    Description = vals["Description"],
                    ShortCode = vals["ShortCode"],
                };
        rtn.AddRange(x)

        return  rtn;

Just replace with

List<object> rtn = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(dt));

You will have the provide the anonymous object as a parameter and use json/xml serialization:

protected static List<T> ToAnonymousCollection<T>(DataTable dt, T anonymousObject)
{
    List<DataColumn> dataColumns = dt.Columns.OfType<DataColumn>().ToList();

    return dt.Rows.OfType<DataRow>().Select(dr =>
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();

        dataColumns.Each(dc => dict.Add(dc.ColumnName, dr[dc]));

        return JsonConvert.DeserializeAnonymousType(JsonConvert.SerializeObject(dict), anonymousObject);
    }).ToList();
}

Usage:

var anonymousCollection = ToAnonymousCollection(dt, new { Code = [ColumnTypeValue, eg. 0], Description = [ColumnTypeValue, eg. string.Empty], ShortCode = Code=[ColumnTypeValue, eg. 0] })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM