从IDataReader中读取数据实体2

不过在这个之前,先把我们需要的一些IDataReader里面的方法先反射出来,做好缓存(放在DataReaderExtensions类里面,避免为每个T反射一次):



1         #region Static Readonly Fields
2         private static readonly MethodInfo DataRecord_ItemGetter_Int =
3             typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
4         private static readonly MethodInfo DataRecord_GetOrdinal =
5             typeof(IDataRecord).GetMethod("GetOrdinal");
6         private static readonly MethodInfo DataReader_Read =
7             typeof(IDataReader).GetMethod("Read");
8         private static readonly MethodInfo Convert_IsDBNull =
9             typeof(Convert).GetMethod("IsDBNull");
10         private static readonly MethodInfo DataRecord_GetDateTime =
11             typeof(IDataRecord).GetMethod("GetDateTime");
12         private static readonly MethodInfo DataRecord_GetDecimal =
13             typeof(IDataRecord).GetMethod("GetDecimal");
14         private static readonly MethodInfo DataRecord_GetDouble =
15             typeof(IDataRecord).GetMethod("GetDouble");
16         private static readonly MethodInfo DataRecord_GetInt32 =
17             typeof(IDataRecord).GetMethod("GetInt32");
18         private static readonly MethodInfo DataRecord_GetInt64 =
19             typeof(IDataRecord).GetMethod("GetInt64");
20         private static readonly MethodInfo DataRecord_GetString =
21             typeof(IDataRecord).GetMethod("GetString");
22         private static readonly MethodInfo DataRecord_IsDBNull =
23             typeof(IDataRecord).GetMethod("IsDBNull");
24         #endregion
25


    接下来就是Emit了,但是鉴于其的难度比较高,就不仔细说明了,如果各位有兴趣,可以单独聊,这里就直接把这成堆的天书贴上来了(未处理short、byte、bool的情况,因为Oracle不支持这个类型,所以一直没写,同样枚举也只支持基础类型是int的或long的):



  1             #region Init Methods
  2
  3             private static Converter<IDataReader, List<T>> CreateBatchDataLoader(List<DbColumnInfo> columnInfoes)
  4             {
  5                 DynamicMethod dm = new DynamicMethod(string.Empty, typeof(List<T>),
  6                     new Type[] { typeof(IDataReader) }, typeof(EntityConverter<T>));
  7                 ILGenerator il = dm.GetILGenerator();
  8                 LocalBuilder list = il.DeclareLocal(typeof(List<T>));
  9                 LocalBuilder item = il.DeclareLocal(typeof(T));
10                 Label exit = il.DefineLabel();
11                 Label loop = il.DefineLabel();
12                 // List<T> list = new List<T>();
13                 il.Emit(OpCodes.Newobj, typeof(List<T>).GetConstructor(Type.EmptyTypes));
14                 il.Emit(OpCodes.Stloc_S, list);
15                 // [ int %index% = arg.GetOrdinal(%ColumnName%); ]
16                 LocalBuilder[] colIndices = GetColumnIndices(il, columnInfoes);
17                 // while (arg.Read()) {
18                 il.MarkLabel(loop);
19                 il.Emit(OpCodes.Ldarg_0);
20                 il.Emit(OpCodes.Callvirt, DataReader_Read);
21                 il.Emit(OpCodes.Brfalse, exit);
22                 //      T item = new T { %Property% =  };
23                 BuildItem(il, columnInfoes, item, colIndices);
24                 //      list.Add(item);
25                 il.Emit(OpCodes.Ldloc_S, list);
26                 il.Emit(OpCodes.Ldloc_S, item);
27                 il.Emit(OpCodes.Callvirt, typeof(List<T>).GetMethod("Add"));
28                 // }
29                 il.Emit(OpCodes.Br, loop);
30                 il.MarkLabel(exit);
31                 // return list;
32                 il.Emit(OpCodes.Ldloc_S, list);
33                 il.Emit(OpCodes.Ret);
34                 return (Converter<IDataReader, List<T>>)dm.CreateDelegate(typeof(Converter<IDataReader, List<T>>));
35             }
36
37             private static LocalBuilder[] GetColumnIndices(ILGenerator il, List<DbColumnInfo> columnInfoes)
38             {
39                 LocalBuilder[] colIndices = new LocalBuilder[columnInfoes.Count];
40                 for (int i = 0; i < colIndices.Length; i++)
41                 {
42                     // int %index% = arg.GetOrdinal(%ColumnName%);
43                     colIndices[i] = il.DeclareLocal(typeof(int));
44                     il.Emit(OpCodes.Ldarg_0);
45                     il.Emit(OpCodes.Ldstr, columnInfoes[i].ColumnName);
46                     il.Emit(OpCodes.Callvirt, DataRecord_GetOrdinal);
47                     il.Emit(OpCodes.Stloc_S, colIndices[i]);
48                 }
49                 return colIndices;
50             }
51
52             private static void BuildItem(ILGenerator il, List<DbColumnInfo> columnInfoes,
53                 LocalBuilder item, LocalBuilder[] colIndices)
54             {
55                 // T item = new T();
56                 il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
57                 il.Emit(OpCodes.Stloc_S, item);
58                 for (int i = 0; i < colIndices.Length; i++)
59                 {
60                     if (IsCompatibleType(columnInfoes[i].Type, typeof(int)))
61                     {
62                         // item.%Property% = arg.GetInt32(%index%);
63                         ReadInt32(il, item, columnInfoes, colIndices, i);
64                     }
65                     else if (IsCompatibleType(columnInfoes[i].Type, typeof(int?)))
66                     {
67                         // item.%Property% = arg.IsDBNull ? default(int?) : (int?)arg.GetInt32(%index%);
68                         ReadNullableInt32(il, item, columnInfoes, colIndices, i);
69                     }
70                     else if (IsCompatibleType(columnInfoes[i].Type, typeof(long)))
71                     {
72                         // item.%Property% = arg.GetInt64(%index%);
73                         ReadInt64(il, item, columnInfoes, colIndices, i);
74                     }
75                     else if (IsCompatibleType(columnInfoes[i].Type, typeof(long?)))
76                     {
77                         // item.%Property% = arg.IsDBNull ? default(long?) : (long?)arg.GetInt64(%index%);
78                         ReadNullableInt64(il, item, columnInfoes, colIndices, i);
79                     }
80                     else if (IsCompatibleType(columnInfoes[i].Type, typeof(decimal)))
81                     {
82                         // item.%Property% = arg.GetDecimal(%index%);
83                         ReadDecimal(il, item, columnInfoes[i].SetMethod, colIndices[i]);
84                     }
85                     else if (columnInfoes[i].Type == typeof(decimal?))
86                     {
87                         // item.%Property% = arg.IsDBNull ? default(decimal?) : (int?)arg.GetDecimal(%index%);
88                         ReadNullableDecimal(il, item, columnInfoes[i].SetMethod, colIndices[i]);
89                     }
90                     else if (columnInfoes[i].Type == typeof(DateTime))
91                     {
92                         // item.%Property% = arg.GetDateTime(%index%);
93                         ReadDateTime(il, item, columnInfoes[i].SetMethod, colIndices[i]);
94                     }
95                     else if (columnInfoes[i].Type == typeof(DateTime?))
96                     {
97                         // item.%Property% = arg.IsDBNull ? default(DateTime?) : (int?)arg.GetDateTime(%index%);
98                         ReadNullableDateTime(il, item, columnInfoes[i].SetMethod, colIndices[i]);
99                     }
100                     else
101                     {
102                         // item.%Property% = (%PropertyType%)arg[%index%];
103                         ReadObject(il, item, columnInfoes, colIndices, i);
104                     }
105                 }
106             }
107
108             private static bool IsCompatibleType(Type t1, Type t2)
109             {
110                 if (t1 == t2)
111                     return true;
112                 if (t1.IsEnum && Enum.GetUnderlyingType(t1) == t2)
113                     return true;
114                 var u1 = Nullable.GetUnderlyingType(t1);
115                 var u2 = Nullable.GetUnderlyingType(t2);
116                 if (u1 != null && u2 != null)
117                     return IsCompatibleType(u1, u2);
118                 return false;
119             }
120
121             private static void ReadInt32(ILGenerator il, LocalBuilder item,
122                 List<DbColumnInfo> columnInfoes, LocalBuilder[] colIndices, int i)
123             {
124                 il.Emit(OpCodes.Ldloc_S, item);
125                 il.Emit(OpCodes.Ldarg_0);
126                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
127                 il.Emit(OpCodes.Callvirt, DataRecord_GetInt32);
128                 il.Emit(OpCodes.Callvirt, columnInfoes[i].SetMethod);
129             }
130
131             private static void ReadNullableInt32(ILGenerator il, LocalBuilder item,
132                 List<DbColumnInfo> columnInfoes, LocalBuilder[] colIndices, int i)
133             {
134                 var local = il.DeclareLocal(columnInfoes[i].Type);
135                 Label intNull = il.DefineLabel();
136                 Label intCommon = il.DefineLabel();
137                 il.Emit(OpCodes.Ldloca, local);
138                 il.Emit(OpCodes.Ldarg_0);
139                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
140                 il.Emit(OpCodes.Callvirt, DataRecord_IsDBNull);
141                 il.Emit(OpCodes.Brtrue_S, intNull);
142                 il.Emit(OpCodes.Ldarg_0);
143                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
144                 il.Emit(OpCodes.Callvirt, DataRecord_GetInt32);
145                 il.Emit(OpCodes.Call, columnInfoes[i].Type.GetConstructor(
146                     new Type[] { Nullable.GetUnderlyingType(columnInfoes[i].Type) }));
147                 il.Emit(OpCodes.Br_S, intCommon);
148                 il.MarkLabel(intNull);
149                 il.Emit(OpCodes.Initobj, columnInfoes[i].Type);
150                 il.MarkLabel(intCommon);
151                 il.Emit(OpCodes.Ldloc_S, item);
152                 il.Emit(OpCodes.Ldloc, local);
153                 il.Emit(OpCodes.Callvirt, columnInfoes[i].SetMethod);
154             }
155
156             private static void ReadInt64(ILGenerator il, LocalBuilder item,
157                 List<DbColumnInfo> columnInfoes, LocalBuilder[] colIndices, int i)
158             {
159                 il.Emit(OpCodes.Ldloc_S, item);
160                 il.Emit(OpCodes.Ldarg_0);
161                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
162                 il.Emit(OpCodes.Callvirt, DataRecord_GetInt64);
163                 il.Emit(OpCodes.Callvirt, columnInfoes[i].SetMethod);
164             }
165
166             private static void ReadNullableInt64(ILGenerator il, LocalBuilder item,
167                 List<DbColumnInfo> columnInfoes, LocalBuilder[] colIndices, int i)
168             {
169                 var local = il.DeclareLocal(columnInfoes[i].Type);
170                 Label intNull = il.DefineLabel();
171                 Label intCommon = il.DefineLabel();
172                 il.Emit(OpCodes.Ldloca, local);
173                 il.Emit(OpCodes.Ldarg_0);
174                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
175                 il.Emit(OpCodes.Callvirt, DataRecord_IsDBNull);
176                 il.Emit(OpCodes.Brtrue_S, intNull);
177                 il.Emit(OpCodes.Ldarg_0);
178                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
179                 il.Emit(OpCodes.Callvirt, DataRecord_GetInt64);
180                 il.Emit(OpCodes.Call, columnInfoes[i].Type.GetConstructor(
181                     new Type[] { Nullable.GetUnderlyingType(columnInfoes[i].Type) }));
182                 il.Emit(OpCodes.Br_S, intCommon);
183                 il.MarkLabel(intNull);
184                 il.Emit(OpCodes.Initobj, columnInfoes[i].Type);
185                 il.MarkLabel(intCommon);
186                 il.Emit(OpCodes.Ldloc_S, item);
187                 il.Emit(OpCodes.Ldloc, local);
188                 il.Emit(OpCodes.Callvirt, columnInfoes[i].SetMethod);
189             }
190
191             private static void ReadDecimal(ILGenerator il, LocalBuilder item,
192                 MethodInfo setMethod, LocalBuilder colIndex)
193             {
194                 il.Emit(OpCodes.Ldloc_S, item);
195                 il.Emit(OpCodes.Ldarg_0);
196                 il.Emit(OpCodes.Ldloc_S, colIndex);
197                 il.Emit(OpCodes.Callvirt, DataRecord_GetDecimal);
198                 il.Emit(OpCodes.Callvirt, setMethod);
199             }
200
201             private static void ReadNullableDecimal(ILGenerator il, LocalBuilder item,
202                 MethodInfo setMethod, LocalBuilder colIndex)
203             {
204                 var local = il.DeclareLocal(typeof(decimal?));
205                 Label decimalNull = il.DefineLabel();
206                 Label decimalCommon = il.DefineLabel();
207                 il.Emit(OpCodes.Ldloca, local);
208                 il.Emit(OpCodes.Ldarg_0);
209                 il.Emit(OpCodes.Ldloc_S, colIndex);
210                 il.Emit(OpCodes.Callvirt, DataRecord_IsDBNull);
211                 il.Emit(OpCodes.Brtrue_S, decimalNull);
212                 il.Emit(OpCodes.Ldarg_0);
213                 il.Emit(OpCodes.Ldloc_S, colIndex);
214                 il.Emit(OpCodes.Callvirt, DataRecord_GetDecimal);
215                 il.Emit(OpCodes.Call, typeof(decimal?).GetConstructor(new Type[] { typeof(decimal) }));
216                 il.Emit(OpCodes.Br_S, decimalCommon);
217                 il.MarkLabel(decimalNull);
218                 il.Emit(OpCodes.Initobj, typeof(decimal?));
219                 il.MarkLabel(decimalCommon);
220                 il.Emit(OpCodes.Ldloc_S, item);
221                 il.Emit(OpCodes.Ldloc, local);
222                 il.Emit(OpCodes.Callvirt, setMethod);
223             }
224
225             private static void ReadDateTime(ILGenerator il, LocalBuilder item,
226                 MethodInfo setMethod, LocalBuilder colIndex)
227             {
228                 il.Emit(OpCodes.Ldloc_S, item);
229                 il.Emit(OpCodes.Ldarg_0);
230                 il.Emit(OpCodes.Ldloc_S, colIndex);
231                 il.Emit(OpCodes.Callvirt, DataRecord_GetDateTime);
232                 il.Emit(OpCodes.Callvirt, setMethod);
233             }
234
235             private static void ReadNullableDateTime(ILGenerator il, LocalBuilder item,
236                 MethodInfo setMethod, LocalBuilder colIndex)
237             {
238                 var local = il.DeclareLocal(typeof(DateTime?));
239                 Label dtNull = il.DefineLabel();
240                 Label dtCommon = il.DefineLabel();
241                 il.Emit(OpCodes.Ldloca, local);
242                 il.Emit(OpCodes.Ldarg_0);
243                 il.Emit(OpCodes.Ldloc_S, colIndex);
244                 il.Emit(OpCodes.Callvirt, DataRecord_IsDBNull);
245                 il.Emit(OpCodes.Brtrue_S, dtNull);
246                 il.Emit(OpCodes.Ldarg_0);
247                 il.Emit(OpCodes.Ldloc_S, colIndex);
248                 il.Emit(OpCodes.Callvirt, DataRecord_GetDateTime);
249                 il.Emit(OpCodes.Call, typeof(DateTime?).GetConstructor(new Type[] { typeof(DateTime) }));
250                 il.Emit(OpCodes.Br_S, dtCommon);
251                 il.MarkLabel(dtNull);
252                 il.Emit(OpCodes.Initobj, typeof(DateTime?));
253                 il.MarkLabel(dtCommon);
254                 il.Emit(OpCodes.Ldloc_S, item);
255                 il.Emit(OpCodes.Ldloc, local);
256                 il.Emit(OpCodes.Callvirt, setMethod);
257             }
258
259             private static void ReadObject(ILGenerator il, LocalBuilder item,
260                 List<DbColumnInfo> columnInfoes, LocalBuilder[] colIndices, int i)
261             {
262                 Label common = il.DefineLabel();
263                 il.Emit(OpCodes.Ldloc_S, item);
264                 il.Emit(OpCodes.Ldarg_0);
265                 il.Emit(OpCodes.Ldloc_S, colIndices[i]);
266                 il.Emit(OpCodes.Callvirt, DataRecord_ItemGetter_Int);
267                 il.Emit(OpCodes.Dup);
268                 il.Emit(OpCodes.Call, Convert_IsDBNull);
269                 il.Emit(OpCodes.Brfalse_S, common);
270                 il.Emit(OpCodes.Pop);
271                 il.Emit(OpCodes.Ldnull);
272                 il.MarkLabel(common);
273                 il.Emit(OpCodes.Unbox_Any, columnInfoes[i].Type);
274                 il.Emit(OpCodes.Callvirt, columnInfoes[i].SetMethod);
275             }
276
277             #endregion
278
279             #region Internal Methods
280
281             internal static List<T> Select(IDataReader reader)
282             {
283                 return BatchDataLoader(reader);
284             }
285
286             #endregion
287





    好,到这里,这个扩展方法已经完成了,来试用一下吧:



1         public List<MyClass> GetList()
2         {
3             var reader = GetReader();
4             return reader.Select<MyClass>();
5         }
6
7         public IDataReader GetReader()
8         {
9             // todo : GetReader
10             throw new NotImplementedException();
11         }
12





    是不是很简单,大家不妨做个效率测试,看看是这段基于反射的代码效率高还是大家手写的效率高,以及填充到DataSet的效率,当然要注意数据的访问时间本身是不缺定的。(里面用了不少优化的访问方式,如果大家在处理IDataReader的手法不够娴熟的话,还真难说效率谁的高,呵呵)

(最后的示例代码里面忘记用using了。。。不改了,大家自己加上吧)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值