2011-10-17 10 views
14

Jak przekonwertować DataTable w IEnumerable<dynamicObject>?Jak przekonwertować DataTable na obiekt Dynamic?

Na przykład chcę przekonwertować żadnegoDataTable

ID | Name   DI | emaN 
--------- or --------- 
1 | x    2 | x 
2 | y    1 | y 

W liście obiektów

// list 1  (ex 1)    // list 2 (ex 2) 
{         { 
    { ID = 1, Name = "x" }   { DI = 2, emaN = "x" } 
    { ID = 2, Name = "y" }   { DI = 1, emaN = "y" } 
}         } 

Więc

list1.First().ID // 1 
list2.First().emaN // "x" 

Jak mogę to zrobić?

Odpowiedz

23

Jak o ze DynamicObject:

public static class DataTableX 
{ 
    public static IEnumerable<dynamic> AsDynamicEnumerable(this DataTable table) 
    { 
     // Validate argument here.. 

     return table.AsEnumerable().Select(row => new DynamicRow(row)); 
    } 

    private sealed class DynamicRow : DynamicObject 
    { 
     private readonly DataRow _row; 

     internal DynamicRow(DataRow row) { _row = row; } 

     // Interprets a member-access as an indexer-access on the 
     // contained DataRow. 
     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      var retVal = _row.Table.Columns.Contains(binder.Name); 
      result = retVal ? _row[binder.Name] : null; 
      return retVal; 
     } 
    } 
} 

Można też spróbować nadrzędnymi TrySetMember jeśli chcesz, aby wiersz dynamiczny był zapisywalny.

Wykorzystanie:

DataTable table = ... 
    var dynamicTable = table.AsDynamicEnumerable(); 

    var firstRowsNameField = dynamicTable.First().Name; 
+1

Najlepsze rozwiązanie. Wspaniały. –

+3

Cztery lata później, wciąż wspaniała odpowiedź! – code4life

1

spróbować

var MyResult = from x in MyDataTable select new { ID = x["ID"], Name = x["Name"] }.ToList(); 
+0

Mam na myśli coś bardziej ogólnego. – BrunoLM

+0

masz na myśli - bez znajomości pól? – Yahia

+0

Tak, dokładnie. Nowe pola mogą pojawiać się lub znikać, lub mogą to być zupełnie inne pola ..... – BrunoLM

2

Istnieje kilka ORMs, które można odczytać bezpośrednio z DB do dynamic ExpandoObject. Na przykład petapoco (i przeczytać tutaj example)

Albo można spróbować coś podobnego:

var dt = new DataTable(); 

var dns = new List<dynamic>(); 

foreach (var item in dt.AsEnumerable()) 
{ 
    // Expando objects are IDictionary<string, object> 
    IDictionary<string, object> dn = new ExpandoObject(); 

    foreach (var column in dt.Columns.Cast<DataColumn>()) 
    { 
     dn[column.ColumnName] = item[column]; 
    } 

    dns.Add(dn); 
} 

// Now you can do something like dns[0].MyColumnName 
// or recast to IDictionary<string, object> and do 
// something like casted["MyColumnName"] 
+0

nie można zastosować indeksowania z [] do ExpandoObject, zamień kod na istniejący tutaj http://stackoverflow.com/a/7794962/84216 –

+0

@AmrBadawy Corrected – xanatos

23
class Program 
{ 
    static void Main() 
    { 
     var dt = new DataTable(); 
     dt.Columns.Add("ID", typeof(int)); 
     dt.Columns.Add("Name", typeof(string)); 
     dt.Rows.Add(1, "x"); 
     dt.Rows.Add(2, "y"); 

     List<dynamic> dynamicDt = dt.ToDynamic(); 
     Console.WriteLine(dynamicDt.First().ID); 
     Console.WriteLine(dynamicDt.First().Name); 
    } 
} 

public static class DataTableExtensions 
{ 
    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; 
    } 
} 
+5

Jest mały wielki błąd człowieka! Linia 'dynamicDt.Add (dyn);' Powinna znajdować się poza wewnętrzną pętlą. –

+0

