jda*_*vis 4 .net c# generics reflection ado.net
我正在尝试编写一个将DataTable转换为强类型对象列表的泛型方法.
我到目前为止使用的代码是......
public List<T> ImportTable<T>(String fileName, String table)
{
//Establish Connection to Access Database File
var mdbData = new ConnectToAccess(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\ACCESS\" + fileName + ".mdb;");
var tableData = new List<T>();
foreach (DataRow row in mdbData.GetData("SELECT * FROM " + table).Rows)
{
tableData.Add(ConvertRowToType<T>(row));
}
return tableData;
}
public T ConvertRowToType<T>(DataRow row)
{
//??? What is the best thing to do here ???
}
Run Code Online (Sandbox Code Playgroud)
如果任何人的建议需要更改,我不会注意这个代码.
所以假设我把这个函数称为传递类型...
public class mdbConcern
{
public Int32 ConcernId { get; set; }
public String Concern { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
回到DataTable中的数据看起来像......
ConcernID Concern
1 Law and Ethics
2 Mail
3 Business English
... ...
Run Code Online (Sandbox Code Playgroud)
实现ConvertRowToType(DataRow行)方法的最佳方法是什么?
有人可以告诉我如何使用Func作为参数之一,所以我可以传递一些映射信息?
我认为这extension method是最好的方式:
public static class Helper
{
public static T ToType<T>(this DataRow row) where T : new()
{
T obj = new T();
var props = TypeDescriptor.GetProperties(obj);
foreach (PropertyDescriptor prop in props)
{
if(row.Table.Columns.IndexOf(prop.Name) >= 0
&& row[prop.Name].GetType() == prop.PropertyType)
{
prop.SetValue(obj, row[prop.Name]);
}
}
return obj;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
public List<T> ImportTable<T>(String fileName, String table)
{
//Establish Connection to Access Database File
var mdbData = new ConnectToAccess(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\ACCESS\" + fileName + ".mdb;");
var tableData = new List<T>();
foreach (DataRow row in mdbData.GetData("SELECT * FROM " + table).Rows)
{
tableData.Add(row.ToType<T>());
}
return tableData;
}
Run Code Online (Sandbox Code Playgroud)
更新我看到你要求Func提供映射.我不确定你想要的是什么,但这是我想出的方法:
public class mdbConcern
{
public Int32 ConcernId { get; set; }
public String Concern { get; set; }
public static PropertyDescriptor Mapping(string name)
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(mdbConcern));
switch (name)
{
case "Concern_Id":
return props.GetByName("ConcernId");
case "Concern":
return props.GetByName("Concern");
default:
return null;
}
}
}
public static class Helper
{
public static T ToType<T>(this DataRow row, Func<string, PropertyDescriptor> mapping)
where T : new()
{
T obj = new T();
foreach (DataColumn col in row.Table.Columns)
{
var prop = mapping(col.ColumnName);
if(prop != null)
prop.SetValue(obj, row[col]);
}
return obj;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
foreach (DataRow row in mdbData.GetData("SELECT * FROM " + table).Rows)
{
tableData.Add(row.ToType<mdbConcern>(mdbConcern.Mapping));
}
Run Code Online (Sandbox Code Playgroud)
这是一个使用类型属性的属性来存储其映射的版本.我认为这是一个更自然的解决方案:
[AttributeUsage(AttributeTargets.Property)]
public class ColumnMappingAttribute : Attribute
{
public string Name { get; set; }
public ColumnMappingAttribute(string name)
{
Name = name;
}
}
public class mdbConcern
{
ColumnMapping("Concern_Id")]
public Int32 ConcernId { get; set; }
ColumnMapping("Concern")]
public String Concern { get; set; }
}
public static class Helper
{
public static T ToType<T>(this DataRow row) where T : new()
{
T obj = new T();
var props = TypeDescriptor.GetProperties(obj);
foreach (PropertyDescriptor prop in props)
{
var columnMapping = prop.Attributes.OfType<ColumnMappingAttribute>().FirstOrDefault();
if(columnMapping != null)
{
if(row.Table.Columns.IndexOf(columnMapping.Name) >= 0
&& row[columnMapping.Name].GetType() == prop.PropertyType)
{
prop.SetValue(obj, row[columnMapping.Name]);
}
}
}
return obj;
}
}
Run Code Online (Sandbox Code Playgroud)