5

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.

Abdul Rehman Sayed
  • 6,532
  • 7
  • 45
  • 74
  • depends upon the column. #Abdul Rehman Sayed – Shahzad Khan Feb 24 '15 at 08:01
  • 2
    So what will be the use of this method? How'll you use that `List`? It will be no way useful AFAICS – Sriram Sakthivel Feb 24 '15 at 08:01
  • I need it to generate JSON for a wcf. (my wcf method returns List) which will be consumed both by .NET as well as non-dot net clients @SriramSakthivel – Abdul Rehman Sayed Feb 24 '15 at 08:03
  • Not sure why you need to return `List` though. If you can return a JSON string, you can [use this](http://stackoverflow.com/a/12063095/2530848). Then you can parse it to JSON object at other end using `Parse` method of serializer. – Sriram Sakthivel Feb 24 '15 at 08:05
  • @SriramSakthivel I'm using List becoz non-dotnet clients (Eg : html/ajax) will use json (wcf does this work for me if i provide List..) & dot net clients (win forms) will benefit by using the collection as a service reference proxy.. I want a generic version because i have around 25+ such methods & don't want repetition of the code. – Abdul Rehman Sayed Feb 24 '15 at 08:10

5 Answers5

9

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));
Parthasarathy
  • 2,698
  • 1
  • 12
  • 14
5

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);
Piyush
  • 830
  • 8
  • 19
1

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.

Rahul Singh
  • 21,585
  • 6
  • 41
  • 56
1

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));
1

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] })