将DataSet转换为List

74

这是我的C#代码

Employee objEmp = new Employee();
List<Employee> empList = new List<Employee>();
foreach (DataRow dr in ds.Tables[0].Rows)
{
    empList.Add(new Employee { Name = Convert.ToString(dr["Name"]), Age = Convert.ToInt32(dr["Age"]) });
}

它使用循环从数据集创建一个列表。是否有任何直接方法、更短的方法或一行代码将数据集转换为列表?


为什么你需要它在一行中?当前的多行形式阅读起来不是同样容易吗? - Jens Kloster
4
@JensKloster 如果这个东西可以用一行写出来,知道它有什么害处呢 :) - iJade
11个回答

118

尝试使用类似以下的代码:

var empList = ds.Tables[0].AsEnumerable()
    .Select(dataRow => new Employee
    {
        Name = dataRow.Field<string>("Name")
    }).ToList();

2
这是我尝试的代码 --- var empList = ds.Tables[0].AsEnumerable().Select(dataRow => new Employee { Name = dataRow.Field<string>("Name"), Age = dataRow.Field<int>("Age") }).ToList(); 报错 "指定的转换无效"。 - iJade
如果你遇到了“指定的转换无效”的错误,请尝试在AsEnumerable之后加上ToList。解决方案来自:https://dev59.com/6n3aa4cB1Zd3GeqPZi1x - Burak Altin
var ProTLData = ds.Tables[0].AsEnumerable().ToList().Select(s => new IssueViewModel { ProjectId = s.Field<long>("ProjectId"), RoleId = s.Field<long>("RoleId"), UserId = s.Field<long>("UserId"), UserName = s.Field<string>("UserName") }); custData.IssueList = ProTLData.ToList(); 这段代码没有产生指定的转换错误,但是当我将其分配给custData.IssueList时,它会生成相同的错误。 - user11366721

39
这里提供一种将 DataTable 转换为对象列表的扩展方法:
    public static class Extensions
    {
        public static List<T> ToList<T>(this DataTable table) where T : new()
        {
            IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
            List<T> result = new List<T>();

            foreach (var row in table.Rows)
            {
                var item = CreateItemFromRow<T>((DataRow)row, properties);
                result.Add(item);
            }

            return result;
        }

        private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
        {
            T item = new T();
            foreach (var property in properties)
            {
                if (property.PropertyType == typeof(System.DayOfWeek))
                {
                    DayOfWeek day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), row[property.Name].ToString());
                    property.SetValue(item,day,null);
                }
                else
                {
                    if(row[property.Name] == DBNull.Value)
                        property.SetValue(item, null, null);
                    else
                    {
                        if (Nullable.GetUnderlyingType(property.PropertyType) != null)
                        {
                            //nullable
                            object convertedValue = null;
                            try
                            {
                                convertedValue = System.Convert.ChangeType(row[property.Name], Nullable.GetUnderlyingType(property.PropertyType));
                            }
                            catch (Exception ex)
                            {
                            }
                            property.SetValue(item, convertedValue, null);
                        }
                        else
                            property.SetValue(item, row[property.Name], null);
                    }
                }
            }
            return item;
        }
    }

使用方法:

List<Employee> lst = ds.Tables[0].ToList<Employee>();

@itay.b 代码解释: 我们首先使用反射从类T中读取所有属性名称,
然后我们遍历datatable中的所有行,并创建T类的新对象,
接着,我们使用反射设置新创建对象的属性。

属性值来自行匹配列单元格的值。

注意:类属性名称和表列名称必须相同。


喜欢这个,很棒的答案,也是泛型的一个不错的例子。 - Simon
我看到你解释了如何转换系统定义的枚举类型,能否请你解释一下如何转换在代码中定义的枚举类型,比如性别(Gender)?谢谢。 - sairfan
我可以问一下,在 CreateItemFromRow 中,为什么首先要检查属性的类型是否等于 typeof(System.DayOfWeek)?调用 property.SetValue(item, row[property.Name], null) 会引发异常吗? - Steven Volckaert
是的 @StevenVolckaert - Nitin Sawant

16
var myData = ds.Tables[0].AsEnumerable().Select(r => new Employee {
    Name = r.Field<string>("Name"),
    Age = r.Field<int>("Age")
});
var list = myData.ToList(); // For if you really need a List and not IEnumerable

4
请使用以下代码:
using Newtonsoft.Json;
string JSONString = string.Empty;
JSONString = JsonConvert.SerializeObject(ds.Tables[0]);

最佳的方法是这样做。 - Badhon Jain

