[轉][.NET]將DataTable轉成List物件

來源  http://www.dotblogs.com.tw/rainmaker/archive/2013/11/05/126727.aspx

今天看同事分享時,看到他們將DataTable轉成物件時,使用for…each的方式。

雖然有很多的ORM框架可以幫我們做到同樣的效果,但如果手動要做的話,有那些方式呢?

1 //要轉換的物件
2 public class Document
3 {
4     public string CompId { getset; }
5     public string HandleUnit { getset; }
6     public string No { getset; }
7 }

方法1:使用for…each (for…next也可以)

01 //將DataTable轉成List<物件>
02 DataTable dt = new DataTable();
03 dt.Columns.Add("CompId"typeof(string));
04 dt.Columns.Add("HandleUnit"typeof(string));
05 dt.Columns.Add("No"typeof(string));
06 dt.Rows.Add(new object[] {"655""EBS""001" });
07 dt.Rows.Add(new object[] { "655""ODM""002" });
08 dt.Rows.Add(new object[] { "655""OCS""003" });
09
10 //Way 1, for next
11 List<Document> Way1 = new List<Document>();
12 foreach (DataRow dr in dt.Rows)
13 {
14     Document doc = new Document();
15     doc.CompId = dr.Field<string>("CompId");
16     doc.HandleUnit = dr.Field<string>("HandleUnit");
17     doc.No = dr.Field<string>("No");
18     Way1.Add(doc);
19 }

方式2:建立Extension Methods透過Reflection來簡化(參考:fetch datarow to c# object)

01 public static class DataTableExtensions
02 {
03     public static IList<T> ToList<T>(this DataTable table) where T : new()
04     {
05         IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
06         IList<T> result = new List<T>();
07
08         foreach (var row in table.Rows)
09         {
10             var item = CreateItemFromRow<T>((DataRow)row, properties);
11             result.Add(item);
12         }
13
14         return result;
15     }
16
17     public static IList<T> ToList<T>(this DataTable table, Dictionary<stringstring> mappings) where T : new()
18     {
19         IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
20         IList<T> result = new List<T>();
21
22         foreach (var row in table.Rows)
23         {
24             var item = CreateItemFromRow<T>((DataRow)row, properties, mappings);
25             result.Add(item);
26         }
27
28         return result;
29     }
30
31     private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
32     {
33         T item = new T();
34         foreach (var property in properties)
35         {
36             property.SetValue(item, row[property.Name], null);
37         }
38         return item;
39     }
40
41     private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties, Dictionary<stringstring> mappings) where T : new()
42     {
43         T item = new T();
44         foreach (var property in properties)
45         {
46             if (mappings.ContainsKey(property.Name))
47                 property.SetValue(item, row[mappings[property.Name]], null);
48         }
49         return item;
50     }
51 }

方式2.1:如果欄位名稱跟物件屬性名稱相同,則直接對應。

1 DataTable dt2 = new DataTable();
2 dt2.Columns.Add("CompId"typeof(string));
3 dt2.Columns.Add("HandleUnit"typeof(string));
4 dt2.Columns.Add("No"typeof(string));
5 dt2.Rows.Add(new object[] { "655""EBS""001" });
6 dt2.Rows.Add(new object[] { "655""ODM""002" });
7 dt2.Rows.Add(new object[] { "655""OCS""003" });
8 //Way 2, 如果欄位名稱跟屬性一樣,就直接Assign
9 var Wary2 = dt2.ToList<Document>();

方式2.2:如果欄位名稱跟物件屬性名稱不同,則建立Dictionary型態的Mapping物件,如下,

01 DataTable dt3 = new DataTable();
02 dt3.Columns.Add("CompId"typeof(string));
03 dt3.Columns.Add("HandleUnit"typeof(string));
04 dt3.Columns.Add("No"typeof(string));
05 dt3.Rows.Add(new object[] { "655""EBS""001" });
06 dt3.Rows.Add(new object[] { "655""ODM""002" });
07 dt3.Rows.Add(new object[] { "655""OCS""003" });
08 //Way 3, 如果欄位跟屬性不同,就建一個Mapping表
09
10 var mappings = new Dictionary<stringstring>();
11 mappings.Add("CompId""CompId");
12 mappings.Add("HandleUnit""HandleUnit");
13 mappings.Add("No""No");
14 var Way3 = dt3.ToList<Document>(mappings);

相信一定有一堆人會問說,為何要這樣做呢? 為何不使用ORM呢?  為什麼? 為什麼? …..等很多的疑問

同事回說,因為只是針對舊有的系統新增一個小的模組,而目前系統的Table有300多個,時間有限 … So…. 就先這樣搞…

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *