如何将DataTable转换为通用列表?

时间:2008-10-16 13:23:51

标签: c# generics datatable

目前,我正在使用:

DataTable dt = CreateDataTableInSomeWay();

List<DataRow> list = new List<DataRow>(); 
foreach (DataRow dr in dt.Rows)
{
    list.Add(dr);
}

有更好的/神奇的方式吗?

28 个答案:

答案 0 :(得分:252)

如果您使用的是.NET 3.5,则可以使用DataTableExtensions.AsEnumerable(扩展方法)然后如果您确实需要List<DataRow>而不只是IEnumerable<DataRow>,则可以调用{{ 3}}:

IEnumerable<DataRow> sequence = dt.AsEnumerable();

using System.Linq;
...
List<DataRow> list = dt.AsEnumerable().ToList();

答案 1 :(得分:62)

List<Employee> emp = new List<Employee>();

//Maintaining DataTable on ViewState
//For Demo only

DataTable dt = ViewState["CurrentEmp"] as DataTable;

//read data from DataTable 
//using lamdaexpression


emp = (from DataRow row in dt.Rows

   select new Employee
   {
       _FirstName = row["FirstName"].ToString(),
       _LastName = row["Last_Name"].ToString()

   }).ToList();

答案 2 :(得分:34)

使用C#3.0和System.Data.DataSetExtensions.dll,

List<DataRow> rows = table.Rows.Cast<DataRow>().ToList();

答案 3 :(得分:31)

您可以使用

List<DataRow> list = new List<DataRow>(dt.Select());

dt.Select()将返回表中的所有行,作为数据行数组,List构造函数接受该对象数组作为参数,以便最初填充列表。

答案 4 :(得分:13)

您可以创建扩展功能:

public static List<T> ToListof<T>(this DataTable dt)
{
    const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
    var columnNames = dt.Columns.Cast<DataColumn>()
        .Select(c => c.ColumnName)
        .ToList();
    var objectProperties = typeof(T).GetProperties(flags);
    var targetList = dt.AsEnumerable().Select(dataRow =>
    {
        var instanceOfT = Activator.CreateInstance<T>();

        foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
        {
            properties.SetValue(instanceOfT, dataRow[properties.Name], null);
        }
        return instanceOfT;
    }).ToList();

    return targetList;
}


var output = yourDataInstance.ToListof<targetModelType>();

答案 5 :(得分:12)

如果您只想要返回“ID”int字段中的值列表,可以使用...

List<int> ids = (from row in dt.AsEnumerable() select Convert.ToInt32(row["ID"])).ToList();

答案 6 :(得分:9)

using System.Data;


var myEnumerable = myDataTable.AsEnumerable();

List<MyClass> myClassList =
    (from item in myEnumerable
     select new MyClass{
         MyClassProperty1 = item.Field<string>("DataTableColumnName1"),
         MyClassProperty2 = item.Field<string>("DataTableColumnName2")
    }).ToList();

答案 7 :(得分:8)

