Expression构建DataTable to Entity 映射委托
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);就能很方便的获取一个实体类集合。