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);就能很方便的获取一个实体类集合。

 

posted @ 2014-07-28 22:21  Echofool  阅读(2351)  评论(6编辑  收藏  举报