Bagaimana Anda mengonversi DataTable ke daftar umum?

185

Saat ini, saya menggunakan:

DataTable dt = CreateDataTableInSomeWay();

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

Apakah ada cara yang lebih baik / ajaib?

Iain Holder
sumber
2
Apa yang ingin Anda capai dengan Daftar yang tidak dapat Anda lakukan dengan DataRowCollection Anda?
Jason Kealey
Milik saya terlambat tetapi harapan akan bermanfaat. Solusi yang
berfungsi

Jawaban:

276

Jika Anda menggunakan .NET 3.5, Anda dapat menggunakan DataTableExtensions.AsEnumerable(metode ekstensi) dan kemudian jika Anda benar-benar membutuhkan, Anda List<DataRow>hanya IEnumerable<DataRow>dapat menelepon Enumerable.ToList:

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

atau

using System.Linq;
...
List<DataRow> list = dt.AsEnumerable().ToList();
Jon Skeet
sumber
cara mengkonversi ini listke json.
ACP
6
@Pandiya: Ada berbagai cara untuk mengubah data menjadi JSON di .NET. Secara pribadi saya selalu menggunakan perpustakaan JSON.NET, tetapi ada pendekatan lain juga.
Jon Skeet
1
@ Jon Skeet: Saya ingin mendapatkan nilai di DataRow. Apakah ada metode? Alih-alih mendapatkan daftar seperti. Item Array [0].
Ramesh Durai
@Jon, FYI: dt.AsEnumerable (). ToList () 'System.Data.EnumerableRowCollection <System.Data.DataRow>' tidak mengandung definisi untuk 'ToList'
Pradip
66
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();
darshan pandya
sumber
Kode di atas mungkin tidak berfungsi bcs. dt.Rows belum menerapkan 'AsEnumerable'. Ini dapat diperbaiki seperti di bawah ini: emp = (dari baris DataRow di dt.AsEnumerable () pilih Karyawan baru {_FirstName = baris ["FirstName"]. ToString (), _LastName = baris ["Last_Name"]. ToString ()}) .ToList ();
Navin Pandit
37

Dengan C # 3.0 dan System.Data.DataSetExtensions.dll,

List<DataRow> rows = table.Rows.Cast<DataRow>().ToList();
Marc Gravell
sumber
3
melakukan ini telah membantu kinerja dari hanya menggunakan foreach atas datarow sebanyak 50% waktu.
lloydom
33

Anda bisa menggunakannya

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

dt.Select()akan mengembalikan semua baris dalam tabel Anda, sebagai array flatows, dan Listkonstruktor menerima array objek sebagai argumen untuk mengisi daftar Anda dengan awalnya.

Kibbee
sumber
Pilih () tidak memerlukan parameter apa pun. Parameterless overload akan mengembalikan semua baris.
Kon
Terima kasih, menyesuaikan jawaban saya agar sesuai dengan saran Anda
Kibbee
15

Anda dapat membuat fungsi ekstensi sebagai:

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>();
Rahul Garg
sumber
Tidak berfungsi - lihat dotnetfiddle.net/I22r2c Perlu juga dicatat bahwa menggunakan Reflection lambat dan tidak direkomendasikan dalam kode kinerja kritis.
Almenon
Anda perlu menambahkan informasi tipe data untuk kolom. DataTable dt = DataTable baru (); dt.Columns.Add ("id", typeof (Int32)); dt.Columns.Add ("name", typeof (String)); dt.Columns.Add ("foo", typeof (DateTime)); for (int i = 0; i <= 1000; i ++) {dt.Rows.Add (i, "foo", DateTime.Now);}
Rahul Garg
Bekerja sekarang. Terima kasih.
Almenon
14

Jika Anda hanya ingin daftar nilai dari bidang int "ID" dikembalikan, Anda dapat menggunakan ...

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

