c# - 将 DataTable 转换为强类型对象列表

标签 c# .net 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 ???        
}

如果任何人的建议需要更改,我不会关注此代码。

假设我调用这个函数传递类型...

public class mdbConcern
{
    public Int32 ConcernId { get; set; }
    public String Concern { get; set; }
}

DataTable 中返回的数据看起来像...

ConcernID  Concern
1          Law and Ethics
2          Mail
3          Business English
...        ...

实现 ConvertRowToType(DataRow row) 方法的最佳方式是什么?

有人可以告诉我如何使用 Func 作为参数之一,以便我可以传递一些映射信息吗?

最佳答案

我认为扩展方法是最好的方法:

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

用法:

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

更新 我看到您要求提供映射的 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;
    }
}

用法:

foreach (DataRow row in mdbData.GetData("SELECT * FROM " + table).Rows)
{
    tableData.Add(row.ToType<mdbConcern>(mdbConcern.Mapping));
}

这是一个使用类型属性上的属性来存储其映射的版本。我认为这是一个更自然的解决方案:

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

关于c# - 将 DataTable 转换为强类型对象列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9199473/

相关文章:

c# - 在 C++ DLL 和 C# GUI 之间传递数据时结果不一致

c# - Sonarlint 不会将 "Managed Binary Analysis rules"引入 Visual Studio

c# - 如何在新创建的数据库列上将访问列值设置为 0(默认值)? C#

c# - 有没有一种快速方法可以对 TFS 中的待处理更改进行 checkin 锁定?

generics - 无法在大小通用类型的函数内使用 mem::size_of 创建常量 (E401)

generics - 如何避免 Rust 中重复的长通用约束

c# - 从构造函数调用时静态函数意外返回

.NET 如何检测是否支持 DirectX 10?

.net - MSBuild 的路径

swift - Swift 中协议(protocol)和泛型的限制