DataTable與List的轉換

透過反射互相轉換,如果是要用ADO.NET查資料出來但又想用linq的話很方便

之前在工作上碰到一個bug,就是專案使用EntityFramework把資料撈出來,但是發現View沒有設定primary key,這時候如果前面欄位資料都一樣(譬如是同一分類或群組資料),查出來的第一行資料就會蓋掉其他筆,造成bug,有嘗試在class欄位上加上[key]但還是沒辦法,最後只好改用ADO.NET撈資料再轉成List,所以今天就是要來分享怎麼轉

1.List轉DataTable

 public DataTable ConvertToDataTable<T>(IList<T> data)
        {
            PropertyDescriptorCollection properties =
               TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }
            return table;

        }

2.DataTable轉List

        /// <summary>
        /// DataTable轉成List 透過反射
        /// </summary>
        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;
        }
        /// <summary>
        /// DataTable轉成List 透過反射 欄位名稱與類別名稱不同 <DataTable欄位名稱.Class屬性名稱>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <param name="mappings"></param>
        /// <returns></returns>
        public static IList<T> ToList<T>(this DataTable table, Dictionary<string, string> mappings) 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, mappings);
                result.Add(item);
            }

            return result;
        }
        private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties, Dictionary<string, string> mappings) where T : new()
        {
            T item = new T();
            foreach (var property in properties)
            {
                if (mappings.ContainsKey(property.Name))
                    property.SetValue(item, row[mappings[property.Name]], null);
            }
            return item;
        }

 

 

前面用法都是給DataSet使用,以下是給DataReader使用,對ADO.NET不太熟的可以看前篇文章

        /// <summary>
        /// 通過反射填充泛型集合List的方法
        /// </summary>
        /// <typeparam name="T">資料型態</typeparam>
        /// <param name="reader">單向捲動檢視 (Forward-only) 資料流</param>
        /// <returns>泛型集合List</returns>
        public static List<T> FillDataListGeneric<T>(IDataReader reader) where T : class
        {
            List<T> DataList = new List<T>();
            while (reader.Read())
            {
                T RowInstance = Activator.CreateInstance<T>();
                foreach (PropertyInfo Property in typeof(T).GetProperties())
                {
                    try
                    {
                        if (HasColumn(reader, Property.Name))
                        {
                            if (reader[Property.Name] != DBNull.Value)
                            {
                                Property.SetValue(RowInstance, Convert.ChangeType(reader[Property.Name], Property.PropertyType), null);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("通過反射填充泛型集合時發生錯誤," + "錯誤原因:" + ex.Message);
                    }
                }
                DataList.Add(RowInstance);
            }
            return DataList;
        }