Saya telah menambahkan beberapa modifikasi pada kode dari jawaban ini ( https://stackoverflow.com/a/24588210/4489664 ) karena untuk Jenis yang dapat dibatalkan akan mengembalikan pengecualian

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;
}
Bondaryuk Vladimir
sumber
Saya menghapus kelas karena dapat bekerja dengan struct juga.
Mickey Perlstein
Ini bekerja dengan sangat baik, kerja bagus. Jika ada yang ingin bermain-main dengan kode ini, saya membuat biola .net di tautan ini: dotnetfiddle.net/mTKevy
Almenon
@Almenon Saya telah menambahkan modifikasi kecil, itu harus sedikit meningkatkan kinerja
Bondaryuk Vladimir
11
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();
Morteza
sumber
Cemerlang! Anda menyelamatkan hari saya
Anynomous Khan
6

Sekali lagi, menggunakan 3.5 Anda dapat melakukannya seperti:

dt.Select().ToList()

BRGDS

Guilherme Duarte
sumber
4

Cara yang lebih 'ajaib', dan tidak perlu. NET 3.5.

Jika, misalnya, DBDatatablemengembalikan satu kolom Guids (uniqueidentifier dalam SQL) maka Anda dapat menggunakan:

Dim gList As New List(Of Guid)
gList.AddRange(DirectCast(DBDataTable.Select(), IEnumerable(Of Guid)))
Barney
sumber
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;
}
Nathan
sumber
3

DataTable.Select() tidak memberikan Baris dalam urutan mereka hadir di datatable.

Jika pesanan penting, saya merasa iterasi pada koleksi datarow dan membentuk Daftar adalah cara yang tepat untuk pergi atau Anda juga bisa menggunakan kelebihan DataTable.Select(string filterexpression, string sort).

Tapi kelebihan ini mungkin tidak menangani semua pemesanan (seperti pesanan per kasus ...) yang disediakan SQL.

pengguna129206
sumber
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});
}
syed ali abbas
sumber
1

Gunakan System.Datanamespace maka Anda akan mendapatkan .AsEnumerable().

rajashekar
sumber
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
         */

Berikut ini adalah dua fungsi di mana jika kita melewati kelas DataTable dan yang ditentukan pengguna. Kemudian akan mengembalikan Daftar kelas itu dengan data DataTable.

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

Metode ini akan memeriksa tipe data bidang, dan mengonversi nilai dataTable ke tipe data itu.

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

Untuk memanggil metode sebelumnya, gunakan sintaks berikut:

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

Ubah nama kelas Siswa dan nilai dt berdasarkan kebutuhan Anda. Dalam hal ini nama kolom DataTable dan nama properti kelas harus sama jika tidak fungsi ini tidak akan berfungsi dengan baik.

Saurin
sumber
1
Terima kasih atas jawaban anda. Akan lebih bagus jika Anda juga menambahkan penjelasan singkat dan beberapa komentar pada kode Anda. Ini membantu orang untuk memahami jawaban Anda dengan lebih baik.
Andre Hofmeister
0

Ini bekerja untuk saya: Perlu setidaknya. Net Framework 3.5, Kode di bawah ini menampilkan DataRow beralih ke Generic. Dapat dihitung, comboBox1 telah digunakan untuk ilustrasi yang lebih baik.

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;
Retribusi
sumber
0

Keluaran

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", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(50, "luci", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(10, "Andrey", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(21, "Michael", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(100, "Steven", "[email protected]", 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>
mrtwin
sumber
0

Kita dapat menggunakan Metode Generik untuk mengkonversi DataTableke Listbukan secara manual mengkonversi DataTablekeList .

Catatan: DataTable's ColumnNamedan Type' sPropertyName harus sama.

Panggil Metode di bawah ini:

long result = Utilities.ConvertTo<Student>(dt ,out listStudent);

// Generic Method
public class Utilities
{
    public static long ConvertTo<T>(DataTable table, out List<T> entity)
    {
        long returnCode = -1;
        entity = null;

        if (table == null)
        {
            return -1;
        }

        try
        {
            entity = ConvertTo<T>(table.Rows);
            returnCode = 0;
        }

        catch (Exception ex)
        {
            returnCode = 1000;
        }

        return returnCode;
    }