2
                DataSet ds = new DataSet();
                ds = obj.getXmlData();// get the multiple table in dataset.

                Employee objEmp = new Employee ();// create the object of class Employee 
                List<Employee > empList = new List<Employee >();
                int table = Convert.ToInt32(ds.Tables.Count);// count the number of table in dataset
                for (int i = 1; i < table; i++)// set the table value in list one by one
                {
                    foreach (DataRow dr in ds.Tables[i].Rows)
                    {
                        empList.Add(new Employee { Title1 = Convert.ToString(dr["Title"]), Hosting1 = Convert.ToString(dr["Hosting"]), Startdate1 = Convert.ToString(dr["Startdate"]), ExpDate1 = Convert.ToString(dr["ExpDate"]) });
                    }
                }
                dataGridView1.DataSource = empList;

enter image description here


2

尝试这个... 根据您的需求修改代码。

      List<Employee> target = dt.AsEnumerable()
      .Select(row => new Employee
      {
        Name = row.Field<string?>(0).GetValueOrDefault(),
        Age= row.Field<int>(1)
      }).ToList();

2
只是一个小注释,但字符串已经是可空的了,使用string没有用处。 - Carra
我找不到ToList()方法,它没有出现。 - NewTech
@NewTech 使用 - 使用 System.Linq; - PAVITRA

2
添加一个名为“Helper”的新类,并将该类的属性更改为“public static”。
public static class Helper
{
    public static List<T> DataTableToList<T>(this DataTable table) where T : class, new()
    {
        try
        {
            List<T> list = new List<T>();

            foreach (var row in table.AsEnumerable())
            {
                T obj = new T();

                foreach (var prop in obj.GetType().GetProperties())
                {
                    try
                    {
                        PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
                        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
                    }
                    catch
                    {
                        continue;
                    }
                }

                list.Add(obj);
            }

            return list;
        }
        catch
        {
            return null;
        }
    }
}

在您的代码后台中可以像下面这样访问此类:

 DataTable dtt = dsCallList.Tables[0];
 List<CallAssignment> lstCallAssignement = dtt.DataTableToList<CallAssignment>();

1

我无法让Nitin Sawant的答案起作用,但我能够修改他的代码以适应我的需求。实际上,我需要使用GetRuntimeFields而不是GetProperties。这就是我最终得到的代码:

public static class Extensions
{
    public static List<T> ToList<T>(this DataTable table) where T : new()
    {
        IList<FieldInfo> fields = typeof(T).GetRuntimeFields().ToList();
        List<T> result = new List<T>();
        if (row.Table.Columns.Contains(field.Name))
        {
            foreach (var row in table.Rows)
            {
                var item = CreateItemFromRow<T>((DataRow)row, fields);
                result.Add(item);
            }
        }

        return result;
    }

    private static T CreateItemFromRow<T>(DataRow row, IList<FieldInfo> fields) where T : new()
    {
        T item = new T();

        foreach (var field in fields)
        {
            if (row[field.Name] == DBNull.Value)
                field.SetValue(item, null);
            else
                field.SetValue(item, row[field.Name]);
        }
        return item;
    }
}

在 ToList 方法中使用的 if 语句中的 row 变量声明在哪里? - wintoch
List<T> result = new List<T>();这一行后面你忘记了使用foreach循环。 - Burak Dobur
这个程序无法直接构建。在你的ToList方法中,row没有被实例化。 - Terrance Jackson

1

从存储过程命令中填充数据集

DbDataAdapter adapter = DbProviderFactories.GetFactory(cmd.Connection).CreateDataAdapter();
adapter.SelectCommand = cmd;
DataSet ds = new DataSet();
adapter.Fill(ds);

获取模式。
string s = ds.GetXmlSchema();

将其保存到一个文件中,比如说:datasetSchema.xsd。为此模式生成C#类:(在VS命令提示符下)
xsd datasetSchema.xsd /c

现在,当您需要将 DataSet 数据转换为可反序列化的类时(生成的根类的默认名称为 NewDataSet):
public static T Create<T>(string xml)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (StringReader reader = new StringReader(xml))
    {
        T t = (T)serializer.Deserialize(reader);

        reader.Close();
        return t;
    }
}

var xml = ds.GetXml();
var dataSetObjects = Create<NewDataSet>(xml);

+1。这让我更接近回答我的XML序列化/反序列化问题 - Nick Alexeev

-1
尝试上述代码,它适用于任何列表类型。
  public DataTable ListToDataTable<T>(IList<T> data)
    {
        PropertyDescriptorCollection props =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        for (int i = 0; i < props.Count; i++)
        {
            PropertyDescriptor prop = props[i];
            table.Columns.Add(prop.Name, prop.PropertyType);
        }
        object[] values = new object[props.Count];
        foreach (T item in data)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = props[i].GetValue(item);
            }
            table.Rows.Add(values);
        }
        return table;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接