雖然有很多的ORM框架可以幫我們將資料轉成List<物件>,但如果手動要將DataTable轉成List<物件>,有那些方式呢?
今天看同事分享時,看到他們將DataTable轉成物件時,使用for...each的方式。
雖然有很多的ORM框架可以幫我們做到同樣的效果,但如果手動要做的話,有那些方式呢?
//要轉換的物件
public class Document
{
public string CompId { get; set; }
public string HandleUnit { get; set; }
public string No { get; set; }
}
方法1:使用for...each (for…next也可以)
//將DataTable轉成List<物件>
DataTable dt = new DataTable();
dt.Columns.Add("CompId", typeof(string));
dt.Columns.Add("HandleUnit", typeof(string));
dt.Columns.Add("No", typeof(string));
dt.Rows.Add(new object[] {"655", "EBS", "001" });
dt.Rows.Add(new object[] { "655", "ODM", "002" });
dt.Rows.Add(new object[] { "655", "OCS", "003" });
//Way 1, for next
List<Document> Way1 = new List<Document>();
foreach (DataRow dr in dt.Rows)
{
Document doc = new Document();
doc.CompId = dr.Field<string>("CompId");
doc.HandleUnit = dr.Field<string>("HandleUnit");
doc.No = dr.Field<string>("No");
Way1.Add(doc);
}
方式2:建立Extension Methods透過Reflection來簡化(參考:fetch datarow to c# object)
public static class DataTableExtensions
{
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;
}
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) where T : new()
{
T item = new T();
foreach (var property in properties)
{
property.SetValue(item, row[property.Name], null);
}
return item;
}
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;
}
}
方式2.1:如果欄位名稱跟物件屬性名稱相同,則直接對應。
DataTable dt2 = new DataTable();
dt2.Columns.Add("CompId", typeof(string));
dt2.Columns.Add("HandleUnit", typeof(string));
dt2.Columns.Add("No", typeof(string));
dt2.Rows.Add(new object[] { "655", "EBS", "001" });
dt2.Rows.Add(new object[] { "655", "ODM", "002" });
dt2.Rows.Add(new object[] { "655", "OCS", "003" });
//Way 2, 如果欄位名稱跟屬性一樣,就直接Assign
var Wary2 = dt2.ToList<Document>();
方式2.2:如果欄位名稱跟物件屬性名稱不同,則建立Dictionary型態的Mapping物件,如下,
DataTable dt3 = new DataTable();
dt3.Columns.Add("CompId", typeof(string));
dt3.Columns.Add("HandleUnit", typeof(string));
dt3.Columns.Add("No", typeof(string));
dt3.Rows.Add(new object[] { "655", "EBS", "001" });
dt3.Rows.Add(new object[] { "655", "ODM", "002" });
dt3.Rows.Add(new object[] { "655", "OCS", "003" });
//Way 3, 如果欄位跟屬性不同,就建一個Mapping表
var mappings = new Dictionary<string, string>();
mappings.Add("CompId", "CompId");
mappings.Add("HandleUnit", "HandleUnit");
mappings.Add("No", "No");
var Way3 = dt3.ToList<Document>(mappings);
相信一定有一堆人會問說,為何要這樣做呢? 為何不使用ORM呢? 為什麼? 為什麼? …..等很多的疑問
同事回說,因為只是針對舊有的系統新增一個小的模組,而目前系統的Table有300多個,時間有限 ... So.... 就先這樣搞…
參考資料
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^