Mercurial > pub > bltoolkit
comparison Source/DataAccess/DataAccessorBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f990fcb411a9 |
---|---|
1 using System; | |
2 using System.Collections; | |
3 using System.Collections.Generic; | |
4 using System.ComponentModel; | |
5 using System.Data; | |
6 using System.Linq; | |
7 using System.Reflection; | |
8 using System.Reflection.Emit; | |
9 | |
10 using BLToolkit.Common; | |
11 using BLToolkit.Data; | |
12 using BLToolkit.Data.DataProvider; | |
13 using BLToolkit.Mapping; | |
14 using BLToolkit.Properties; | |
15 using BLToolkit.Reflection; | |
16 using BLToolkit.Reflection.Emit; | |
17 using BLToolkit.TypeBuilder; | |
18 using BLToolkit.TypeBuilder.Builders; | |
19 | |
20 namespace BLToolkit.DataAccess | |
21 { | |
22 public class DataAccessorBuilder : AbstractTypeBuilderBase | |
23 { | |
24 struct MapOutputParametersValue | |
25 { | |
26 public readonly string ReturnValueMember; | |
27 public readonly ParameterInfo ParameterInfo; | |
28 | |
29 public MapOutputParametersValue(string returnValueMember, ParameterInfo parameterInfo) | |
30 { | |
31 ReturnValueMember = returnValueMember; | |
32 ParameterInfo = parameterInfo; | |
33 } | |
34 } | |
35 | |
36 public override int GetPriority(BuildContext context) | |
37 { | |
38 return TypeBuilderConsts.Priority.DataAccessor; | |
39 } | |
40 | |
41 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) | |
42 { | |
43 if (context.IsBuildStep) | |
44 { | |
45 if (context.IsAbstractMethod) | |
46 { | |
47 // Give up if there is any builder that builds the method body. | |
48 // | |
49 if (builders.Count > 1) | |
50 foreach (IAbstractTypeBuilder builder in builders) | |
51 if (builder != this && builder.IsApplied(context, builders)) | |
52 return false; | |
53 | |
54 return true; | |
55 } | |
56 | |
57 // Treat an abstract getter/setter as a regular method | |
58 // when the property has [NoInstance] attribute | |
59 // | |
60 if (context.IsAbstractGetter || context.IsAbstractSetter) | |
61 return context.CurrentProperty.IsDefined(typeof(NoInstanceAttribute), true); | |
62 } | |
63 | |
64 return false; | |
65 } | |
66 | |
67 private Dictionary<Type, Type> _actualTypes; | |
68 private Dictionary<Type, Type> ActualTypes | |
69 { | |
70 get | |
71 { | |
72 if (_actualTypes == null) | |
73 { | |
74 _actualTypes = new Dictionary<Type, Type>(); | |
75 | |
76 object[] attrs = Context.Type.GetAttributes(typeof(ActualTypeAttribute)); | |
77 | |
78 foreach (ActualTypeAttribute attr in attrs) | |
79 if (!_actualTypes.ContainsKey(attr.BaseType)) | |
80 _actualTypes.Add(attr.BaseType, attr.ActualType); | |
81 } | |
82 | |
83 return _actualTypes; | |
84 } | |
85 } | |
86 | |
87 enum ReturnType | |
88 { | |
89 DataReader, | |
90 DataSet, | |
91 DataTable, | |
92 List, | |
93 Dictionary, | |
94 Enumerable, | |
95 Void, | |
96 Scalar, | |
97 Object | |
98 } | |
99 | |
100 static ReturnType GetReturnType(Type returnType) | |
101 { | |
102 if (returnType == typeof(IDataReader)) | |
103 return ReturnType.DataReader; | |
104 | |
105 if (returnType == typeof(DataSet) || returnType.IsSubclassOf(typeof(DataSet))) | |
106 return ReturnType.DataSet; | |
107 | |
108 if (returnType == typeof(DataTable) || returnType.IsSubclassOf(typeof(DataTable))) | |
109 return ReturnType.DataTable; | |
110 | |
111 if (!returnType.IsArray && | |
112 (IsInterfaceOf(returnType, typeof(IList)) || | |
113 returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IList<>))) | |
114 return ReturnType.List; | |
115 | |
116 if (IsInterfaceOf(returnType, typeof(IDictionary)) || | |
117 returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) | |
118 return ReturnType.Dictionary; | |
119 | |
120 if (returnType == typeof(IEnumerable) || | |
121 returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) | |
122 return ReturnType.Enumerable; | |
123 | |
124 if (returnType == typeof(void)) | |
125 return ReturnType.Void; | |
126 | |
127 if (TypeHelper.IsScalar(returnType.IsByRef ? returnType.GetElementType() : returnType)) | |
128 return ReturnType.Scalar; | |
129 | |
130 return ReturnType.Object; | |
131 } | |
132 | |
133 void ThrowTypeBuilderException(string message) | |
134 { | |
135 throw new TypeBuilderException( | |
136 string.Format(message, Context.CurrentMethod.DeclaringType.Name, Context.CurrentMethod.Name)); | |
137 } | |
138 | |
139 const BindingFlags _bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; | |
140 | |
141 readonly Type _baseType = typeof(DataAccessor); | |
142 Type _objectType; | |
143 bool _explicitObjectType; | |
144 ParameterInfo[] _parameters; | |
145 ArrayList _paramList; | |
146 ArrayList _refParamList; | |
147 bool _createManager; | |
148 LocalBuilder _locManager; | |
149 LocalBuilder _locObjType; | |
150 ArrayList _outputParameters; | |
151 SqlQueryAttribute _sqlQueryAttribute; | |
152 ArrayList _formatParamList; | |
153 ParameterInfo _destination; | |
154 ArrayList _mapOutputParameters; | |
155 | |
156 protected override void BuildAbstractMethod() | |
157 { | |
158 // Any class variable must be initialized before use | |
159 // as the same instance of the class is utilized to build abstract methods. | |
160 // | |
161 _paramList = new ArrayList(); | |
162 _refParamList = new ArrayList(); | |
163 _formatParamList = new ArrayList(); | |
164 _mapOutputParameters = new ArrayList(); | |
165 _destination = null; | |
166 _createManager = true; | |
167 _objectType = null; | |
168 _explicitObjectType = false; | |
169 _parameters = Context.CurrentMethod.GetParameters(); | |
170 _locManager = Context.MethodBuilder.Emitter.DeclareLocal(typeof(DbManager)); | |
171 _locObjType = Context.MethodBuilder.Emitter.DeclareLocal(typeof(Type)); | |
172 _outputParameters = null; | |
173 _sqlQueryAttribute = null; | |
174 | |
175 GetSqlQueryAttribute(); | |
176 ProcessParameters(); | |
177 | |
178 var returnType = MethodReturnType; | |
179 var rt = GetReturnType(returnType); | |
180 | |
181 CreateDbManager(rt != ReturnType.Enumerable); | |
182 SetObjectType(); | |
183 | |
184 // Define execution method type. | |
185 // | |
186 switch (rt) | |
187 { | |
188 case ReturnType.DataReader : ExecuteReader(); break; | |
189 case ReturnType.DataSet : ExecuteDataSet(returnType); break; | |
190 case ReturnType.DataTable : ExecuteDataTable(); break; | |
191 case ReturnType.Void : ExecuteNonQuery(); break; | |
192 case ReturnType.Scalar : ExecuteScalar(); break; | |
193 case ReturnType.Enumerable : ExecuteEnumerable(); break; | |
194 | |
195 case ReturnType.List: | |
196 | |
197 if (!_explicitObjectType) | |
198 { | |
199 Type elementType = TypeHelper.GetListItemType(returnType); | |
200 | |
201 if (elementType == typeof(object) && _destination != null) | |
202 elementType = TypeHelper.GetListItemType(Context.CurrentMethod.ReturnType); | |
203 | |
204 if (elementType != typeof(object)) | |
205 _objectType = elementType; | |
206 | |
207 if (ActualTypes.ContainsKey(_objectType)) | |
208 _objectType = ActualTypes[_objectType]; | |
209 } | |
210 | |
211 if (_objectType == null || _objectType == typeof(object)) | |
212 ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType); | |
213 | |
214 if (TypeHelper.IsScalar(_objectType)) | |
215 ExecuteScalarList(); | |
216 else | |
217 ExecuteList(); | |
218 | |
219 break; | |
220 | |
221 case ReturnType.Dictionary: | |
222 { | |
223 Type elementType = null; | |
224 Type keyType = typeof(object); | |
225 Type[] gTypes = TypeHelper.GetGenericArguments(returnType, typeof(IDictionary)); | |
226 | |
227 if ((gTypes == null || gTypes.Length != 2) && _destination != null) | |
228 gTypes = TypeHelper.GetGenericArguments(_destination.ParameterType, typeof(IDictionary)); | |
229 | |
230 if (gTypes != null && gTypes.Length == 2) | |
231 { | |
232 keyType = gTypes[0]; | |
233 elementType = gTypes[1]; | |
234 } | |
235 | |
236 if (elementType == null || _explicitObjectType) | |
237 elementType = _objectType; | |
238 | |
239 if (elementType == null || elementType == typeof(object)) | |
240 ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType); | |
241 | |
242 bool isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType); | |
243 | |
244 if (keyType != typeof(object) && !isIndex && !TypeHelper.IsScalar(keyType)) | |
245 ThrowTypeBuilderException( | |
246 Resources.DataAccessorBuilder_BadKeyType); | |
247 | |
248 MethodInfo mi = Context.CurrentMethod; | |
249 | |
250 object[] attrs = mi.GetCustomAttributes(typeof(IndexAttribute), true); | |
251 NameOrIndexParameter[] fields = new NameOrIndexParameter[0]; | |
252 | |
253 if (attrs.Length != 0) | |
254 fields = ((IndexAttribute)attrs[0]).Fields; | |
255 | |
256 if (fields.Length > 1 && keyType != typeof(object) && !isIndex) | |
257 ThrowTypeBuilderException( | |
258 Resources.DataAccessor_InvalidKeyType); | |
259 | |
260 if (TypeHelper.IsScalar(elementType)) | |
261 { | |
262 attrs = mi.GetCustomAttributes(typeof(ScalarFieldNameAttribute), true); | |
263 | |
264 if (attrs.Length == 0) | |
265 ThrowTypeBuilderException(Resources.DataAccessorBuilder_ScalarFieldNameMissing); | |
266 | |
267 NameOrIndexParameter scalarField = ((ScalarFieldNameAttribute)attrs[0]).NameOrIndex; | |
268 | |
269 if (fields.Length == 0) | |
270 ExecuteScalarDictionaryWithPK(keyType, scalarField, elementType); | |
271 else if (isIndex || fields.Length > 1) | |
272 ExecuteScalarDictionaryWithMapIndex(fields, scalarField, elementType); | |
273 else | |
274 ExecuteScalarDictionaryWithScalarKey(fields[0], keyType, scalarField, elementType); | |
275 } | |
276 else | |
277 { | |
278 if (!_explicitObjectType && ActualTypes.ContainsKey(elementType)) | |
279 elementType = ActualTypes[elementType]; | |
280 | |
281 if (fields.Length == 0) | |
282 ExecuteDictionaryWithPK(keyType, elementType); | |
283 else if (isIndex || fields.Length > 1) | |
284 ExecuteDictionaryWithMapIndex(fields, elementType); | |
285 else | |
286 ExecuteDictionaryWithScalarKey(fields[0], elementType); | |
287 } | |
288 } | |
289 | |
290 break; | |
291 | |
292 default: | |
293 | |
294 if (_objectType == null || !TypeHelper.IsSameOrParent(returnType, _objectType)) | |
295 _objectType = returnType; | |
296 | |
297 if (!_explicitObjectType && ActualTypes.ContainsKey(_objectType)) | |
298 _objectType = ActualTypes[_objectType]; | |
299 | |
300 ExecuteObject(); | |
301 | |
302 break; | |
303 } | |
304 | |
305 GetOutRefParameters(); | |
306 | |
307 if (rt != ReturnType.Enumerable) | |
308 Finally(); | |
309 } | |
310 | |
311 protected override void BuildAbstractGetter() | |
312 { | |
313 BuildAbstractMethod(); | |
314 } | |
315 | |
316 protected override void BuildAbstractSetter() | |
317 { | |
318 BuildAbstractMethod(); | |
319 } | |
320 | |
321 void GetSqlQueryAttribute() | |
322 { | |
323 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(SqlQueryAttribute), true); | |
324 | |
325 if (attrs.Length != 0) | |
326 _sqlQueryAttribute = (SqlQueryAttribute)attrs[0]; | |
327 } | |
328 | |
329 void AddParameter(ParameterInfo pi) | |
330 { | |
331 Type pType = pi.ParameterType; | |
332 | |
333 if (pType.IsByRef) | |
334 pType = pType.GetElementType(); | |
335 | |
336 if (TypeHelper.IsScalar(pType) | |
337 #if FW4 | |
338 || pi.IsRefCursor() | |
339 #endif | |
340 ) | |
341 _paramList.Add(pi); | |
342 else if (pType == typeof(DbManager) || pType.IsSubclassOf(typeof(DbManager))) | |
343 _createManager = false; | |
344 else | |
345 _refParamList.Add(pi); | |
346 } | |
347 | |
348 void ProcessParameters() | |
349 { | |
350 for (int i = 0; i < _parameters.Length; i++) | |
351 { | |
352 ParameterInfo pi = _parameters[i]; | |
353 NoMapAttribute[] attrs = (NoMapAttribute[])pi.GetCustomAttributes(typeof(NoMapAttribute), true); | |
354 | |
355 if (attrs.Length == 0) | |
356 AddParameter(pi); | |
357 else | |
358 { | |
359 for (int j = 0; j < attrs.Length; ++j) | |
360 { | |
361 if (!attrs[j].NoMap) | |
362 AddParameter(pi); | |
363 | |
364 if (attrs[j] is FormatAttribute) | |
365 { | |
366 int index = ((FormatAttribute)attrs[j]).Index; | |
367 | |
368 if (index < 0) | |
369 index = 0; | |
370 else if (index > _formatParamList.Count) | |
371 index = _formatParamList.Count; | |
372 | |
373 _formatParamList.Insert(index, pi); | |
374 } | |
375 else if (attrs[j] is DestinationAttribute) | |
376 { | |
377 if (_destination != null) | |
378 throw new TypeBuilderException(Resources.DataAccessorBuilderTooManyDestinations); | |
379 | |
380 _destination = pi; | |
381 } | |
382 } | |
383 } | |
384 } | |
385 } | |
386 | |
387 void CreateDbManager(bool beginException) | |
388 { | |
389 EmitHelper emit = Context.MethodBuilder.Emitter; | |
390 | |
391 if (_createManager) | |
392 { | |
393 emit | |
394 .ldarg_0 | |
395 .callvirt(_baseType, "GetDbManager") | |
396 .stloc(_locManager); | |
397 | |
398 if (beginException) | |
399 emit.BeginExceptionBlock(); | |
400 } | |
401 else | |
402 { | |
403 for (int i = 0; i < _parameters.Length; i++) | |
404 { | |
405 Type pType = _parameters[i].ParameterType; | |
406 | |
407 if (pType == typeof(DbManager) || pType.IsSubclassOf(typeof(DbManager))) | |
408 { | |
409 emit | |
410 .ldarg(_parameters[i]) | |
411 .stloc(_locManager) | |
412 ; | |
413 | |
414 break; | |
415 } | |
416 } | |
417 } | |
418 } | |
419 | |
420 void SetObjectType() | |
421 { | |
422 var mi = Context.CurrentMethod; | |
423 var attrs = mi.GetCustomAttributes(typeof(ObjectTypeAttribute), true); | |
424 | |
425 if (attrs.Length == 0) | |
426 attrs = mi.DeclaringType.GetCustomAttributes(typeof(ObjectTypeAttribute), true); | |
427 else | |
428 _explicitObjectType = true; | |
429 | |
430 if (attrs.Length != 0) | |
431 _objectType = ((ObjectTypeAttribute)attrs[0]).ObjectType; | |
432 | |
433 if (_objectType == null) | |
434 { | |
435 var types = TypeHelper.GetGenericArguments(mi.DeclaringType, typeof(DataAccessor)); | |
436 | |
437 if (types != null) | |
438 _objectType = types[0]; | |
439 } | |
440 } | |
441 | |
442 #region ExecuteReader | |
443 | |
444 void ExecuteReader() | |
445 { | |
446 InitObjectType(); | |
447 GetSprocNameOrSqlQueryTest(); | |
448 CallSetCommand(); | |
449 | |
450 var attrs = Context.CurrentMethod.GetCustomAttributes(typeof(CommandBehaviorAttribute), true); | |
451 | |
452 if (attrs.Length == 0) | |
453 { | |
454 Context.MethodBuilder.Emitter | |
455 .callvirt(typeof(DbManager).GetMethod("ExecuteReader", Type.EmptyTypes)) | |
456 .stloc(Context.ReturnValue) | |
457 ; | |
458 } | |
459 else | |
460 { | |
461 Context.MethodBuilder.Emitter | |
462 .ldc_i4_((int)((CommandBehaviorAttribute)attrs[0]).CommandBehavior) | |
463 .callvirt(typeof(DbManager), "ExecuteReader", typeof(CommandBehavior)) | |
464 .stloc(Context.ReturnValue) | |
465 ; | |
466 } | |
467 } | |
468 | |
469 #endregion | |
470 | |
471 #region ExecuteDataSet | |
472 | |
473 void ExecuteDataSet(Type returnType) | |
474 { | |
475 CreateReturnTypeInstance(); | |
476 InitObjectType(); | |
477 GetSprocNameOrSqlQueryTest(); | |
478 CallSetCommand(); | |
479 | |
480 var emit = Context.MethodBuilder.Emitter; | |
481 | |
482 if (returnType == typeof(DataSet)) | |
483 { | |
484 LoadDestinationOrReturnValue(); | |
485 | |
486 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true); | |
487 | |
488 if (attrs.Length == 0) | |
489 { | |
490 emit | |
491 .callvirt(typeof(DbManager), "ExecuteDataSet", typeof(DataSet)) | |
492 .pop | |
493 .end() | |
494 ; | |
495 } | |
496 else | |
497 { | |
498 emit | |
499 .ldNameOrIndex(((DataSetTableAttribute)attrs[0]).NameOrIndex) | |
500 .callvirt(typeof(DbManager), "ExecuteDataSet", typeof(DataSet), typeof(NameOrIndexParameter)) | |
501 .pop | |
502 .end() | |
503 ; | |
504 } | |
505 } | |
506 else | |
507 { | |
508 emit | |
509 .pop | |
510 .end() | |
511 ; | |
512 | |
513 LoadDestinationOrReturnValue(); | |
514 | |
515 Label l1 = emit.DefineLabel(); | |
516 Label l2 = emit.DefineLabel(); | |
517 | |
518 emit | |
519 .callvirt(typeof(DataSet).GetProperty("Tables").GetGetMethod()) | |
520 .callvirt(typeof(InternalDataCollectionBase).GetProperty("Count").GetGetMethod()) | |
521 .ldc_i4_0 | |
522 .ble_s(l1) | |
523 .ldloc(_locManager); | |
524 | |
525 LoadDestinationOrReturnValue(); | |
526 | |
527 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true); | |
528 | |
529 if (attrs.Length == 0) | |
530 { | |
531 LoadDestinationOrReturnValue(); | |
532 | |
533 emit | |
534 .callvirt(typeof(DataSet).GetProperty("Tables").GetGetMethod()) | |
535 .ldc_i4_0 | |
536 .callvirt(typeof(DataTableCollection), "get_Item", typeof(int)) | |
537 .callvirt(typeof(DataTable).GetProperty("TableName").GetGetMethod()) | |
538 .call(typeof(NameOrIndexParameter), "op_Implicit", typeof(string)) | |
539 ; | |
540 } | |
541 else | |
542 { | |
543 emit | |
544 .ldNameOrIndex(((DataSetTableAttribute)attrs[0]).NameOrIndex) | |
545 ; | |
546 } | |
547 | |
548 emit | |
549 .callvirt(typeof(DbManager), "ExecuteDataSet", typeof(DataSet), typeof(NameOrIndexParameter)) | |
550 .pop | |
551 .br_s(l2) | |
552 .MarkLabel(l1) | |
553 .ldloc(_locManager); | |
554 | |
555 LoadDestinationOrReturnValue(); | |
556 | |
557 emit | |
558 .callvirt(typeof(DbManager), "ExecuteDataSet", typeof(DataSet)) | |
559 .pop | |
560 .MarkLabel(l2) | |
561 ; | |
562 } | |
563 } | |
564 | |
565 #endregion | |
566 | |
567 #region ExecuteDataTable | |
568 | |
569 void ExecuteDataTable() | |
570 { | |
571 CreateReturnTypeInstance(); | |
572 InitObjectType(); | |
573 GetSprocNameOrSqlQueryTest(); | |
574 CallSetCommand(); | |
575 LoadDestinationOrReturnValue(); | |
576 | |
577 EmitHelper emit = Context.MethodBuilder.Emitter; | |
578 | |
579 emit | |
580 .callvirt(typeof(DbManager), "ExecuteDataTable", typeof(DataTable)) | |
581 .pop | |
582 .end() | |
583 ; | |
584 | |
585 // When DataSetTableAttribute is present, simply set table name to the name specified. | |
586 // | |
587 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true); | |
588 | |
589 if (attrs.Length != 0) | |
590 { | |
591 DataSetTableAttribute attr = (DataSetTableAttribute)attrs[0]; | |
592 | |
593 if (!attr.NameOrIndex.ByName) | |
594 throw new TypeBuilderException(string.Format( | |
595 Resources.DataAccessorBuilder_DataSetTableMustBeByName, | |
596 Context.CurrentMethod.DeclaringType.Name, Context.CurrentMethod.Name)); | |
597 | |
598 LoadDestinationOrReturnValue(); | |
599 | |
600 emit | |
601 .ldstr(attr.NameOrIndex.Name) | |
602 .callvirt(typeof(DataTable), "set_TableName", typeof(string)) | |
603 ; | |
604 } | |
605 } | |
606 | |
607 #endregion | |
608 | |
609 #region ExecuteScalarList | |
610 | |
611 void ExecuteScalarList() | |
612 { | |
613 CreateReturnTypeInstance(); | |
614 InitObjectType(); | |
615 GetSprocNameOrSqlQueryTest(); | |
616 CallSetCommand(); | |
617 LoadDestinationOrReturnValue(); | |
618 | |
619 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ScalarFieldNameAttribute), true); | |
620 | |
621 if (attrs.Length == 0) | |
622 { | |
623 Context.MethodBuilder.Emitter | |
624 .ldloc(_locObjType) | |
625 .callvirt(typeof(DbManager), "ExecuteScalarList", typeof(IList), typeof(Type)) | |
626 .pop | |
627 .end() | |
628 ; | |
629 } | |
630 else | |
631 { | |
632 Context.MethodBuilder.Emitter | |
633 .ldloc(_locObjType) | |
634 .ldNameOrIndex(((ScalarFieldNameAttribute)attrs[0]).NameOrIndex) | |
635 .callvirt(typeof(DbManager), "ExecuteScalarList", typeof(IList), typeof(Type), typeof(NameOrIndexParameter)) | |
636 .pop | |
637 .end() | |
638 ; | |
639 } | |
640 } | |
641 | |
642 void ExecuteList() | |
643 { | |
644 CreateReturnTypeInstance(); | |
645 InitObjectType(); | |
646 GetSprocNameOrSqlQueryTest(); | |
647 CallSetCommand(); | |
648 LoadDestinationOrReturnValue(); | |
649 | |
650 Context.MethodBuilder.Emitter | |
651 .CastIfNecessary(typeof(IList), MethodReturnType) | |
652 .ldloc(_locObjType) | |
653 .callvirt(typeof(DbManager), "ExecuteList", typeof(IList), typeof(Type)) | |
654 .pop | |
655 .end() | |
656 ; | |
657 } | |
658 | |
659 #endregion | |
660 | |
661 #region ExecuteDictionary | |
662 | |
663 public FieldBuilder GetIndexField(NameOrIndexParameter[] namesOrIndexes) | |
664 { | |
665 var id = "index$" + string.Join("%", | |
666 Array.ConvertAll<NameOrIndexParameter, string>(namesOrIndexes, | |
667 delegate(NameOrIndexParameter nameOrIndex) | |
668 { | |
669 return nameOrIndex.ToString(); | |
670 })); | |
671 | |
672 var fieldBuilder = Context.GetField(id); | |
673 | |
674 if (fieldBuilder == null) | |
675 { | |
676 fieldBuilder = Context.CreatePrivateStaticField(id, typeof(MapIndex)); | |
677 | |
678 EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter; | |
679 | |
680 emit | |
681 .ldc_i4_(namesOrIndexes.Length) | |
682 .newarr(typeof(NameOrIndexParameter)) | |
683 ; | |
684 | |
685 for (int i = 0; i < namesOrIndexes.Length; i++) | |
686 { | |
687 emit | |
688 .dup | |
689 .ldc_i4_(i) | |
690 .ldelema(typeof(NameOrIndexParameter)); | |
691 | |
692 if (namesOrIndexes[i].ByName) | |
693 { | |
694 emit | |
695 .ldstr(namesOrIndexes[i].Name) | |
696 .call(typeof(NameOrIndexParameter), "op_Implicit", typeof(string)); | |
697 } | |
698 else | |
699 { | |
700 emit | |
701 .ldc_i4_(namesOrIndexes[i].Index) | |
702 .call(typeof(NameOrIndexParameter), "op_Implicit", typeof(int)); | |
703 } | |
704 | |
705 emit | |
706 .stobj(typeof(NameOrIndexParameter)) | |
707 .end() | |
708 ; | |
709 } | |
710 | |
711 emit | |
712 .newobj(typeof(MapIndex), typeof(NameOrIndexParameter[])) | |
713 .stsfld(fieldBuilder) | |
714 ; | |
715 } | |
716 | |
717 return fieldBuilder; | |
718 } | |
719 | |
720 /// <summary> | |
721 /// Maps primary keys(s) to a scalar field. | |
722 /// </summary> | |
723 void ExecuteScalarDictionaryWithPK( | |
724 Type keyType, | |
725 NameOrIndexParameter scalarField, | |
726 Type elementType) | |
727 { | |
728 CreateReturnTypeInstance(); | |
729 InitObjectType(); | |
730 | |
731 Context.MethodBuilder.Emitter | |
732 .ldarg_0 | |
733 .end() | |
734 ; | |
735 | |
736 GetSprocNameOrSqlQueryTest(); | |
737 CallSetCommand(); | |
738 LoadDestinationOrReturnValue(); | |
739 | |
740 Context.MethodBuilder.Emitter | |
741 .ldloc(_locObjType) | |
742 .LoadType(keyType) | |
743 .ldstr(Context.CurrentMethod.Name) | |
744 .ldNameOrIndex(scalarField) | |
745 .LoadType(elementType) | |
746 .callvirt(_baseType, "ExecuteScalarDictionary", _bindingFlags, | |
747 typeof(DbManager), typeof(IDictionary), typeof(Type), | |
748 typeof(Type), typeof(string), typeof(NameOrIndexParameter), typeof(Type)) | |
749 ; | |
750 } | |
751 | |
752 /// <summary> | |
753 /// Maps a complex index to a scalar field. | |
754 /// </summary> | |
755 void ExecuteScalarDictionaryWithMapIndex( | |
756 NameOrIndexParameter[] index, | |
757 NameOrIndexParameter scalarField, | |
758 Type elementType) | |
759 { | |
760 _objectType = elementType; | |
761 | |
762 CreateReturnTypeInstance(); | |
763 InitObjectType(); | |
764 GetSprocNameOrSqlQueryTest(); | |
765 CallSetCommand(); | |
766 LoadDestinationOrReturnValue(); | |
767 | |
768 Context.MethodBuilder.Emitter | |
769 .ldsfld(GetIndexField(index)) | |
770 .ldNameOrIndex(scalarField) | |
771 .ldloc(_locObjType) | |
772 .callvirt(typeof(DbManager), "ExecuteScalarDictionary", | |
773 typeof(IDictionary), typeof(MapIndex), | |
774 typeof(NameOrIndexParameter), typeof(Type)) | |
775 .pop | |
776 .end() | |
777 ; | |
778 } | |
779 | |
780 /// <summary> | |
781 /// Maps any single field to any (other) single field. | |
782 /// </summary> | |
783 void ExecuteScalarDictionaryWithScalarKey( | |
784 NameOrIndexParameter keyField, Type keyType, | |
785 NameOrIndexParameter scalarField, Type elementType) | |
786 { | |
787 _objectType = elementType; | |
788 | |
789 CreateReturnTypeInstance(); | |
790 InitObjectType(); | |
791 GetSprocNameOrSqlQueryTest(); | |
792 CallSetCommand(); | |
793 LoadDestinationOrReturnValue(); | |
794 | |
795 Context.MethodBuilder.Emitter | |
796 .ldNameOrIndex(keyField) | |
797 .LoadType(keyType) | |
798 .ldNameOrIndex(scalarField) | |
799 .ldloc(_locObjType) | |
800 .callvirt(typeof(DbManager), "ExecuteScalarDictionary", | |
801 typeof(IDictionary), typeof(NameOrIndexParameter), typeof(Type), | |
802 typeof(NameOrIndexParameter), typeof(Type)) | |
803 .pop | |
804 .end() | |
805 ; | |
806 } | |
807 | |
808 /// <summary> | |
809 /// Maps primary keys(s) to an object of the specified type. | |
810 /// </summary> | |
811 void ExecuteDictionaryWithPK( | |
812 Type keyType, | |
813 Type elementType) | |
814 { | |
815 EmitHelper emit = Context.MethodBuilder.Emitter; | |
816 | |
817 _objectType = elementType; | |
818 | |
819 CreateReturnTypeInstance(); | |
820 InitObjectType(); | |
821 | |
822 emit | |
823 .ldarg_0 | |
824 .end() | |
825 ; | |
826 | |
827 GetSprocNameOrSqlQueryTest(); | |
828 CallSetCommand(); | |
829 LoadDestinationOrReturnValue(); | |
830 | |
831 if (IsGenericDestinationOrReturnValue()) | |
832 { | |
833 Type[] genericArgs = Context.ReturnValue.LocalType.GetGenericArguments(); | |
834 Type[] types = new Type[] | |
835 { | |
836 typeof(DbManager), | |
837 typeof(IDictionary<,>).MakeGenericType(genericArgs), | |
838 typeof(Type), | |
839 typeof(string), | |
840 }; | |
841 MethodInfo method = _baseType.GetMethod("ExecuteDictionary", | |
842 _bindingFlags, GenericBinder.Generic, types, null); | |
843 | |
844 if (TypeHelper.IsSameOrParent(typeof(CompoundValue), genericArgs[0])) | |
845 method = method.MakeGenericMethod(genericArgs[1]); | |
846 else | |
847 method = method.MakeGenericMethod(genericArgs); | |
848 | |
849 emit | |
850 .ldloc(_locObjType) | |
851 .ldstr(Context.CurrentMethod.Name) | |
852 .callvirt(method) | |
853 ; | |
854 } | |
855 else | |
856 | |
857 emit | |
858 .ldloc(_locObjType) | |
859 .LoadType(keyType) | |
860 .ldstr(Context.CurrentMethod.Name) | |
861 .callvirt(_baseType, "ExecuteDictionary", _bindingFlags, | |
862 typeof(DbManager), typeof(IDictionary), typeof(Type), | |
863 typeof(Type), typeof(string)) | |
864 ; | |
865 } | |
866 | |
867 /// <summary> | |
868 /// Maps a complex index to an object of the specified type. | |
869 /// </summary> | |
870 void ExecuteDictionaryWithMapIndex( | |
871 NameOrIndexParameter[] index, | |
872 Type elementType) | |
873 { | |
874 _objectType = elementType; | |
875 | |
876 CreateReturnTypeInstance(); | |
877 InitObjectType(); | |
878 GetSprocNameOrSqlQueryTest(); | |
879 CallSetCommand(); | |
880 LoadDestinationOrReturnValue(); | |
881 | |
882 Context.MethodBuilder.Emitter | |
883 .ldsfld(GetIndexField(index)) | |
884 .ldloc(_locObjType) | |
885 .ldnull | |
886 .callvirt(typeof(DbManager), "ExecuteDictionary", | |
887 typeof(IDictionary), typeof(MapIndex), typeof(Type), typeof(object[])) | |
888 .pop | |
889 .end() | |
890 ; | |
891 } | |
892 | |
893 /// <summary> | |
894 /// Maps any single field to object type. | |
895 /// </summary> | |
896 void ExecuteDictionaryWithScalarKey( | |
897 NameOrIndexParameter keyField, | |
898 Type elementType) | |
899 { | |
900 EmitHelper emit = Context.MethodBuilder.Emitter; | |
901 | |
902 _objectType = elementType; | |
903 | |
904 CreateReturnTypeInstance(); | |
905 InitObjectType(); | |
906 GetSprocNameOrSqlQueryTest(); | |
907 CallSetCommand(); | |
908 LoadDestinationOrReturnValue(); | |
909 | |
910 if (IsGenericDestinationOrReturnValue()) | |
911 { | |
912 Type[] genericArgs = Context.ReturnValue.LocalType.GetGenericArguments(); | |
913 Type[] types = new Type[] | |
914 { | |
915 typeof(IDictionary<,>).MakeGenericType(genericArgs), | |
916 typeof(NameOrIndexParameter), | |
917 typeof(Type), | |
918 typeof(object[]), | |
919 }; | |
920 MethodInfo method = typeof(DbManager).GetMethod("ExecuteDictionary", _bindingFlags, GenericBinder.Generic, types, null) | |
921 .MakeGenericMethod(genericArgs); | |
922 | |
923 emit | |
924 .ldNameOrIndex(keyField) | |
925 .ldloc(_locObjType) | |
926 .ldnull | |
927 .callvirt(method) | |
928 .pop | |
929 .end() | |
930 ; | |
931 } | |
932 else | |
933 { | |
934 emit | |
935 .ldNameOrIndex(keyField) | |
936 .ldloc(_locObjType) | |
937 .ldnull | |
938 .callvirt(typeof(DbManager), "ExecuteDictionary", typeof(IDictionary), typeof(NameOrIndexParameter), typeof(Type), typeof(object[])) | |
939 .pop | |
940 .end() | |
941 ; | |
942 } | |
943 } | |
944 | |
945 #endregion | |
946 | |
947 #region ExecuteEnumerable | |
948 | |
949 public void ExecuteEnumerable() | |
950 { | |
951 EmitHelper emit = Context.MethodBuilder.Emitter; | |
952 Type returnType = Context.CurrentMethod.ReturnType; | |
953 | |
954 if (_objectType == null && returnType.IsGenericType) | |
955 _objectType = returnType.GetGenericArguments()[0]; | |
956 | |
957 if (_objectType == null || _objectType == typeof(object)) | |
958 ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType); | |
959 | |
960 Type returnObjectType = returnType.IsGenericType ? returnType.GetGenericArguments()[0] : _objectType; | |
961 | |
962 InitObjectType(); | |
963 | |
964 Context.MethodBuilder.Emitter | |
965 .ldarg_0 | |
966 .end() | |
967 ; | |
968 | |
969 GetSprocNameOrSqlQueryTest(); | |
970 CallSetCommand(); | |
971 | |
972 Type[] genericArgs = new Type[] { returnObjectType }; | |
973 Type[] types = new Type[] { typeof(DbManager), typeof(Type), typeof(bool), }; | |
974 MethodInfo method = _baseType | |
975 .GetMethod("ExecuteEnumerable", _bindingFlags, GenericBinder.Generic, types, null) | |
976 .MakeGenericMethod(genericArgs); | |
977 | |
978 emit | |
979 .LoadType(_objectType) | |
980 .ldc_i4_1 | |
981 .callvirt(method) | |
982 .stloc(Context.ReturnValue) | |
983 ; | |
984 } | |
985 | |
986 #endregion | |
987 | |
988 #region ExecuteNonQuery | |
989 | |
990 public void ExecuteNonQuery() | |
991 { | |
992 if (_destination != null) | |
993 throw new TypeBuilderException(Resources.DataAccessorBuilder_CantExecuteNonQueryToDestination); | |
994 | |
995 InitObjectType(); | |
996 GetSprocNameOrSqlQueryTest(); | |
997 CallSetCommand(); | |
998 | |
999 MethodInfo mi = typeof(DbManager).GetMethod("ExecuteNonQuery", Type.EmptyTypes); | |
1000 LocalBuilder locExec = Context.MethodBuilder.Emitter.DeclareLocal(mi.ReturnType); | |
1001 | |
1002 Context.MethodBuilder.Emitter | |
1003 .callvirt(mi) | |
1004 .stloc(locExec) | |
1005 ; | |
1006 | |
1007 if (Context.ReturnValue != null) | |
1008 { | |
1009 Context.MethodBuilder.Emitter | |
1010 .ldloc(locExec) | |
1011 .stloc(Context.ReturnValue) | |
1012 ; | |
1013 } | |
1014 } | |
1015 | |
1016 #endregion | |
1017 | |
1018 #region ExecuteScalar | |
1019 | |
1020 public void ExecuteScalar() | |
1021 { | |
1022 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1023 Type returnType = Context.CurrentMethod.ReturnType; | |
1024 Type scalarType; | |
1025 | |
1026 if (_destination != null) | |
1027 { | |
1028 if (_destination.ParameterType.IsByRef) | |
1029 scalarType = _destination.ParameterType.GetElementType(); | |
1030 else | |
1031 throw new TypeBuilderException(Resources.DataAccessorBuilder_ScalarDestinationIsNotByRef); | |
1032 | |
1033 if (returnType != typeof(void) && !TypeHelper.IsSameOrParent(returnType, scalarType)) | |
1034 { | |
1035 // object Foo(out int num) is valid, | |
1036 // IConvertible Foo(ref int num) is also ok, | |
1037 // but string Bar(out DateTime dt) is not | |
1038 // | |
1039 throw new TypeBuilderException(string.Format( | |
1040 Resources.DataAccessorBuilder_IncompatibleDestinationType, | |
1041 returnType.FullName, Context.CurrentMethod.Name, scalarType.FullName)); | |
1042 } | |
1043 } | |
1044 else | |
1045 scalarType = returnType; | |
1046 | |
1047 if (_destination != null) | |
1048 emit | |
1049 .ldarg(_destination) | |
1050 ; | |
1051 | |
1052 emit | |
1053 .ldarg_0 | |
1054 .ldloc(_locManager) | |
1055 ; | |
1056 | |
1057 InitObjectType(); | |
1058 GetSprocNameOrSqlQueryTest(); | |
1059 CallSetCommand(); | |
1060 | |
1061 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ScalarSourceAttribute), true); | |
1062 | |
1063 if (attrs.Length == 0) | |
1064 { | |
1065 emit | |
1066 .callvirtNoGenerics(typeof(DbManager), "ExecuteScalar") | |
1067 ; | |
1068 } | |
1069 else | |
1070 { | |
1071 ScalarSourceAttribute attr = (ScalarSourceAttribute)attrs[0]; | |
1072 | |
1073 emit | |
1074 .ldc_i4_((int)attr.ScalarType) | |
1075 .ldNameOrIndex(attr.NameOrIndex) | |
1076 .callvirtNoGenerics(typeof(DbManager), "ExecuteScalar", typeof(ScalarSourceType), typeof(NameOrIndexParameter)); | |
1077 } | |
1078 | |
1079 MethodInfo converter = GetConverterMethod(scalarType); | |
1080 | |
1081 if (converter == null) | |
1082 { | |
1083 emit | |
1084 .LoadType(scalarType) | |
1085 .ldnull | |
1086 .callvirt(_baseType, "ConvertChangeType", _bindingFlags, typeof(DbManager), typeof(object), typeof(Type), typeof(object)) | |
1087 .unboxIfValueType(scalarType) | |
1088 ; | |
1089 | |
1090 } | |
1091 else | |
1092 { | |
1093 emit | |
1094 .ldnull | |
1095 .callvirt(converter) | |
1096 ; | |
1097 } | |
1098 | |
1099 if (_destination != null) | |
1100 { | |
1101 emit | |
1102 .stind(scalarType) | |
1103 ; | |
1104 | |
1105 // The return value and a destination both are present | |
1106 // | |
1107 if (Context.ReturnValue != null) | |
1108 { | |
1109 emit | |
1110 .ldargEx(_destination, false) | |
1111 ; | |
1112 | |
1113 if (scalarType != returnType) | |
1114 emit | |
1115 .boxIfValueType(scalarType) | |
1116 .CastFromObject(returnType) | |
1117 ; | |
1118 | |
1119 emit.stloc(Context.ReturnValue) | |
1120 ; | |
1121 } | |
1122 } | |
1123 else | |
1124 emit | |
1125 .stloc(Context.ReturnValue) | |
1126 ; | |
1127 } | |
1128 | |
1129 #endregion | |
1130 | |
1131 #region ExecuteObject | |
1132 | |
1133 public void ExecuteObject() | |
1134 { | |
1135 InitObjectType(); | |
1136 GetSprocNameOrSqlQueryTest(); | |
1137 CallSetCommand(); | |
1138 | |
1139 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1140 | |
1141 if (_destination != null) | |
1142 { | |
1143 emit | |
1144 .ldarg(_destination) | |
1145 .callvirt(typeof(DbManager), "ExecuteObject", typeof(Object)) | |
1146 ; | |
1147 } | |
1148 else | |
1149 { | |
1150 emit | |
1151 .ldloc(_locObjType) | |
1152 .callvirt(typeof(DbManager), "ExecuteObject", typeof(Type)) | |
1153 ; | |
1154 } | |
1155 | |
1156 if (null != Context.ReturnValue) | |
1157 { | |
1158 emit | |
1159 .castclass(_objectType) | |
1160 .stloc(Context.ReturnValue) | |
1161 ; | |
1162 } | |
1163 else | |
1164 { | |
1165 emit | |
1166 .pop | |
1167 .end() | |
1168 ; | |
1169 } | |
1170 } | |
1171 | |
1172 #endregion | |
1173 | |
1174 void Finally() | |
1175 { | |
1176 if (_createManager) | |
1177 { | |
1178 Context.MethodBuilder.Emitter | |
1179 .BeginFinallyBlock() | |
1180 .ldarg_0 | |
1181 .ldloc(_locManager) | |
1182 .callvirt(_baseType, "Dispose", _bindingFlags, typeof(DbManager)) | |
1183 .EndExceptionBlock() | |
1184 ; | |
1185 } | |
1186 } | |
1187 | |
1188 void CreateReturnTypeInstance() | |
1189 { | |
1190 if (null == Context.ReturnValue) | |
1191 return; | |
1192 | |
1193 if (null != _destination) | |
1194 { | |
1195 Context.MethodBuilder.Emitter | |
1196 .ldarg(_destination) | |
1197 .CastIfNecessary(Context.ReturnValue.LocalType, _destination.ParameterType) | |
1198 .stloc(Context.ReturnValue) | |
1199 ; | |
1200 } | |
1201 else | |
1202 { | |
1203 Type returnType = Context.CurrentMethod.ReturnType; | |
1204 | |
1205 if (returnType.IsInterface) | |
1206 { | |
1207 if (IsInterfaceOf(returnType, typeof(IList))) | |
1208 returnType = typeof(ArrayList); | |
1209 else if (IsInterfaceOf(returnType, typeof(IDictionary))) | |
1210 returnType = typeof(Hashtable); | |
1211 else if (returnType.GetGenericTypeDefinition() == typeof(IList<>)) | |
1212 returnType = typeof(List<>).MakeGenericType(returnType.GetGenericArguments()); | |
1213 else if (returnType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) | |
1214 returnType = typeof(Dictionary<,>).MakeGenericType(returnType.GetGenericArguments()); | |
1215 } | |
1216 | |
1217 ConstructorInfo ci = TypeHelper.GetDefaultConstructor(returnType); | |
1218 | |
1219 if (ci == null) | |
1220 throw new TypeBuilderException(string.Format(Resources.DataAccessorBuilder_CantCreateTypeInstance, | |
1221 Context.CurrentMethod.ReturnType.FullName)); | |
1222 | |
1223 Context.MethodBuilder.Emitter | |
1224 .newobj(ci) | |
1225 .stloc(Context.ReturnValue) | |
1226 ; | |
1227 } | |
1228 } | |
1229 | |
1230 Type MethodReturnType | |
1231 { | |
1232 get | |
1233 { | |
1234 return _destination != null ? | |
1235 _destination.ParameterType : | |
1236 Context.CurrentMethod.ReturnType; | |
1237 } | |
1238 } | |
1239 | |
1240 void LoadDestinationOrReturnValue() | |
1241 { | |
1242 if (_destination != null) | |
1243 Context.MethodBuilder.Emitter.ldarg(_destination); | |
1244 else | |
1245 Context.MethodBuilder.Emitter.ldloc(Context.ReturnValue); | |
1246 } | |
1247 | |
1248 bool IsGenericDestinationOrReturnValue() | |
1249 { | |
1250 return _destination == null ? | |
1251 Context.ReturnValue.LocalType.IsGenericType : | |
1252 _destination.ParameterType.IsGenericType; | |
1253 } | |
1254 | |
1255 void InitObjectType() | |
1256 { | |
1257 Context.MethodBuilder.Emitter | |
1258 .LoadType(_objectType) | |
1259 .stloc(_locObjType) | |
1260 ; | |
1261 } | |
1262 | |
1263 static int _nameCounter; | |
1264 static int _uniqueQueryID; | |
1265 | |
1266 void GetSprocNameOrSqlQueryTest() | |
1267 { | |
1268 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1269 | |
1270 if (_sqlQueryAttribute != null) | |
1271 { | |
1272 emit | |
1273 .ldloc(_locManager) | |
1274 ; | |
1275 | |
1276 if (_sqlQueryAttribute.ID != int.MinValue) | |
1277 { | |
1278 emit | |
1279 .ldarg_0 | |
1280 .ldloc(_locManager) | |
1281 .ldc_i4_(_sqlQueryAttribute.ID) | |
1282 .ldc_i4_(++_uniqueQueryID) | |
1283 ; | |
1284 } | |
1285 | |
1286 if (_sqlQueryAttribute.IsDynamic) | |
1287 { | |
1288 Type attrType = typeof(SqlQueryAttribute); | |
1289 FieldBuilder field = Context.CreatePrivateStaticField(attrType + "$" + ++_nameCounter, attrType); | |
1290 Label isNull = emit.DefineLabel(); | |
1291 | |
1292 emit | |
1293 .ldsfld(field) | |
1294 .brtrue_s(isNull) | |
1295 | |
1296 .ldarg_0 | |
1297 .call(typeof(MethodBase), "GetCurrentMethod") | |
1298 .castclass(typeof(MethodInfo)) | |
1299 .callvirt(_baseType, "GetSqlQueryAttribute", _bindingFlags, typeof(MethodInfo)) | |
1300 | |
1301 .stsfld(field) | |
1302 .MarkLabel(isNull) | |
1303 | |
1304 .ldsfld(field) | |
1305 .ldarg_0 | |
1306 .ldloc(_locManager) | |
1307 .callvirt(attrType, "GetSqlText", _bindingFlags, typeof(DataAccessor), typeof(DbManager)) | |
1308 ; | |
1309 } | |
1310 else | |
1311 { | |
1312 emit | |
1313 .ldstr(_sqlQueryAttribute.SqlText) | |
1314 ; | |
1315 } | |
1316 | |
1317 if (_sqlQueryAttribute.ID != int.MinValue) | |
1318 { | |
1319 emit | |
1320 .callvirt(_baseType, "PrepareSqlQuery", _bindingFlags, | |
1321 typeof(DbManager), typeof(int), typeof(int), typeof(string)) | |
1322 ; | |
1323 } | |
1324 } | |
1325 else | |
1326 { | |
1327 object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(SprocNameAttribute), true); | |
1328 | |
1329 if (attrs.Length == 0) | |
1330 { | |
1331 attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ActionNameAttribute), true); | |
1332 | |
1333 string actionName = attrs.Length == 0 ? | |
1334 Context.CurrentMethod.Name : ((ActionNameAttribute)attrs[0]).Name; | |
1335 | |
1336 // Call GetSpName. | |
1337 // | |
1338 emit | |
1339 .ldloc(_locManager) | |
1340 .ldarg_0 | |
1341 .ldloc(_locObjType) | |
1342 .ldstr(actionName) | |
1343 .callvirt(_baseType, "GetSpName", _bindingFlags, typeof(Type), typeof(string)) | |
1344 ; | |
1345 } | |
1346 else | |
1347 { | |
1348 emit | |
1349 .ldloc(_locManager) | |
1350 .ldstr(((SprocNameAttribute)attrs[0]).Name) | |
1351 ; | |
1352 } | |
1353 } | |
1354 | |
1355 // string.Format | |
1356 // | |
1357 if (_formatParamList.Count > 0) | |
1358 { | |
1359 emit | |
1360 .ldc_i4_(_formatParamList.Count) | |
1361 .newarr(typeof(object)) | |
1362 ; | |
1363 | |
1364 for (int i = 0; i < _formatParamList.Count; i++) | |
1365 { | |
1366 ParameterInfo pi = (ParameterInfo)_formatParamList[i]; | |
1367 | |
1368 emit | |
1369 .dup | |
1370 .ldc_i4_(i) | |
1371 .ldarg(pi) | |
1372 .boxIfValueType(pi.ParameterType) | |
1373 .stelem_ref | |
1374 .end() | |
1375 ; | |
1376 } | |
1377 | |
1378 emit | |
1379 .call(typeof(string), "Format", typeof(string), typeof(object[])) | |
1380 ; | |
1381 } | |
1382 } | |
1383 | |
1384 void CallSetCommand() | |
1385 { | |
1386 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1387 | |
1388 // Get DiscoverParametersAttribute. | |
1389 // | |
1390 object[] attrs = | |
1391 Context.CurrentMethod.DeclaringType.GetCustomAttributes(typeof(DiscoverParametersAttribute), true); | |
1392 | |
1393 bool discoverParams = false; | |
1394 | |
1395 if (_sqlQueryAttribute == null) | |
1396 { | |
1397 discoverParams = attrs.Length == 0 ? | |
1398 false : ((DiscoverParametersAttribute)attrs[0]).Discover; | |
1399 | |
1400 attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DiscoverParametersAttribute), true); | |
1401 | |
1402 if (attrs.Length != 0) | |
1403 discoverParams = ((DiscoverParametersAttribute)attrs[0]).Discover; | |
1404 } | |
1405 | |
1406 LocalBuilder locParams = discoverParams ? | |
1407 BuildParametersWithDiscoverParameters() : | |
1408 BuildParameters(); | |
1409 | |
1410 // Call SetSpCommand. | |
1411 // | |
1412 string methodName = _sqlQueryAttribute == null ? "SetSpCommand" : "SetCommand"; | |
1413 Type paramType = _sqlQueryAttribute == null ? typeof(object[]) : typeof(IDbDataParameter[]); | |
1414 | |
1415 emit | |
1416 .ldloc(locParams) | |
1417 .callvirt(typeof(DbManager), methodName, _bindingFlags, typeof(string), paramType) | |
1418 ; | |
1419 } | |
1420 | |
1421 LocalBuilder BuildParameters() | |
1422 { | |
1423 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1424 | |
1425 LocalBuilder retParams = emit | |
1426 .DeclareLocal(typeof(IDbDataParameter[])); | |
1427 | |
1428 LocalBuilder locParams = _refParamList.Count > 0 ? | |
1429 BuildRefParameters() : | |
1430 BuildSimpleParameters(); | |
1431 | |
1432 emit | |
1433 .ldarg_0 | |
1434 .ldloc(_locManager) | |
1435 .ldloc(locParams) | |
1436 .callvirt(_baseType, "PrepareParameters", _bindingFlags, typeof(DbManager), typeof(object[])) | |
1437 .stloc(retParams) | |
1438 ; | |
1439 | |
1440 return retParams; | |
1441 } | |
1442 | |
1443 LocalBuilder BuildSimpleParameters() | |
1444 { | |
1445 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1446 | |
1447 // Parameters. | |
1448 // | |
1449 LocalBuilder locParams = emit.DeclareLocal( | |
1450 _sqlQueryAttribute == null ? typeof(object[]) : typeof(IDbDataParameter[])); | |
1451 | |
1452 emit | |
1453 .ldc_i4_(_paramList.Count) | |
1454 .newarr(_sqlQueryAttribute == null ? typeof(object) : typeof(IDbDataParameter)) | |
1455 ; | |
1456 | |
1457 for (int i = 0; i < _paramList.Count; i++) | |
1458 { | |
1459 ParameterInfo pi = (ParameterInfo)_paramList[i]; | |
1460 | |
1461 emit | |
1462 .dup | |
1463 .ldc_i4_(i) | |
1464 ; | |
1465 | |
1466 BuildParameter(pi); | |
1467 | |
1468 emit | |
1469 .stelem_ref | |
1470 .end() | |
1471 ; | |
1472 } | |
1473 | |
1474 emit.stloc(locParams); | |
1475 return locParams; | |
1476 } | |
1477 | |
1478 FieldBuilder CreateStringArrayField(object[] attrs) | |
1479 { | |
1480 if (attrs.Length == 0) | |
1481 return null; | |
1482 | |
1483 List<string> list = new List<string>(); | |
1484 | |
1485 foreach (Direction attr in attrs) | |
1486 if (attr.Members != null) | |
1487 list.AddRange(attr.Members); | |
1488 | |
1489 if (list.Count == 0) | |
1490 return null; | |
1491 | |
1492 list.Sort(string.CompareOrdinal); | |
1493 | |
1494 string[] strings = list.ToArray(); | |
1495 | |
1496 // There a no limit for a field name length, but Visual Studio Debugger | |
1497 // may crash on fields with name longer then 256 symbols. | |
1498 // | |
1499 string key = "_string_array$" + string.Join("%", strings); | |
1500 FieldBuilder fieldBuilder = Context.GetField(key); | |
1501 | |
1502 if (null == fieldBuilder) | |
1503 { | |
1504 fieldBuilder = Context.CreatePrivateStaticField(key, typeof(string[])); | |
1505 | |
1506 EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter; | |
1507 | |
1508 emit | |
1509 .ldc_i4_(strings.Length) | |
1510 .newarr(typeof(string)) | |
1511 ; | |
1512 | |
1513 for (int i = 0; i < strings.Length; i++) | |
1514 { | |
1515 emit | |
1516 .dup | |
1517 .ldc_i4_(i) | |
1518 .ldstr(strings[i]) | |
1519 .stelem_ref | |
1520 .end() | |
1521 ; | |
1522 } | |
1523 | |
1524 emit | |
1525 .stsfld(fieldBuilder) | |
1526 ; | |
1527 } | |
1528 | |
1529 return fieldBuilder; | |
1530 } | |
1531 | |
1532 FieldBuilder CreateNullValueField(Type type, string value) | |
1533 { | |
1534 string key = "_null_value$" + type.FullName + "%" + value; | |
1535 FieldBuilder fieldBuilder = Context.GetField(key); | |
1536 | |
1537 if (null == fieldBuilder) | |
1538 { | |
1539 fieldBuilder = Context.CreatePrivateStaticField(key, type); | |
1540 | |
1541 EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter; | |
1542 | |
1543 emit | |
1544 .LoadType(type) | |
1545 .call(typeof(TypeDescriptor), "GetConverter", typeof(Type)) | |
1546 .ldstr(value) | |
1547 .callvirt(typeof(TypeConverter), "ConvertFromInvariantString", typeof(string)) | |
1548 .unbox_any(type) | |
1549 .stsfld(fieldBuilder) | |
1550 ; | |
1551 } | |
1552 | |
1553 return fieldBuilder; | |
1554 } | |
1555 | |
1556 LocalBuilder BuildRefParameters() | |
1557 { | |
1558 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1559 | |
1560 // Parameters. | |
1561 // | |
1562 LocalBuilder locParams = emit.DeclareLocal(typeof(object[])); | |
1563 | |
1564 emit | |
1565 .ldc_i4_(_parameters.Length) | |
1566 .newarr(typeof(object)) | |
1567 ; | |
1568 | |
1569 for (int i = 0; i < _parameters.Length; i++) | |
1570 { | |
1571 ParameterInfo pi = _parameters[i]; | |
1572 | |
1573 emit | |
1574 .dup | |
1575 .ldc_i4_(i) | |
1576 ; | |
1577 | |
1578 if (_paramList.Contains(pi)) | |
1579 { | |
1580 BuildParameter(pi); | |
1581 } | |
1582 else if (_refParamList.Contains(pi)) | |
1583 { | |
1584 var mapOutputParameters = false; | |
1585 string returnValueMember = null; | |
1586 FieldBuilder fieldBuilder; | |
1587 var type = | |
1588 pi.ParameterType == typeof(DataRow) || pi.ParameterType.IsSubclassOf(typeof(DataRow)) ? | |
1589 typeof(DataRow) : typeof(object); | |
1590 | |
1591 emit | |
1592 .ldarg_0 | |
1593 .ldloc(_locManager) | |
1594 .ldarg(pi) | |
1595 ; | |
1596 | |
1597 fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.OutputAttribute), true)); | |
1598 | |
1599 if (fieldBuilder != null) | |
1600 { | |
1601 emit.ldsfld(fieldBuilder); | |
1602 mapOutputParameters = true; | |
1603 } | |
1604 else | |
1605 emit.ldnull.end(); | |
1606 | |
1607 fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.InputOutputAttribute), true)); | |
1608 | |
1609 if (fieldBuilder != null) | |
1610 { | |
1611 emit.ldsfld(fieldBuilder); | |
1612 mapOutputParameters = true; | |
1613 } | |
1614 else | |
1615 emit.ldnull.end(); | |
1616 | |
1617 fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.IgnoreAttribute), true)); | |
1618 | |
1619 if (fieldBuilder != null) | |
1620 emit.ldsfld(fieldBuilder); | |
1621 else | |
1622 emit.ldnull.end(); | |
1623 | |
1624 emit | |
1625 .ldnull | |
1626 .callvirt(_baseType, "CreateParameters", _bindingFlags, | |
1627 typeof(DbManager), type, typeof(string[]), typeof(string[]), typeof(string[]), typeof(IDbDataParameter[])) | |
1628 ; | |
1629 | |
1630 object[] attrs = pi.GetCustomAttributes(typeof(Direction.ReturnValueAttribute), true); | |
1631 | |
1632 if (attrs.Length != 0) | |
1633 returnValueMember = ((Direction.ReturnValueAttribute)attrs[0]).Member; | |
1634 | |
1635 if (null != returnValueMember || mapOutputParameters) | |
1636 _mapOutputParameters.Add(new MapOutputParametersValue(returnValueMember, pi)); | |
1637 } | |
1638 else | |
1639 { | |
1640 emit | |
1641 .ldnull | |
1642 .end() | |
1643 ; | |
1644 } | |
1645 | |
1646 emit | |
1647 .stelem_ref | |
1648 .end() | |
1649 ; | |
1650 } | |
1651 | |
1652 emit.stloc(locParams); | |
1653 return locParams; | |
1654 } | |
1655 | |
1656 void LoadParameterOrNull(ParameterInfo pi, Type type) | |
1657 { | |
1658 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1659 object[] attrs = pi.GetCustomAttributes(typeof(ParamNullValueAttribute), true); | |
1660 | |
1661 object nullValue = attrs.Length == 0 ? | |
1662 null : ((ParamNullValueAttribute)attrs[0]).Value; | |
1663 | |
1664 Label labelNull = emit.DefineLabel(); | |
1665 Label labelEndIf = emit.DefineLabel(); | |
1666 | |
1667 if (pi.Attributes == ParameterAttributes.Out) | |
1668 { | |
1669 emit | |
1670 .ldnull | |
1671 .end() | |
1672 ; | |
1673 | |
1674 return; | |
1675 } | |
1676 | |
1677 if (nullValue != null) | |
1678 { | |
1679 Type nullValueType = type; | |
1680 bool isNullable = TypeHelper.IsNullable(type); | |
1681 | |
1682 if (type.IsEnum) | |
1683 { | |
1684 nullValueType = Enum.GetUnderlyingType(type); | |
1685 nullValue = System.Convert.ChangeType(nullValue, nullValueType); | |
1686 } | |
1687 else if (isNullable) | |
1688 { | |
1689 nullValueType = type.GetGenericArguments()[0]; | |
1690 | |
1691 emit | |
1692 .ldarga(pi) | |
1693 .call(type, "get_HasValue") | |
1694 .brfalse(labelNull) | |
1695 ; | |
1696 } | |
1697 | |
1698 if (nullValueType == nullValue.GetType() && emit.LoadWellKnownValue(nullValue)) | |
1699 { | |
1700 if (nullValueType == typeof(string)) | |
1701 emit | |
1702 .ldargEx(pi, false) | |
1703 .call(nullValueType, "Equals", nullValueType) | |
1704 .brtrue(labelNull) | |
1705 ; | |
1706 else if (isNullable) | |
1707 emit | |
1708 .ldarga(pi) | |
1709 .call(type, "get_Value") | |
1710 .beq(labelNull) | |
1711 ; | |
1712 else | |
1713 emit | |
1714 .ldargEx(pi, false) | |
1715 .beq(labelNull) | |
1716 ; | |
1717 } | |
1718 else | |
1719 { | |
1720 string nullString = TypeDescriptor.GetConverter(nullValue).ConvertToInvariantString(nullValue); | |
1721 FieldBuilder staticField = CreateNullValueField(nullValueType, nullString); | |
1722 MethodInfo miEquals = new TypeHelper(nullValueType).GetPublicMethod("Equals", nullValueType); | |
1723 | |
1724 if (miEquals == null) | |
1725 { | |
1726 // Is it possible? | |
1727 // | |
1728 throw new TypeBuilderException(string.Format( | |
1729 Resources.DataAccessorBuilder_EqualsMethodIsNotPublic, type.FullName)); | |
1730 } | |
1731 | |
1732 if (isNullable) | |
1733 emit | |
1734 .ldsflda(staticField) | |
1735 .ldarga(pi) | |
1736 .call(pi.ParameterType, "get_Value") | |
1737 ; | |
1738 else | |
1739 emit | |
1740 .ldsflda(staticField) | |
1741 .ldarg(pi) | |
1742 ; | |
1743 | |
1744 if (miEquals.GetParameters()[0].ParameterType.IsClass) | |
1745 emit | |
1746 .boxIfValueType(nullValueType) | |
1747 ; | |
1748 | |
1749 emit | |
1750 .call(miEquals) | |
1751 .brtrue(labelNull) | |
1752 ; | |
1753 } | |
1754 } | |
1755 | |
1756 if (type.IsEnum) | |
1757 emit | |
1758 .ldloc(_locManager) | |
1759 .callvirt(typeof(DbManager).GetProperty("MappingSchema").GetGetMethod()) | |
1760 ; | |
1761 | |
1762 emit | |
1763 .ldargEx(pi, true) | |
1764 ; | |
1765 | |
1766 if (type.IsEnum) | |
1767 emit | |
1768 .ldc_i4_1 | |
1769 .callvirt(typeof(MappingSchema), "MapEnumToValue", typeof(object), typeof(bool)) | |
1770 ; | |
1771 | |
1772 if (nullValue != null) | |
1773 { | |
1774 emit | |
1775 .br(labelEndIf) | |
1776 .MarkLabel(labelNull) | |
1777 .ldnull | |
1778 .MarkLabel(labelEndIf) | |
1779 ; | |
1780 } | |
1781 } | |
1782 | |
1783 void BuildParameter(ParameterInfo pi) | |
1784 { | |
1785 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1786 Type type = pi.ParameterType; | |
1787 object[] attrs = pi.GetCustomAttributes(typeof(ParamNameAttribute), true); | |
1788 string paramName = attrs.Length == 0 ? pi.Name : ((ParamNameAttribute)attrs[0]).Name; | |
1789 | |
1790 ParameterDirection direction = !type.IsByRef ? ParameterDirection.Input : | |
1791 pi.IsOut ? ParameterDirection.Output : ParameterDirection.InputOutput; | |
1792 | |
1793 emit | |
1794 .ldloc(_locManager) | |
1795 .ldc_i4_((int)direction) | |
1796 ; | |
1797 | |
1798 if (paramName[0] != '@') | |
1799 { | |
1800 string methodName = _sqlQueryAttribute == null ? "GetSpParameterName" : "GetQueryParameterName"; | |
1801 emit | |
1802 .ldarg_0 | |
1803 .ldloc(_locManager) | |
1804 .ldstr(paramName) | |
1805 .callvirt(_baseType, methodName, _bindingFlags, typeof(DbManager), typeof(string)) | |
1806 ; | |
1807 } | |
1808 else | |
1809 emit.ldstr(paramName); | |
1810 | |
1811 if (type.IsByRef) | |
1812 { | |
1813 if (_outputParameters == null) | |
1814 _outputParameters = new ArrayList(); | |
1815 | |
1816 _outputParameters.Add(pi); | |
1817 | |
1818 type = type.GetElementType(); | |
1819 } | |
1820 | |
1821 LoadParameterOrNull(pi, type); | |
1822 | |
1823 // Special case for user-defined types. | |
1824 // | |
1825 attrs = pi.GetCustomAttributes(typeof(ParamTypeNameAttribute), true); | |
1826 if (attrs.Length > 0) | |
1827 { | |
1828 emit | |
1829 .ldstr(((ParamTypeNameAttribute)attrs[0]).TypeName) | |
1830 .callvirt(typeof(DbManager), "Parameter", | |
1831 typeof(ParameterDirection), typeof(string), typeof(object), typeof(string)) | |
1832 ; | |
1833 } | |
1834 else | |
1835 { | |
1836 emit | |
1837 .callvirt(typeof(DbManager), "Parameter", | |
1838 typeof(ParameterDirection), typeof(string), typeof(object)) | |
1839 ; | |
1840 } | |
1841 | |
1842 // Check if parameter type/size is specified. | |
1843 // | |
1844 attrs = pi.GetCustomAttributes(typeof(ParamDbTypeAttribute), true); | |
1845 if (attrs.Length > 0) | |
1846 { | |
1847 emit | |
1848 .dup | |
1849 .ldc_i4_((int)((ParamDbTypeAttribute)attrs[0]).DbType) | |
1850 .callvirt(typeof(IDataParameter), "set_DbType", typeof(DbType)) | |
1851 ; | |
1852 } | |
1853 | |
1854 attrs = pi.GetCustomAttributes(typeof(ParamSizeAttribute), true); | |
1855 if (attrs.Length > 0) | |
1856 { | |
1857 emit | |
1858 .dup | |
1859 .ldc_i4_(((ParamSizeAttribute)attrs[0]).Size) | |
1860 .callvirt(typeof(IDbDataParameter), "set_Size", typeof(int)) | |
1861 ; | |
1862 } | |
1863 } | |
1864 | |
1865 LocalBuilder BuildParametersWithDiscoverParameters() | |
1866 { | |
1867 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1868 LocalBuilder locParams = emit.DeclareLocal(typeof(object[])); | |
1869 | |
1870 emit | |
1871 .ldc_i4_(_paramList.Count) | |
1872 .newarr(typeof(object)) | |
1873 ; | |
1874 | |
1875 for (int i = 0; i < _paramList.Count; i++) | |
1876 { | |
1877 ParameterInfo pi = (ParameterInfo)_paramList[i]; | |
1878 | |
1879 emit | |
1880 .dup | |
1881 .ldc_i4_(i) | |
1882 ; | |
1883 | |
1884 LoadParameterOrNull(pi, pi.ParameterType); | |
1885 | |
1886 emit | |
1887 .stelem_ref | |
1888 .end() | |
1889 ; | |
1890 } | |
1891 | |
1892 emit.stloc(locParams); | |
1893 return locParams; | |
1894 } | |
1895 | |
1896 void StoreParameterValue(LocalBuilder param, ParameterInfo pi, Type type) | |
1897 { | |
1898 EmitHelper emit = Context.MethodBuilder.Emitter; | |
1899 Label labelNull = emit.DefineLabel(); | |
1900 Label labelEndIf = emit.DefineLabel(); | |
1901 | |
1902 object[] attrs = pi.GetCustomAttributes(typeof(ParamNullValueAttribute), true); | |
1903 object nullValue = attrs.Length == 0 ? null : ((ParamNullValueAttribute)attrs[0]).Value; | |
1904 | |
1905 if (nullValue != null) | |
1906 { | |
1907 emit | |
1908 .ldarg_0 | |
1909 .ldloc(_locManager) | |
1910 .ldloc(param) | |
1911 .callvirt(typeof(IDataParameter).GetProperty("Value").GetGetMethod()) | |
1912 .ldloc(param) | |
1913 .callvirt(_baseType, "IsNull", _bindingFlags, typeof(DbManager), typeof(object), typeof(object)) | |
1914 .brtrue(labelNull) | |
1915 ; | |
1916 } | |
1917 | |
1918 if (type.IsEnum) | |
1919 { | |
1920 emit | |
1921 .ldloc(_locManager) | |
1922 .callvirt(typeof(DbManager).GetProperty("MappingSchema").GetGetMethod()) | |
1923 .ldloc(param) | |
1924 .callvirt(typeof(IDataParameter).GetProperty("Value").GetGetMethod()) | |
1925 .LoadType(type) | |
1926 .callvirt(typeof(MappingSchema), "MapValueToEnum", typeof(object), typeof(Type)) | |
1927 .CastFromObject(type) | |
1928 ; | |
1929 } | |
1930 #if FW4 | |
1931 else if (pi.IsRefCursor()) | |
1932 { | |
1933 // Make sure the parameter is a List | |
1934 if (!type.GetInterfaces().Contains(typeof(IList))) | |
1935 { | |
1936 throw new Exception("The argument '" + pi.Name + "' must be of type 'IList'"); | |
1937 } | |
1938 //Get the generic type of the list | |
1939 Type genericType = type.GetGenericArguments().First(); | |
1940 | |
1941 | |
1942 // Get the data reader to the ref cursor | |
1943 var dataReader = emit.DeclareLocal(typeof(IDataReader)); | |
1944 emit | |
1945 .ldloc(_locManager) | |
1946 .callvirt(typeof(DbManager).GetProperty("DataProvider").GetGetMethod()) | |
1947 .ldloc(param) | |
1948 .callvirt(typeof(IDataParameter).GetProperty("Value").GetGetMethod()) | |
1949 .callvirt(typeof(DataProviderBase), "GetRefCursorDataReader", typeof(object)) | |
1950 .CastFromObject(typeof(IDataReader)) | |
1951 .stloc(dataReader) | |
1952 ; | |
1953 | |
1954 // Create the generic methos info to invoke | |
1955 var mapDataReaderToListMethodInfo = typeof (MappingSchema).GetMethod("MapDataReaderToList", | |
1956 new[] | |
1957 { | |
1958 typeof (IDataReader), | |
1959 typeof (object[]) | |
1960 }) | |
1961 .MakeGenericMethod(genericType); | |
1962 | |
1963 // Run MapDataReaderToList | |
1964 emit | |
1965 .ldloc(_locManager) | |
1966 .callvirt(typeof(DbManager).GetProperty("MappingSchema").GetGetMethod()) | |
1967 .ldloc(dataReader) | |
1968 .ldnull | |
1969 .callvirt(mapDataReaderToListMethodInfo) | |
1970 ; | |
1971 } | |
1972 #endif | |
1973 else | |
1974 { | |
1975 emit | |
1976 .ldarg_0 | |
1977 .ldloc(_locManager) | |
1978 .ldloc(param) | |
1979 .callvirt(typeof(IDataParameter).GetProperty("Value").GetGetMethod()) | |
1980 ; | |
1981 | |
1982 MethodInfo converter = GetConverterMethod(type); | |
1983 | |
1984 if (converter == null) | |
1985 { | |
1986 emit | |
1987 .LoadType(type) | |
1988 .ldloc(param) | |
1989 .callvirt(_baseType, "ConvertChangeType", _bindingFlags, typeof(DbManager), typeof(object), typeof(Type), typeof(object)) | |
1990 .unboxIfValueType(type) | |
1991 ; | |
1992 } | |
1993 else | |
1994 { | |
1995 emit | |
1996 .ldloc(param) | |
1997 .callvirt(converter) | |
1998 ; | |
1999 } | |
2000 } | |
2001 | |
2002 if (nullValue != null) | |
2003 { | |
2004 emit | |
2005 .br(labelEndIf) | |
2006 .MarkLabel(labelNull); | |
2007 | |
2008 if (nullValue.GetType() != type || !emit.LoadWellKnownValue(nullValue)) | |
2009 { | |
2010 string nullString = TypeDescriptor.GetConverter(type).ConvertToInvariantString(nullValue); | |
2011 FieldBuilder staticField = CreateNullValueField(type, nullString); | |
2012 | |
2013 emit | |
2014 .ldsfld(staticField) | |
2015 ; | |
2016 } | |
2017 | |
2018 emit | |
2019 .MarkLabel(labelEndIf) | |
2020 ; | |
2021 } | |
2022 | |
2023 emit.stind(type); | |
2024 } | |
2025 | |
2026 void GetOutRefParameters() | |
2027 { | |
2028 EmitHelper emit = Context.MethodBuilder.Emitter; | |
2029 | |
2030 if (_outputParameters != null) | |
2031 { | |
2032 LocalBuilder param = emit.DeclareLocal(typeof(IDataParameter)); | |
2033 | |
2034 foreach (ParameterInfo pi in _outputParameters) | |
2035 { | |
2036 Type type = pi.ParameterType.GetElementType(); | |
2037 | |
2038 emit | |
2039 .ldarg(pi) | |
2040 ; | |
2041 | |
2042 // Get parameter. | |
2043 // | |
2044 object[] attrs = pi.GetCustomAttributes(typeof(ParamNameAttribute), true); | |
2045 | |
2046 string paramName = attrs.Length == 0 ? | |
2047 pi.Name : ((ParamNameAttribute)attrs[0]).Name; | |
2048 | |
2049 emit | |
2050 .ldarg_0 | |
2051 .ldloc(_locManager) | |
2052 ; | |
2053 | |
2054 if (paramName[0] != '@') | |
2055 { | |
2056 string methodName = _sqlQueryAttribute == null ? "GetSpParameterName" : "GetQueryParameterName"; | |
2057 | |
2058 emit | |
2059 .ldarg_0 | |
2060 .ldloc(_locManager) | |
2061 .ldstr(paramName) | |
2062 .callvirt(_baseType, methodName, _bindingFlags, typeof(DbManager), typeof(string)) | |
2063 ; | |
2064 } | |
2065 else | |
2066 emit.ldstr(paramName); | |
2067 | |
2068 emit | |
2069 .callvirt(_baseType, "GetParameter", _bindingFlags, typeof(DbManager), typeof(string)) | |
2070 .stloc(param) | |
2071 ; | |
2072 | |
2073 StoreParameterValue(param, pi, type); | |
2074 } | |
2075 } | |
2076 | |
2077 foreach (MapOutputParametersValue v in _mapOutputParameters) | |
2078 { | |
2079 emit | |
2080 .ldloc(_locManager) | |
2081 .ldstrEx(v.ReturnValueMember) | |
2082 .ldarg(v.ParameterInfo) | |
2083 .callvirt(typeof(DbManager), "MapOutputParameters", typeof(string), typeof(object)); | |
2084 } | |
2085 } | |
2086 | |
2087 static bool IsInterfaceOf(Type type, Type interfaceType) | |
2088 { | |
2089 Type[] types = type.GetInterfaces(); | |
2090 | |
2091 foreach (Type t in types) | |
2092 if (t == interfaceType) | |
2093 return true; | |
2094 | |
2095 return type == interfaceType; | |
2096 } | |
2097 | |
2098 private MethodInfo GetConverterMethod(Type type) | |
2099 { | |
2100 if (type.IsEnum) | |
2101 type = Enum.GetUnderlyingType(type); | |
2102 | |
2103 Type[] types = new Type[] { typeof(DbManager), typeof(object), typeof(object) }; | |
2104 return _baseType.GetMethod("ConvertTo" + type.Name, _bindingFlags, null, types, null); | |
2105 } | |
2106 } | |
2107 } |