To rozwiązanie działało idealnie dla mnie, ponieważ chcę tylko powiązać datagrid z datatable. – kinnu

0

Konwersja DataTable do widoku listy

#region "Convert DataTable to List<dynamic>" 

    public List<dynamic> ToDynamicList(DataTable dt) 
    { 
     List<string> cols = (dt.Columns.Cast<DataColumn>()).Select(column => column.ColumnName).ToList(); 
     return ToDynamicList(ToDictionary(dt), getNewObject(cols)); 
    } 
    public List<Dictionary<string, object>> ToDictionary(DataTable dt) 
    { 
     var columns = dt.Columns.Cast<DataColumn>(); 
     var Temp = dt.AsEnumerable().Select(dataRow => columns.Select(column => 
          new { Column = column.ColumnName, Value = dataRow[column] }) 
         .ToDictionary(data => data.Column, data => data.Value)).ToList(); 
     return Temp.ToList(); 
    } 
    public List<dynamic> ToDynamicList(List<Dictionary<string, object>> list, Type TypeObj) 
    { 
     dynamic temp = new List<dynamic>(); 
     foreach (Dictionary<string, object> step in list) 
     { 
      object Obj = Activator.CreateInstance(TypeObj); 
      PropertyInfo[] properties = Obj.GetType().GetProperties(); 
      Dictionary<string, object> DictList = (Dictionary<string, object>)step; 
      foreach (KeyValuePair<string, object> keyValuePair in DictList) 
      { 
       foreach (PropertyInfo property in properties) 
       { 
        if (property.Name == keyValuePair.Key) 
        { 
         property.SetValue(Obj, keyValuePair.Value.ToString(), null); 
         break; 
        } 
       } 
      } 
      temp.Add(Obj); 
     } 
     return temp; 
    }  
    private Type getNewObject(List<string> list) 
    { 
     AssemblyName assemblyName = new AssemblyName(); 
     assemblyName.Name = "tmpAssembly"; 
     AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule"); 
     TypeBuilder typeBuilder = module.DefineType("WebgridRowCellCollection", TypeAttributes.Public); 
     foreach (string step in list) 
     { 
      string propertyName = step; 
      FieldBuilder field = typeBuilder.DefineField(propertyName, typeof(string), FieldAttributes.Public); 
      PropertyBuilder property = typeBuilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, typeof(string), new Type[] { typeof(string) }); 
      MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig; 
      MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, typeof(string), Type.EmptyTypes); 
      ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator(); 
      currGetIL.Emit(OpCodes.Ldarg_0); 
      currGetIL.Emit(OpCodes.Ldfld, field); 
      currGetIL.Emit(OpCodes.Ret); 
      MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, null, new Type[] { typeof(string) }); 
      ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator(); 
      currSetIL.Emit(OpCodes.Ldarg_0); 
      currSetIL.Emit(OpCodes.Ldarg_1); 
      currSetIL.Emit(OpCodes.Stfld, field); 
      currSetIL.Emit(OpCodes.Ret); 
      property.SetGetMethod(currGetPropMthdBldr); 
      property.SetSetMethod(currSetPropMthdBldr); 
     } 
     Type obj = typeBuilder.CreateType(); 
     return obj; 
    } 

    #endregion 
4

Poprzednia kody suneelsarraf tylko generowane Runtime dynamiczny obiekt z nieruchomości jako ciąg. Następująca aktualizacja wygeneruje każdą właściwość w oparciu o typ danych kolumny DataTable.

public static class DataTableExtension 
{ 
    /// <summary> 
    /// Convert a database data table to a runtime dynamic definied type collection (dynamic class' name as table name). 
    /// </summary> 
    /// <param name="dt"></param> 
    /// <param name="className"></param> 
    /// <returns></returns> 
    public static List<dynamic> ToDynamicList(DataTable dt, string className) 
    { 
     return ToDynamicList(ToDictionary(dt), getNewObject(dt.Columns, className)); 
    } 

    private static List<Dictionary<string, object>> ToDictionary(DataTable dt) 
    { 
     var columns = dt.Columns.Cast<DataColumn>(); 
     var Temp = dt.AsEnumerable().Select(dataRow => columns.Select(column => 
          new { Column = column.ColumnName, Value = dataRow[column] }) 
         .ToDictionary(data => data.Column, data => data.Value)).ToList(); 
     return Temp.ToList(); 
    } 

    private static List<dynamic> ToDynamicList(List<Dictionary<string, object>> list, Type TypeObj) 
    { 
     dynamic temp = new List<dynamic>(); 
     foreach (Dictionary<string, object> step in list) 
     { 
      object Obj = Activator.CreateInstance(TypeObj); 

      PropertyInfo[] properties = Obj.GetType().GetProperties(); 

      Dictionary<string, object> DictList = (Dictionary<string, object>)step; 

      foreach (KeyValuePair<string, object> keyValuePair in DictList) 
      { 
       foreach (PropertyInfo property in properties) 
       { 
        if (property.Name == keyValuePair.Key) 
        { 
         if (keyValuePair.Value != null && keyValuePair.Value.GetType() != typeof(System.DBNull)) 
         { 
          if (keyValuePair.Value.GetType() == typeof(System.Guid)) 
          { 
           property.SetValue(Obj, keyValuePair.Value, null); 
          } 
          else 
          { 
           property.SetValue(Obj, keyValuePair.Value, null); 
          } 
         } 
         break; 
        } 
       } 
      } 
      temp.Add(Obj); 
     } 
     return temp; 
    } 

    private static Type getNewObject(DataColumnCollection columns, string className) 
    { 
     AssemblyName assemblyName = new AssemblyName(); 
     assemblyName.Name = "YourAssembly"; 
     System.Reflection.Emit.AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     ModuleBuilder module = assemblyBuilder.DefineDynamicModule("YourDynamicModule"); 
     TypeBuilder typeBuilder = module.DefineType(className, TypeAttributes.Public); 

     foreach (DataColumn column in columns) 
     { 
      string propertyName = column.ColumnName; 
      FieldBuilder field = typeBuilder.DefineField(propertyName, column.DataType, FieldAttributes.Public); 
      PropertyBuilder property = typeBuilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, column.DataType, new Type[] { column.DataType }); 
      MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig; 
      MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, column.DataType, new Type[] { column.DataType }); // Type.EmptyTypes); 
      ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator(); 
      currGetIL.Emit(OpCodes.Ldarg_0); 
      currGetIL.Emit(OpCodes.Ldfld, field); 
      currGetIL.Emit(OpCodes.Ret); 
      MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, null, new Type[] { column.DataType }); 
      ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator(); 
      currSetIL.Emit(OpCodes.Ldarg_0); 
      currSetIL.Emit(OpCodes.Ldarg_1); 
      currSetIL.Emit(OpCodes.Stfld, field); 
      currSetIL.Emit(OpCodes.Ret); 
      property.SetGetMethod(currGetPropMthdBldr); 
      property.SetSetMethod(currSetPropMthdBldr); 
     } 
     Type obj = typeBuilder.CreateType(); 
     return obj; 
    }  
} 
+0

Dokładnie to, czego szukałem- dziękuję za opublikowanie tego! –

0

Można użyć rozszerzenie takiego:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Dynamic; 

public static class DataTableExtensions 
{ 
    public static IEnumerable<dynamic> AsDynamicEnumerable(this DataTable table) 
    { 
     if (table == null) 
     { 
      yield break; 
     } 

     foreach (DataRow row in table.Rows) 
     { 
      IDictionary<string, object> dRow = new ExpandoObject(); 

      foreach (DataColumn column in table.Columns) 
      { 
       var value = row[column.ColumnName]; 
       dRow[column.ColumnName] = Convert.IsDBNull(value) ? null : value; 
      } 

      yield return dRow; 
     } 
    } 
} 

Zastosowanie:

var dataTable = GetDataTableFromSomewhere(); 
var dynamicTable = dataTable.AsDynamicEnumerable(); 
var firstRowIDColumn = dynamicTable.First().ID; 
var lastRowIDColumn = dynamicTable.Last()["ID"]; 

Ale wolałem podejście IDataReader jeśli to możliwe.

Powiązane problemy