我在此答案(https://stackoverflow.com/a/24588210/4489664)中添加了一些修改代码,因为对于可为空的类型,它将返回异常

public static List<T> DataTableToList<T>(this DataTable table) where T: new()
{
    List<T> list = new List<T>();
    var typeProperties = typeof(T).GetProperties().Select(propertyInfo => new
        {
            PropertyInfo = propertyInfo,
            Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType
        }).ToList();

    foreach (var row in table.Rows.Cast<DataRow>())
    {
        T obj = new T();
        foreach (var typeProperty in typeProperties)
        {
            object value = row[typeProperty.PropertyInfo.Name];
            object safeValue = value == null || DBNull.Value.Equals(value)
                ? null
                : Convert.ChangeType(value, typeProperty.Type);

            typeProperty.PropertyInfo.SetValue(obj, safeValue, null);
        }
        list.Add(obj);
    }
    return list;
}

答案 8 :(得分:6)

再次使用3.5,你可以这样做:

dt.Select().ToList()

BRGDS

答案 9 :(得分:4)

// this is better suited for expensive object creation/initialization
IEnumerable<Employee> ParseEmployeeTable(DataTable dtEmployees)
{
    var employees = new ConcurrentBag<Employee>();

    Parallel.ForEach(dtEmployees.AsEnumerable(), (dr) =>
    {
        employees.Add(new Employee() 
        {
            _FirstName = dr["FirstName"].ToString(),
            _LastName = dr["Last_Name"].ToString()
        });
    });

    return employees;
}

答案 10 :(得分:4)

这是一个DataTable扩展方法,它将DataTable转换为通用列表。

https://gist.github.com/gaui/a0a615029f1327296cf8

<强>用法:

List<Employee> emp = dtTable.DataTableToList<Employee>();

答案 11 :(得分:4)

更“神奇”的方式,不需要.NET 3.5。

例如,如果DBDatatable返回一列Guids(SQL中的uniqueidentifier),那么您可以使用:

Dim gList As New List(Of Guid)
gList.AddRange(DirectCast(DBDataTable.Select(), IEnumerable(Of Guid)))

答案 12 :(得分:3)

DataTable dt;   // datatable should contains datacolumns with Id,Name

List<Employee> employeeList=new List<Employee>();  // Employee should contain  EmployeeId, EmployeeName as properties

foreach (DataRow dr in dt.Rows)
{
    employeeList.Add(new Employee{EmployeeId=dr.Id,EmplooyeeName=dr.Name});
}

答案 13 :(得分:3)

DataTable.Select()不会按照数据表中存在的顺序给出行。

如果顺序很重要,我觉得迭代数据行集合并形成一个List是正确的方法,或者你也可以使用DataTable.Select(string filterexpression, string sort)的重载。

但是这个重载可能无法处理SQL提供的所有排序(如逐个...)。

答案 14 :(得分:2)

将数据表转换为类的通用列表的最简单方法

使用Newtonsoft.Json;

readonly

答案 15 :(得分:1)

使用System.Data命名空间,您将获得.AsEnumerable()

答案 16 :(得分:1)

        /* This is a generic method that will convert any type of DataTable to a List 
         * 
         * 
         * Example :    List< Student > studentDetails = new List< Student >();  
         *              studentDetails = ConvertDataTable< Student >(dt);  
         *
         * Warning : In this case the DataTable column's name and class property name
         *           should be the same otherwise this function will not work properly
         */
  

以下是两个函数,如果我们传递一个   数据表                和用户定义的类。                然后它将使用DataTable数据返回该类的List。

        public static List<T> ConvertDataTable<T>(DataTable dt)
        {
            List<T> data = new List<T>();
            foreach (DataRow row in dt.Rows)
            {
                T item = GetItem<T>(row);
                data.Add(item);
            }
            return data;
        }


        private static T GetItem<T>(DataRow dr)
        {
            Type temp = typeof(T);
            T obj = Activator.CreateInstance<T>();

            foreach (DataColumn column in dr.Table.Columns)
            {
                foreach (PropertyInfo pro in temp.GetProperties())
                {
                   //in case you have a enum/GUID datatype in your model
                   //We will check field's dataType, and convert the value in it.
                    if (pro.Name == column.ColumnName){                
                    try
                    {
                        var convertedValue = GetValueByDataType(pro.PropertyType, dr[column.ColumnName]);
                        pro.SetValue(obj, convertedValue, null);
                    }
                    catch (Exception e)
                    {         
                       //ex handle code                   
                        throw;
                    }
                        //pro.SetValue(obj, dr[column.ColumnName], null);
                }
                    else
                        continue;
                }
            }
            return obj;
        }
  

此方法将检查字段的数据类型,并将dataTable值转换为该数据类型。

    private static object GetValueByDataType(Type propertyType, object o)
    {
        if (o.ToString() == "null")
        {
            return null;
        }
        if (propertyType == (typeof(Guid)) || propertyType == typeof(Guid?))
        {
            return Guid.Parse(o.ToString());
        }
        else if (propertyType == typeof(int) || propertyType.IsEnum) 
        {
            return Convert.ToInt32(o);
        }
        else if (propertyType == typeof(decimal) )
        {
            return Convert.ToDecimal(o);
        }
        else if (propertyType == typeof(long))
        {
            return Convert.ToInt64(o);
        }
        else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
        {
            return Convert.ToBoolean(o);
        }
        else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
        {
            return Convert.ToDateTime(o);
        }
        return o.ToString();
    }
  

要调用上述方法,请使用以下语法:

List< Student > studentDetails = new List< Student >();  
studentDetails = ConvertDataTable< Student >(dt); 
  

根据您的要求更改学生班级名称和学生值。在这种情况下,DataTable列的名称和类属性名称应该相同,否则此函数将无法正常工作。

答案 17 :(得分:0)

我们可以使用通用方法将DataTable转换为List,而不是手动将DataTable转换为List

注意:DataTable的{​​{1}}和ColumnName的{​​{1}}应该相同。

调用以下方法:

Type

答案 18 :(得分:0)

Output

public class ModelUser
{
    #region Model

    private string _username;
    private string _userpassword;
    private string _useremail;
    private int _userid;

    /// <summary>
    /// 
    /// </summary>
    public int userid
    {
        set { _userid = value; }
        get { return _userid; }
    }


    /// <summary>
    /// 
    /// </summary>

    public string username
    {
        set { _username = value; }
        get { return _username; }
    }

    /// <summary>
    /// 
    /// </summary>
    public string useremail
    {
        set { _useremail = value; }
        get { return _useremail; }
    }

    /// <summary>
    /// 
    /// </summary>
    public string userpassword
    {
        set { _userpassword = value; }
        get { return _userpassword; }
    }
    #endregion Model
}

public List<ModelUser> DataTableToList(DataTable dt)
{
    List<ModelUser> modelList = new List<ModelUser>();
    int rowsCount = dt.Rows.Count;
    if (rowsCount > 0)
    {
        ModelUser model;
        for (int n = 0; n < rowsCount; n++)
        {
            model = new ModelUser();

            model.userid = (int)dt.Rows[n]["userid"];
            model.username = dt.Rows[n]["username"].ToString();
            model.useremail = dt.Rows[n]["useremail"].ToString();
            model.userpassword = dt.Rows[n]["userpassword"].ToString();

            modelList.Add(model);
        }
    }
    return modelList;
}

static DataTable GetTable()
{
    // Here we create a DataTable with four columns.
    DataTable table = new DataTable();
    table.Columns.Add("userid", typeof(int));
    table.Columns.Add("username", typeof(string));
    table.Columns.Add("useremail", typeof(string));
    table.Columns.Add("userpassword", typeof(string));

    // Here we add five DataRows.
    table.Rows.Add(25, "Jame", "Jame@hotmail.com", DateTime.Now.ToString());
    table.Rows.Add(50, "luci", "luci@hotmail.com", DateTime.Now.ToString());
    table.Rows.Add(10, "Andrey", "Andrey@hotmail.com", DateTime.Now.ToString());
    table.Rows.Add(21, "Michael", "Michael@hotmail.com", DateTime.Now.ToString());
    table.Rows.Add(100, "Steven", "Steven@hotmail.com", DateTime.Now.ToString());
    return table;
}

protected void Page_Load(object sender, EventArgs e)
{
    List<ModelUser> userList = new List<ModelUser>();

    DataTable dt = GetTable();

    userList = DataTableToList(dt);

    gv.DataSource = userList;
    gv.DataBind();
}[enter image description here][1]

    

</asp:GridView>
</div>

答案 19 :(得分:0)

https://www.nuget.org/packages/AD.GenericConversion/

检查此库以进行转换,您将在此处找到所有类型的转换,例如: -

  1. DataTable to GenericList
  2. DataTable的通用类型
  3. Json to DataTable,Generic list,Generic type
  4. DataTable to Json

答案 20 :(得分:0)

您可以使用通用方法,如将数据表导入通用列表

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);
                    if (propertyInfo.PropertyType.IsEnum)
                    {
                        propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, row[prop.Name].ToString()));
                    }
                    else
                    {
                        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
                    }                          
                }
                catch
                {
                    continue;
                }
            }

            list.Add(obj);
        }

        return list;
    }
    catch
    {
        return null;
    }
}

