Programing

DataTable을 일반 목록으로 어떻게 변환합니까?

crosscheck 2020. 5. 26. 19:43
반응형

DataTable을 일반 목록으로 어떻게 변환합니까?


현재, 나는 다음을 사용하고 있습니다 :

DataTable dt = CreateDataTableInSomeWay();

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

더 나은 / 마법적인 방법이 있습니까?


.NET 3.5를 사용 DataTableExtensions.AsEnumerable하는 경우 (확장 방법)을 사용할 수 있으며 실제로 List<DataRow>대신에 필요한 경우 다음 IEnumerable<DataRow>을 호출 할 수 있습니다 Enumerable.ToList.

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

또는

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

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

C # 3.0 및 System.Data.DataSetExtensions.dll을 사용하면

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

당신은 사용할 수 있습니다

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

dt.Select()는 테이블의 모든 행을 데이터 행의 배열로 반환하고 List생성자는 해당 객체 배열을 인수로 받아 들여 처음에 목록을 채 웁니다.


확장 기능을 다음과 같이 만들 수 있습니다.

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

"ID"int 필드의 값 목록 만 반환하려면 다음을 사용할 수 있습니다.

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

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

nullable 유형의 경우 예외를 반환하기 때문에이 답변 ( 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;
}

다시 3.5를 사용하면 다음과 같이 할 수 있습니다.

dt.Select().ToList()

BRGDS


다음은 DataTable을 일반 목록으로 변환하는 DataTable 확장 메서드입니다.

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

용법:

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

좀 더 '매직'방식이며 .NET 3.5가 필요하지 않습니다.

예를 들어 DBDatatableGuids의 단일 열 (SQL의 고유 식별자)을 반환하는 경우 다음을 사용할 수 있습니다.

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

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

DataTable.Select() 데이터 테이블에 있던 순서대로 행을 제공하지 않습니다.

순서가 중요하다면 datarow 컬렉션을 반복하고 목록을 작성하는 것이 올바른 방법이거나 과부하를 사용할 수도 있다고 생각 DataTable.Select(string filterexpression, string sort)합니다.

그러나이 과부하는 SQL이 제공하는 모든 순서 (예 : 순서대로 ...)를 처리하지 못할 수 있습니다.


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

System.Data네임 스페이스를 사용 하면 얻을 것이다 .AsEnumerable().


        /* 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과 사용자 정의 클래스를 전달하는 두 가지 함수입니다. 그런 다음 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); 

요구 사항에 따라 학생 클래스 이름과 dt 값을 변경하십시오. 이 경우 DataTable 열의 이름과 클래스 속성 이름이 같아야합니다. 그렇지 않으면이 함수가 제대로 작동하지 않습니다.


이것은 나를 위해 일했습니다 : 적어도 .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;

산출

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>

우리는 변환하는 일반적인 방법을 사용할 수 있습니다 DataTableList대신 수동으로 변환 DataTableList.

참고 : DataTableColumnNameType의이 PropertyName동일해야합니다.

아래 메소드를 호출하십시오.

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

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

이 라이브러리에서 변환을 확인하면 다음과 같은 모든 유형의 변환을 찾을 수 있습니다.

  1. DataTable에서 GenericList로
  2. DataTable에 제네릭 형식
  3. Json to DataTable, 일반 목록, 일반 유형
  4. Datason에서 Json으로

데이터 테이블에서 일반 목록에 대한 것과 같은 일반적인 방법을 사용할 수 있습니다

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

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

참고 URL : https://stackoverflow.com/questions/208532/how-do-you-convert-a-datatable-into-a-generic-list

반응형