将DataTable转换为List <t> </t>

时间:2010-02-17 15:07:05

标签: c# .net generics ado.net datatable

我有疑问,有时我从DataTable转换为List<T>

  List<EDog> lstDogs = (from drRow in dsDogs.Tables[0].AsEnumerable()
                        select new EDog()
                        {
                            intIdDog = drRow.Field<int>("IdDog"),
                            intIdOwner = drRow.Field<int?>("IdOwner"),
                            intAge = drRow.Field<int>("Age"),
                            strName = drRow.Field<string>("Name")
                       }).ToList();

这很好用,但现在我正在考虑将它做成通用的,这样任何类型的DataSet都可以转换为强类型列表。

我怎么能把它变成通用的?也许围绕这部分并创建对象的代表?

new EDog()
{
    intIdDog = drRow.Field<int>("IdDog"),
    intIdOwner = drRow.Field<int?>("IdOwner"),
    intAge = drRow.Field<int>("Age"),
    strName = drRow.Field<string>("Name")
}

我试了但是得到了一个错误:

select (lambda) expected....

有什么建议吗?

我之所以需要这个,是因为结果的每个DataRow都需要转换为实体以便更好地操作。

4 个答案:

答案 0 :(得分:10)

好的,让我们玩得开心:

public static class DataTableExtensions
{
    public static List<T> ToGenericList<T>(this DataTable datatable, Func<DataRow, T> converter)
    {
        return (from row in datatable.AsEnumerable()
                select converter(row)).ToList();
    }
}

class EDog
{
    private int intIdDog;
    private int intIdOwner;
    private int intAge;
    private string strName;

    ...

    public static EDog Converter(DataRow row)
    {
        return new EDog
                        {
                            intIdDog = (int)row["IdDog"],
                            intIdOwner = (int)row["IdOwner"],
                            intAge = (int)row["Age"],
                            strName = row["Name"] as string
                        };
    }
}

用法:

List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>(EDog.Converter);

但是没有足够的乐趣,对吗?那怎么样:

class DataRowKeyAttribute : Attribute
{
    private readonly string _Key;

    public string Key
    {
        get { return _Key; }
    }

    public DataRowKeyAttribute(string key)
    {
        _Key = key;
    }
}


static class DataTableExtensions
{
    public static List<T> ToGenericList<T>(this DataTable datatable) where T : new()
    {
        return (from row in datatable.AsEnumerable()
                select Convert<T>(row)).ToList();
    }

    private static T Convert<T>(DataRow row) where T : new()
    {
        var result = new T();

        var type = result.GetType();

        foreach (var fieldInfo in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
        {
            var dataRowKeyAttribute = fieldInfo.GetCustomAttributes(typeof (DataRowKeyAttribute), true).FirstOrDefault() as DataRowKeyAttribute;
            if (dataRowKeyAttribute != null)
            {
                fieldInfo.SetValue(result, row[dataRowKeyAttribute.Key]);
            }
        } 

        return result;
    }
}

class EDog
{
    [DataRowKey("IdDog")]
    private int intIdDog;
    [DataRowKey("IdOwner")]
    private int intIdOwner;
    [DataRowKey("Age")]
    private int intAge;
    [DataRowKey("Name")]
    private string strName;

    ... 
}

用法:

List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>();

如果您希望获得真正的乐趣,请添加错误处理,请考虑缓存反射数据以提高性能并将字段更改为属性。

答案 1 :(得分:6)

这是你想要的东西吗?

public static List<T> ConvertDS<T>(DataSet ds, Converter<DataRow, T> converter)
{
    return
        (from row in ds.Tables[0].AsEnumerable()
         select converter(row)).ToList();
}

答案 2 :(得分:1)

它不会轻易转换,你可以做到,但它可能不会节省太多的工作。

考虑代码示例中的内在知识:您知道DataTable中每列的类型和名称,以及它在输出类型中映射到的属性的类型和名称。另一种方法是知道每列的类型和索引(用名称代替索引)。在这两种情况下,您都需要定义一个包含该信息的映射。

另一种方法是构建一个基于约定的转换器 - 换句话说,你的DataTable列名称及其目标属性需要一致地命名,偏离该约定会导致转换失败。 / p>

答案 3 :(得分:-1)

我能够在一行代码中完成: dt是DataTable

List<DataRow> alist = new dt.AsEnumerable().ToList();