答案 21 :(得分:0)

DataTable转换为通用Dictionary

public static Dictionary<object,IList<dynamic>> DataTable2Dictionary(DataTable dt)
{
    Dictionary<object, IList<dynamic>> dict = new Dictionary<dynamic, IList<dynamic>>();

    foreach(DataColumn column in dt.Columns)
    {
        IList<dynamic> ts = dt.AsEnumerable()
                              .Select(r => r.Field<dynamic>(column.ToString()))
                              .ToList();
        dict.Add(column, ts);
    }
    return dict;
}

答案 22 :(得分:0)

使用扩展名:

private func setSizesSliderValue(pn: Int, slider: UISlider, setSliderValue: Bool)
{
    if setSliderValue
    {
        slider.setValue(Float(pn), animated: true)
    }

    masterPresetInfoLabel.text = String(
        format: TexturingViewController.createAndSendPresetNumberNofiticationTemplate,
        self.currentPresetNumber.name.uppercased(),
        String(self.currentPresetNumber.currentUserIndexHumanFriendly)
    )
}

@objc func presetNumberSliderTouchUp(_ sender: Any)
{
    guard let slider = sender as? NormalSlider else{
        return
    }

    setupSliderChangedValuesGeneric(slider: slider, setSliderValue: true)
}

private func setupSliderChangedValuesGeneric(slider: NormalSlider, setSliderValue: Bool)
{
    let rounded = roundf((Float(slider.value) / Float(presetNumberStep))) * Float(presetNumberStep)

    // Set new preset number value
    self.currentPresetNumber.current = Int(rounded)
    setSizesSliderValue(pn: Int(rounded), slider: slider, setSliderValue: setSliderValue)
}

