1 namespace Echofool.Utility.Common { 2 using System; 3 using System.Collections.Generic; 4 using System.Data; 5 using System.Linq.Expressions; 6 using System.Reflection; 7 using System.Reflection.Emit; 8 9 public class DataTableUtility { 10 11 public static IEnumerable<T> Get<T>(DataTable table) where T : new() { 12 if (table == null) { 13 yield break; 14 } 15 if (table.Rows.Count == 0) { 16 yield break; 17 } 18 foreach (DataRow row in table.Rows) { 19 yield return Get<T>(row); 20 } 21 } 22 23 public static T Get<T>(DataRow row) where T : new() { 24 return GenericCache<T>.Factory(row); 25 } 26 27 public class GenericCache<T> where T : new() { 28 static GenericCache() { 29 //Factory = GetFactoryIL(); 這里寫錯了
Factory = GetFactory(); 30 } 31 public static readonly Func<DataRow, T> Factory; 32 33 private static Func<DataRow, T> GetFactory() { 34 var type = typeof(T); 35 var rowType = typeof(DataRow); 36 var rowDeclare = Expression.Parameter(rowType, "row"); 37 var instanceDeclare = Expression.Parameter(type, "instance"); 38 var newExpression = Expression.New(type); 39 var instanceExpression = Expression.Assign(instanceDeclare, newExpression); 40 var nullEqualExpression = Expression.Equal(rowDeclare, Expression.Constant(null)); 41 var containsMethod = typeof(DataColumnCollection).GetMethod("Contains"); 42 var indexerMethod = rowType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, 43 new[] { typeof(string) }, 44 new[] { new ParameterModifier(1) }); 45 var setExpressions = new List<Expression>(); 46 var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 47 var columns = Expression.Property(Expression.Property(rowDeclare, "Table"), "Columns"); 48 foreach (var propertyInfo in properties) { 49 if (propertyInfo.CanWrite) { 50 var propertyName = Expression.Constant(propertyInfo.Name, typeof(string)); 51 var checkIfContainsColumn = 52 Expression.Call(columns, containsMethod, propertyName); 53 var propertyExpression = Expression.Property(instanceDeclare, propertyInfo); 54 var value = Expression.Call(rowDeclare, indexerMethod, propertyName); 55 var proertyAssign = Expression.Assign(propertyExpression, Expression.Convert(value, propertyInfo.PropertyType)); 56 setExpressions.Add(Expression.IfThen(checkIfContainsColumn, proertyAssign)); 57 } 58 } 59 var checkIfRowIsNull = Expression.IfThenElse(nullEqualExpression, Expression.Empty(), Expression.Block(setExpressions)); 60 var body = Expression.Block(new[] { instanceDeclare }, newExpression, instanceExpression, checkIfRowIsNull, instanceDeclare); 61 return Expression.Lambda<Func<DataRow, T>>(body, rowDeclare).Compile(); 62 } 63 } 64 65 public static T GetByReflection<T>(DataRow dr) where T : new() { 66 var t = new T(); 67 if (dr != null) { 68 foreach (var p in typeof(T).GetProperties()) { 69 if (!dr.Table.Columns.Contains(p.Name)) { 70 continue; 71 } 72 var obj = dr[p.Name]; 73 var set = p.GetSetMethod(); 74 if (set == null) { 75 continue; 76 } 77 p.SetValue(t, obj, null); 78 } 79 } 80 return t; 81 } 82 } 83 }
通過Expression動態構建DataTable映射到實體類,在三層架構中,如果使用的數據層是使用Ado.Net技術,那么加上這個DataTable to Entity的工具類,將為你減少很多代碼量。
主要目的是解決DataTable到Entity的映射關系。
1 public class MyClass { 2 public MyClass() { } 3 4 public MyClass(DataRow row) { 5 if (row != null) { 6 if (row.Table.Columns.Contains("Name")) { 7 this.Name = (string)row["Name"]; 8 } 9 if (row.Table.Columns.Contains("Age")) { 10 this.Age = (int)row["Age"]; 11 } 12 } 13 } 14 15 public string Name { get; set; } 16 public int Age { get; set; } 17 18 }
如上定義的實體類MyClass,有一個string類型的Name屬性和一個int類型的Age屬性。
如果自定義構造函數是可以很方便的從DataRow對象中獲取數據填充實體類,但如果涉及的實體類太多,而且如果想通過定義特性標記 來實現一些字段特殊處理,構造函數的方式,需要你寫太多的代碼,而且很多都是重復的邏輯。
現在使用DataTableUtility.Get<MyClass>.Get(row);就能很方便的獲取一個實體類。
現在使用DataTableUtility.Get<MyClass>.Get(table);就能很方便的獲取一個實體類集合。