2011-10-17 17 views
14

Come posso convertire un DataTable in IEnumerable<dynamicObject>?Come posso convertire un DataTable in un oggetto dinamico?

Per esempio, voglio convertire qualsiasi DataTable

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

In un elenco di oggetti

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

Così

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

Come posso fare?

risposta

23

ne dite con 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; 
     } 
    } 
} 

Si potrebbe anche provare l'override TrySetMember se desideri rendere la riga dinamica scrivibile.

Uso:

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

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

Migliore soluzione. Grande. –

+3

4 anni dopo, ancora un'ottima risposta! – code4life

1

provare

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

Sto pensando a qualcosa di più generico. – BrunoLM

+0

vuoi dire - senza conoscenza dei campi? – Yahia

+0

Sì, esattamente. Nuovi campi possono apparire o scomparire, oppure potrebbero essere campi completamente diversi ... – BrunoLM

2

Ci sono alcuni ORM che possono leggere direttamente da DB a dynamic ExpandoObject. Per esempio petapoco (e leggere qui la example)

Oppure si potrebbe provare qualcosa di simile:

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

non puoi applicare l'indicizzazione con [] a un ExpandoObject, sostituire il codice con uno esistente qui http://stackoverflow.com/a/7794962/84216 –

+0

@AmrBadawy corretto – 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

C'è un piccolo errore nell'uomo! La riga 'dynamicDt.Add (dyn);' Dovrebbe essere al di fuori del ciclo interno. –

+0

Questa soluzione ha funzionato perfettamente per me poiché desidero associare a datagrid da datatable. – kinnu

0

Converti Datatable alla lista

#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

precedenti codici suneelsarraf solo generato runtime oggetto dinamico con la proprietà come stringa. dopo l'aggiornamento genererà ogni proprietà in base al tipo di dati della colonna 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

Esattamente quello che stavo cercando, grazie per aver postato questo! –

0

È possibile utilizzare un'estensione simile a questo:

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; 
     } 
    } 
} 

Usage:

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

Ma ho preferito un approccio IDataReader, se possibile.

Problemi correlati