IL使用-ORM DataTable数据转换为模型类实例

 

          最近在研究动态程序集,遇到了IL语言,故学习了下,换了一个月的时间做了个DB框架,写的这篇文章呢,主要是想将我做的这个DB框架的一部分,代码分享给大家,这是一个ORM对象关系映射转换器,准确的说是将 DataTable 数据转换为模型类实例。

          我之所以会写出这个呢,是因为我之前经常用反射做ORM,发现效率非常低,可是使用了这样的方法,效率会高许多。这个转换器,有个泛型T,由于为该转换器加了反射的缓存,所以第一次使用该T类型的转换,会消耗一个反射出所有属性的时间,第二次就不需要使用反射,也就去掉了反射消耗的时间,提高了效率。而用IL创建出动态方法时,只消耗了小于1毫秒的时间,调用该动态方法则更不用说,远小于1毫秒的时间,比反射调用一次4毫秒要快速很多。

         而且这样还有个特点,因为是动态方法,DataTable返回数据列可以变,动态方法会跟着变,突破了限制。

代码如下,先介绍两个特性:

一个是用于说明属性对应哪个列的特性,OutDataMappingAttribute 特性

      

namespace DBManager.Attributes
{
    /// <summary>
    /// DataTable列映射属性
    /// </summary>
    public class OutDataMappingAttribute:Attribute
    {
        private string columnName;

        /// <summary>
        /// 获取或设置映射列的名称
        /// </summary>
        public string ColumnName
        {
            get { return columnName; }
            set { columnName = value; }
        }

        public OutDataMappingAttribute(string columnName)
        {
            this.columnName = columnName;
        }
    }
}

 另一个则是,用于处理DBNull类型的DefaultValue特性

namespace DBManager.Attributes
{
    /// <summary>
    /// 默认值设置特性
    /// </summary>
    public class DefaultValueAttribute:Attribute
    {
        private object defaultValue;

        public object DefaultValue
        {
            get { return defaultValue; }
            set { defaultValue = value; }
        }