@IBAction func presetNumberChanged(_ sender: Any)
{
    guard let slider = sender as? NormalSlider else{
        return
    }

    setupSliderChangedValuesGeneric(slider: slider, setSliderValue: false)
}

答案 23 :(得分:0)

要将DataTable行分配给类的通用列表

y =( moment('Mon 03-Jul-2017, 11:00 AM', 'ddd DD-MMM-YYYY, hh:mm A').format('hh:mm A') );
x= ( moment('Mon 03-Jul-2017, 11:00 PM', 'ddd DD-MMM-YYYY, hh:mm A').format('hh:mm A') );

console.log(x>y)

答案 24 :(得分:0)

这对我有用: 至少需要.Net Framework 3.5, 下面的代码显示DataRow转向Generic.IEnumerable,comboBox1用于更好的说明。

using System.Linq;

DataTable dt = new DataTable();            
dt = myClass.myMethod();                 
List<object> list = (from row in dt.AsEnumerable() select (row["name"])).ToList();
comboBox1.DataSource = list;

答案 25 :(得分:0)

您可以使用以下两个通用函数

private static List<T> ConvertDataTable<T>(DataTable dt)
    {
        List<T> data = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            T item = GetItem<T>(row);
            data.Add(item);
        }
        return data;
    }
    private static T GetItem<T>(DataRow dr)
    {

        Type temp = typeof(T);
        T obj = Activator.CreateInstance<T>();

        foreach (DataColumn column in dr.Table.Columns)
        {
            foreach (PropertyInfo pro in temp.GetProperties())
            {
                if (pro.Name == column.ColumnName)
                    pro.SetValue(obj, dr[column.ColumnName].ToString(), null);
                else
                    continue;
            }
        }
        return obj;
    }

并按照以下说明使用它

List<StudentScanExamsDTO> studentDetails = ConvertDataTable<StudentScanExamsDTO>(dt);

答案 26 :(得分:0)

lPerson = dt.AsEnumerable().Select(s => new Person()
        {
            Name = s.Field<string>("Name"),
            SurName = s.Field<string>("SurName"),
            Age = s.Field<int>("Age"),
            InsertDate = s.Field<DateTime>("InsertDate")
        }).ToList();

