DataTable
をIEnumerable<dynamicObject>
に変換するにはどうすればよいですか?
たとえば、変換したいanyDataTable
ID | Name DI | emaN
--------- or ---------
1 | x 2 | x
2 | y 1 | y
オブジェクトのリスト
// list 1 (ex 1) // list 2 (ex 2)
{ {
{ ID = 1, Name = "x" } { DI = 2, emaN = "x" }
{ ID = 2, Name = "y" } { DI = 1, emaN = "y" }
} }
そう
list1.First().ID // 1
list2.First().emaN // "x"
どうすればできますか?
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;
}
}
}
動的行を書き込み可能にしたい場合は、TrySetMember
をオーバーライドしてみることもできます。
使用法:
DataTable table = ...
var dynamicTable = table.AsDynamicEnumerable();
var firstRowsNameField = dynamicTable.First().Name;
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;
}
}
以前のsuneelsarrafコードは、プロパティを文字列として持つ生成されたランタイム動的オブジェクトのみを生成していました。次の更新では、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;
}
}
DBからdynamic ExpandoObject
に直接読み取ることができるORMがいくつかあります。例えば petapoco (そしてここで example を読んでください)
または、同様のことを試すことができます。
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"]
試す
var MyResult = from x in MyDataTable select new { ID = x["ID"], Name = x["Name"] }.ToList ();
次のような拡張機能を使用できます。
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;
}
}
}
使用法:
var dataTable = GetDataTableFromSomewhere();
var dynamicTable = dataTable.AsDynamicEnumerable();
var firstRowIDColumn = dynamicTable.First().ID;
var lastRowIDColumn = dynamicTable.Last()["ID"];
しかし、可能であれば、IDataReaderアプローチを使用しました。
データテーブルをリストに変換
#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