    static List<T> ConvertTo<T>(DataRowCollection rows)
    {
        List<T> list = null;
        if (rows != null)
        {
            list = new List<T>();

            foreach (DataRow row in rows)
            {
                T item = CreateItem<T>(row);
                list.Add(item);
            }
        }

        return list;
    }

    static T CreateItem<T>(DataRow row)
    {
        string str = string.Empty;
        string strObj = string.Empty;

        T obj = default(T);

        if (row != null)
        {
            obj = Activator.CreateInstance<T>();
            strObj = obj.ToString();
            NameValueCollection objDictionary = new NameValueCollection();

            foreach (DataColumn column in row.Table.Columns)
            {
                PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);

                if (prop != null)
                {
                    str = column.ColumnName;

                    try
                    {
                        objDictionary.Add(str, row[str].ToString());
                        object value = row[column.ColumnName];
                        Type vType = obj.GetType();

                        if (value == DBNull.Value)
                        {
                            if (vType == typeof(int) || vType == typeof(Int16)
                                                     || vType == typeof(Int32)
                                                     || vType == typeof(Int64)
                                                     || vType == typeof(decimal)
                                                     || vType == typeof(float)
                                                     || vType == typeof(double))
                            {
                                value = 0;
                            }

                            else if (vType == typeof(bool))
                            {
                                value = false;
                            }

                            else if (vType == typeof(DateTime))
                            {
                                value = DateTime.MaxValue;
                            }

                            else
                            {
                                value = null;
                            }

                            prop.SetValue(obj, value, null);
                        }

                        else
                        {
                            prop.SetValue(obj, value, null);
                        }
                    }

                    catch(Exception ex)
                    {

                    }
                }
            }

            PropertyInfo ActionProp = obj.GetType().GetProperty("ActionTemplateValue");

            if (ActionProp != null)
            {
                object ActionValue = objDictionary;
                ActionProp.SetValue(obj, ActionValue, null);
            }
        }

        return obj;
    }
}
Jayaprakash
sumber
0

Anda dapat menggunakan metode generik seperti itu untuk daftar data ke daftar generik

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;
    }
}
Ömer Ceylan
sumber
0

Konversi DataTableke GenerikDictionary

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;
}
Anil
sumber
0

Gunakan Ekstensi:

public static class Extensions
{
    #region Convert Datatable To List
    public static IList<T> ToList<T>(this DataTable table) where T : new()
    {
        IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
        IList<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)
        {
            property.SetValue(item, row[property.Name], null);
        }
        return item;
    }
    #endregion
}
mohamed mostafa
sumber
0

Untuk menetapkan baris DataTable ke Daftar kelas umum

  List<Candidate> temp = new List<Candidate>();//List that holds the Candidate Class,
    //Note:The Candidate class contains RollNo,Name and Department
    //tb is DataTable
    temp = (from DataRow dr in tb.Rows
                        select new Candidate()
                        {
                            RollNO = Convert.ToInt32(dr["RollNO"]),
                            Name = dr["Name"].ToString(),
                            Department = dr["Department"].ToString(),

                        }).ToList();
Maghalakshmi Saravana
sumber
0

Cara termudah untuk Mengubah DataTable ke dalam daftar kelas Generik

menggunakan Newtonsoft.Json;

var json = JsonConvert.SerializeObject(dataTable);
var model = JsonConvert.DeserializeObject<List<ClassName>>(json);
Maghalakshmi Saravana
sumber
0

Anda dapat menggunakan dua fungsi Generik berikut

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

dan gunakan sebagai berikut

List<StudentScanExamsDTO> studentDetails = ConvertDataTable<StudentScanExamsDTO>(dt);
Hosam Hemaily
sumber
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();

Tautan ke Contoh DotNetFiddle yang berfungsi

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

}

mr
sumber