        public DefaultValueAttribute(object value)
        {
            this.defaultValue = value;
        }
    }


}

 下面则是转换器的代码,有兴趣的朋友,还可以将创建的动态方法做缓存处理,我这里就不写明了

  1   1 using System;
  2   2 using System.Collections.Generic;
  3   3 using System.Text;
  4   4 using System.Data;
  5   5 using System.Reflection;
  6   6 using System.Reflection.Emit;
  7   7 
  8   8 namespace DBManager
  9   9 {
 10  10     /// <summary>
 11  11     /// 用于将DataTable中的数据转换为模型类的转换器
 12  12     /// 如需使用生成的程序集之外的特性,作为映射数据特性和默认值特性
 13  13     /// 请遵照生成的程序集中特性布局来,否则会引发错误!
 14  14     /// </summary>
 15  15     public class ModelConverter
 16  16     {
 17  17         private const string METHOD_NAME = "ToList";
 18  18         private volatile Dictionary<Type, TypeInfoDictionary> typeInfoDic;
 19  19 
 20  20         /// <summary>
 21  21         /// 需注意,不要经常创建该实例,因为其中带有转换用的缓存
 22  22         /// 可提高效率,如经常创建,反降低效率
 23  23         /// </summary>
 24  24         public ModelConverter()
 25  25         {
 26  26             typeInfoDic = new Dictionary<Type, TypeInfoDictionary>();
 27  27         }
 28  28 
 29  29 
 30  30         /// <summary>
 31  31         /// 将DataTable转换为含有模型类类型的List
 32  32         /// </summary>
 33  33         /// <typeparam name="T">模型类类型,
 34  34         /// 注:如需使用生成的程序集之外的模型类,需要公开的默认构造函数</typeparam>
 35  35         /// <param name="table">数据源</param>
 36  36         /// <returns>模型类实例的结果集</returns>
 37  37         public List<T> ConvertToList<T>(DataTable table) where T:class
 38  38         {
 39  39             List<T> list = new List<T>();
 40  40             Type modelType = typeof(T);
 41  41             TypeInfoDictionary infoDic = null;
 42  42 
 43  43             #region 获取或创建类型的映射字典
 44  44             lock (typeInfoDic)
 45  45             {
 46  46                 if (typeInfoDic.ContainsKey(modelType))
 47  47                 {
 48  48                     infoDic = typeInfoDic[modelType];
 49  49                 }
 50  50                 #region 内存中无该类型的映射字典,则创建
 51  51                 if (infoDic == null)
 52  52                 {
 53  53                     infoDic = new TypeInfoDictionary();
 54  54                     infoDic.typeCon = modelType.GetConstructor(Type.EmptyTypes);
 55  55                     Type outMappingType = typeof(Attributes.OutDataMappingAttribute);//这是映射列特性 属性 ColumnName string
 56  56                     Type defaultValueType = typeof(Attributes.DefaultValueAttribute);//这是默认值特性 属性 DefaultValue object
 57  57                     PropertyInfo[] pinfos = modelType.GetProperties();
 58  58                     foreach (PropertyInfo p in pinfos)
 59  59                     {
 60  60                         #region 查找两个特性值
 61  61                         object[] out_attrs = p.GetCustomAttributes(outMappingType, true);
 62  62                         object[] default_attr = p.GetCustomAttributes(defaultValueType, true);
 63  63                         Attributes.OutDataMappingAttribute out_attr = null;
 64  64                         Attributes.DefaultValueAttribute defaultAttr = null;
 65  65                         if (out_attrs != null && out_attrs.Length > 0)
 66  66                         {
 67  67                             out_attr = out_attrs[out_attrs.Length - 1] as Attributes.OutDataMappingAttribute;
 68  68                         }
 69  69                         if (default_attr != null && default_attr.Length > 0)
 70  70                         {
 71  71                             defaultAttr = default_attr[default_attr.Length - 1] as Attributes.DefaultValueAttribute;
 72  72                         }
 73  73                         #endregion
 74  74 
 75  75                         if (out_attr != null)
 76  76                         {
 77  77                             TypeInfo typeInfo = new TypeInfo();
 78  78                             if (defaultAttr!= null && 
 79  79                                 defaultAttr.DefaultValue != null)
 80  80                             {
 81  81                                 typeInfo.DefaultValue =Convert.ChangeType(defaultAttr.DefaultValue,p.PropertyType);
 82  82                             }
 83  83                             typeInfo.PropertyInfo = p;
 84  84                             typeInfo.MappingColumnName = out_attr.ColumnName;
 85  85                             infoDic.Add(out_attr.ColumnName, typeInfo);
 86  86                         }
 87  87                     }
 88  88                     typeInfoDic.Add(modelType, infoDic);
 89  89                 }
 90  90                 #endregion
 91  91             }
 92  92             #endregion
 93  93 
 94  94             #region 创建动态方法
 95  95             Dictionary<string, int> columNameParamterDic = new Dictionary<string, int>();
 96  96             List<Type> typeList = new List<Type>();
 97  97             int i = 0;
 98  98             foreach (string columnName in infoDic.Keys)
 99  99             {
100 100                 if (table.Columns.Contains(columnName))
101 101                 {
102 102                     columNameParamterDic.Add(columnName, i);
103 103                     TypeInfo typeInfo = infoDic[columnName];
104 104                     typeList.Add(typeInfo.PropertyInfo.PropertyType);
105 105                     i++;
106 106                 }
107 107             }
108 108             DynamicMethod dyMethod = new DynamicMethod(METHOD_NAME,modelType, typeList.ToArray(),modelType,true);
109 109             ILGenerator dyGL = dyMethod.GetILGenerator();
110 110             LocalBuilder nModel = dyGL.DeclareLocal(modelType);
111 111             //这段IL相当于创建一个模型类实例,并将调用其中的属性
112 112             dyGL.Emit(OpCodes.Newobj, infoDic.typeCon);
113 113             dyGL.Emit(OpCodes.Stloc_0);
114 114             foreach (string columnName in columNameParamterDic.Keys)
115 115             {
116 116                 TypeInfo tInfo = infoDic[columnName];
117 117                 dyGL.Emit(OpCodes.Ldloc_0);
118 118                 dyGL.Emit(OpCodes.Ldarg, columNameParamterDic[columnName]);
119 119                 dyGL.Emit(OpCodes.Callvirt, tInfo.PropertyInfo.GetSetMethod());
120 120             }
121 121             dyGL.Emit(OpCodes.Ldloc_0);
122 122             dyGL.Emit(OpCodes.Ret);
123 123             #endregion
124 124 
125 125             #region 调用动态方法创建模型类,并把数据放入实例中
126 126             foreach (DataRow row in table.Rows)
127 127             {
128 128                 object[] objs = new object[columNameParamterDic.Count];
129 129                 foreach (string columnName in columNameParamterDic.Keys)
130 130                 {
131 131                     int index = columNameParamterDic[columnName];//相当于表明参数位置
132 132                     object defaultValue = infoDic[columnName].DefaultValue;
133 133                     if (!row.IsNull(columnName))
134 134                     {
135 135                         objs[index] = row[columnName];
136 136                     }
137 137                     else
138 138                     {
139 139                         if (defaultValue != null)
140 140                         {
141 141                             objs[index] = defaultValue;
142 142                         }
143 143                     }
144 144                 }
145 145                 T mData = dyMethod.Invoke(null, objs) as T;
146 146                 list.Add(mData);
147 147             }
148 148             #endregion
149 149             return list;
150 150         }
151 151     }
152 152     class TypeInfo
153 153     {
154 154         private PropertyInfo propertyInfo;
155 155 
156 156         public PropertyInfo PropertyInfo
157 157         {
158 158             get { return propertyInfo; }
159 159             set { propertyInfo = value; }
160 160         }
161 161         private string mappingColumnName;
162 162 
163 163         public string MappingColumnName
164 164         {
165 165             get { return mappingColumnName; }
166 166             set { mappingColumnName = value; }
167 167         }
168 168         private object defaultValue;
169 169 
170 170         public object DefaultValue
171 171         {
172 172             get { return defaultValue; }
173 173             set { defaultValue = value; }
174 174         }
175 175     }
176 176 
177 177     class TypeInfoDictionary : Dictionary<string, TypeInfo>
178 178     {
179 179         internal ConstructorInfo typeCon;
180 180     }
181 181 }
转换器代码

 

posted on 2015-04-16 02:49  Marks周  阅读(373)  评论(0)    收藏  举报

导航