链接到有效的DotNetFiddle Example

using System;
using System.Collections.Generic;   
using System.Data;
using System.Linq;
using System.Data.DataSetExtensions;

public static void Main()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("SurName", typeof(string));
    dt.Columns.Add("Age", typeof(int));
    dt.Columns.Add("InsertDate", typeof(DateTime));

    var row1= dt.NewRow();
    row1["Name"] = "Adam";
    row1["SurName"] = "Adam";
    row1["Age"] = 20;
    row1["InsertDate"] = new DateTime(2020, 1, 1);
    dt.Rows.Add(row1);

    var row2 = dt.NewRow();
    row2["Name"] = "John";
    row2["SurName"] = "Smith";
    row2["Age"] = 25;
    row2["InsertDate"] = new DateTime(2020, 3, 12);
    dt.Rows.Add(row2);

    var row3 = dt.NewRow();
    row3["Name"] = "Jack";
    row3["SurName"] = "Strong";
    row3["Age"] = 32;
    row3["InsertDate"] = new DateTime(2020, 5, 20);
    dt.Rows.Add(row3);

    List<Person> lPerson = new List<Person>();
    lPerson = dt.AsEnumerable().Select(s => new Person()
    {
        Name = s.Field<string>("Name"),
        SurName = s.Field<string>("SurName"),
        Age = s.Field<int>("Age"),
        InsertDate = s.Field<DateTime>("InsertDate")
    }).ToList();

    foreach(Person pers in lPerson)
    {
        Console.WriteLine("{0} {1} {2} {3}", pers.Name, pers.SurName, pers.Age, pers.InsertDate);
    }
}   

public class Person
{
    public string Name { get; set; }
    public string SurName { get; set; }
    public int Age { get; set; }
    public DateTime InsertDate { get; set; }
}

}

答案 27 :(得分:0)

如果有人想创建自定义函数以将数据表转换为列表

class Program
{
    static void Main(string[] args)
    {
        DataTable table = GetDataTable();
        var sw = new Stopwatch();

        sw.Start();
        LinqMethod(table);
        sw.Stop();
        Console.WriteLine("Elapsed time for Linq Method={0}", sw.ElapsedMilliseconds);

        sw.Reset();

        sw.Start();
        ForEachMethod(table);
        sw.Stop();
        Console.WriteLine("Elapsed time for Foreach method={0}", sw.ElapsedMilliseconds);

        Console.ReadKey();
    }

    private static DataTable GetDataTable()
    {
        var table = new DataTable();
        table.Columns.Add("ID", typeof(double));
        table.Columns.Add("CategoryName", typeof(string));
        table.Columns.Add("Active", typeof(double));

        var rand = new Random();

        for (int i = 0; i < 100000; i++)
        {
            table.Rows.Add(i, "name" + i,  rand.Next(0, 2));
        }
        return table;
    }

    private static void LinqMethod(DataTable table)
    {
        var list = table.AsEnumerable()
            .Skip(1)
            .Select(dr =>
                new Category
                {
                    Id = Convert.ToInt32(dr.Field<double>("ID")),
                    CategoryName = dr.Field<string>("CategoryName"),                      
                    IsActive =
                            dr.Field<double>("Active") == 1 ? true : false
                }).ToList();
    }
    private static void ForEachMethod(DataTable table)
    {
        var categoryList = new List<Category>(table.Rows.Count);
        foreach (DataRow row in table.Rows)
        {
            var values = row.ItemArray;
            var category = new Category()
            {
                Id = Convert.ToInt32(values[0]),
                CategoryName = Convert.ToString(values[1]),                   
                IsActive = (double)values[2] == 1 ? true : false
            };
            categoryList.Add(category);
        }
    }

    private class Category
    {
        public int Id { get; set; }
        public string CategoryName { get; set; }
        public bool IsActive { get; set; }
    }
}

如果执行上述代码,Foreach方法将在56毫秒内完成,而linq 1则需要101毫秒(用于1000条记录)。 因此,Foreach方法更好用。 来源:Ways to Convert Datatable to List in C# (with performance test example)