using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;
using BLToolkit.Common;
using BLToolkit.Data;
using BLToolkit.Mapping;
using BLToolkit.Properties;
using BLToolkit.Reflection;
using BLToolkit.Reflection.Emit;
using BLToolkit.TypeBuilder;
using BLToolkit.TypeBuilder.Builders;
namespace BLToolkit.DataAccess
{
public class DataAccessorBuilder : AbstractTypeBuilderBase
{
private struct MapOutputParametersValue
{
public readonly string ReturnValueMember;
public readonly ParameterInfo ParameterInfo;
public MapOutputParametersValue(string returnValueMember, ParameterInfo parameterInfo)
{
ReturnValueMember = returnValueMember;
ParameterInfo = parameterInfo;
}
}
public override int GetPriority(BuildContext context)
{
return TypeBuilderConsts.Priority.DataAccessor;
}
public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders)
{
if (context.IsBuildStep)
{
if (context.IsAbstractMethod)
{
// Give up if there is any builder that builds the method body.
//
if (builders.Count > 1)
foreach (IAbstractTypeBuilder builder in builders)
if (builder != this && builder.IsApplied(context, builders))
return false;
return true;
}
// Treat an abstract getter/setter as a regular method
// when the property has [NoInstance] attribute
//
if (context.IsAbstractGetter || context.IsAbstractSetter)
return context.CurrentProperty.IsDefined(typeof(NoInstanceAttribute), true);
}
return false;
}
private Dictionary<Type, Type> _actualTypes;
private Dictionary<Type, Type> ActualTypes
{
get
{
if (_actualTypes == null)
{
_actualTypes = new Dictionary<Type,Type>();
object[] attrs = Context.Type.GetAttributes(typeof(ActualTypeAttribute));
foreach (ActualTypeAttribute attr in attrs)
if (!_actualTypes.ContainsKey(attr.BaseType))
_actualTypes.Add(attr.BaseType, attr.ActualType);
}
return _actualTypes;
}
}
enum ReturnType
{
DataReader,
DataSet,
DataTable,
List,
Dictionary,
Enumerable,
Void,
Scalar,
Object
}
private static ReturnType GetReturnType(Type returnType)
{
if (returnType == typeof(IDataReader))
return ReturnType.DataReader;
if (returnType == typeof(DataSet) || returnType.IsSubclassOf(typeof(DataSet)))
return ReturnType.DataSet;
if (returnType == typeof(DataTable) || returnType.IsSubclassOf(typeof(DataTable)))
return ReturnType.DataTable;
if (!returnType.IsArray &&
(IsInterfaceOf(returnType, typeof(IList)) ||
returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IList<>)))
return ReturnType.List;
if (IsInterfaceOf(returnType, typeof(IDictionary)) ||
returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
return ReturnType.Dictionary;
if (returnType == typeof(IEnumerable) ||
returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return ReturnType.Enumerable;
if (returnType == typeof(void))
return ReturnType.Void;
if (TypeHelper.IsScalar(returnType.IsByRef? returnType.GetElementType(): returnType))
return ReturnType.Scalar;
return ReturnType.Object;
}
void ThrowTypeBuilderException(string message)
{
throw new TypeBuilderException(
string.Format(message, Context.CurrentMethod.DeclaringType.Name, Context.CurrentMethod.Name));
}
const BindingFlags _bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
readonly Type _baseType = typeof(DataAccessor);
Type _objectType;
bool _explicitObjectType;
ParameterInfo[] _parameters;
ArrayList _paramList;
ArrayList _refParamList;
bool _createManager;
LocalBuilder _locManager;
LocalBuilder _locObjType;
ArrayList _outputParameters;
SqlQueryAttribute _sqlQueryAttribute;
ArrayList _formatParamList;
ParameterInfo _destination;
ArrayList _mapOutputParameters;
protected override void BuildAbstractMethod()
{
// Any class variable must be initialized before use
// as the same instance of the class is utilized to build abstract methods.
//
_paramList = new ArrayList();
_refParamList = new ArrayList();
_formatParamList = new ArrayList();
_mapOutputParameters = new ArrayList();
_destination = null;
_createManager = true;
_objectType = null;
_explicitObjectType = false;
_parameters = Context.CurrentMethod.GetParameters();
_locManager = Context.MethodBuilder.Emitter.DeclareLocal(typeof(DbManager));
_locObjType = Context.MethodBuilder.Emitter.DeclareLocal(typeof(Type));
_outputParameters = null;
_sqlQueryAttribute = null;
GetSqlQueryAttribute();
ProcessParameters();
Type returnType = MethodReturnType;
ReturnType rt = GetReturnType(returnType);
CreateDbManager(rt != ReturnType.Enumerable);
SetObjectType();
// Define execution method type.
//
switch (rt)
{
case ReturnType.DataReader : ExecuteReader(); break;
case ReturnType.DataSet : ExecuteDataSet(returnType); break;
case ReturnType.DataTable : ExecuteDataTable(); break;
case ReturnType.Void : ExecuteNonQuery(); break;
case ReturnType.Scalar : ExecuteScalar(); break;
case ReturnType.Enumerable : ExecuteEnumerable(); break;
case ReturnType.List :
if (!_explicitObjectType)
{
Type elementType = TypeHelper.GetListItemType(returnType);
if (elementType == typeof(object) && _destination != null)
elementType = TypeHelper.GetListItemType(Context.CurrentMethod.ReturnType);
if (elementType != typeof(object))
_objectType = elementType;
if (ActualTypes.ContainsKey(_objectType))
_objectType = ActualTypes[_objectType];
}
if (_objectType == null || _objectType == typeof(object))
ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType);
if (TypeHelper.IsScalar(_objectType))
ExecuteScalarList();
else
ExecuteList();
break;
case ReturnType.Dictionary:
{
Type elementType = null;
Type keyType = typeof(object);
Type[] gTypes = TypeHelper.GetGenericArguments(returnType, typeof(IDictionary));
if ((gTypes == null || gTypes.Length != 2) && _destination != null)
gTypes = TypeHelper.GetGenericArguments(_destination.ParameterType, typeof(IDictionary));
if (gTypes != null && gTypes.Length == 2)
{
keyType = gTypes[0];
elementType = gTypes[1];
}
if (elementType == null || _explicitObjectType)
elementType = _objectType;
if (elementType == null || elementType == typeof(object))
ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType);
bool isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType);
if (keyType != typeof(object) && !isIndex && !TypeHelper.IsScalar(keyType))
ThrowTypeBuilderException(
Resources.DataAccessorBuilder_BadKeyType);
MethodInfo mi = Context.CurrentMethod;
object[] attrs = mi.GetCustomAttributes(typeof(IndexAttribute), true);
NameOrIndexParameter[] fields = new NameOrIndexParameter[0];
if (attrs.Length != 0)
fields = ((IndexAttribute)attrs[0]).Fields;
if (fields.Length > 1 && keyType != typeof(object) && !isIndex)
ThrowTypeBuilderException(
Resources.DataAccessor_InvalidKeyType);
if (TypeHelper.IsScalar(elementType))
{
attrs = mi.GetCustomAttributes(typeof(ScalarFieldNameAttribute), true);
if (attrs.Length == 0)
ThrowTypeBuilderException(Resources.DataAccessorBuilder_ScalarFieldNameMissing);
NameOrIndexParameter scalarField = ((ScalarFieldNameAttribute)attrs[0]).NameOrIndex;
if (fields.Length == 0)
ExecuteScalarDictionaryWithPK(keyType, scalarField, elementType);
else if (isIndex || fields.Length > 1)
ExecuteScalarDictionaryWithMapIndex(fields, scalarField, elementType);
else
ExecuteScalarDictionaryWithScalarKey(fields[0], keyType, scalarField, elementType);
}
else
{
if (!_explicitObjectType && ActualTypes.ContainsKey(elementType))
elementType = ActualTypes[elementType];
if (fields.Length == 0)
ExecuteDictionaryWithPK(keyType, elementType);
else if (isIndex || fields.Length > 1)
ExecuteDictionaryWithMapIndex(fields, elementType);
else
ExecuteDictionaryWithScalarKey(fields[0], elementType);
}
}
break;
default:
if (_objectType == null)
_objectType = returnType;
if (!_explicitObjectType && ActualTypes.ContainsKey(_objectType))
_objectType = ActualTypes[_objectType];
ExecuteObject();
break;
}
GetOutRefParameters();
if (rt != ReturnType.Enumerable)
Finally();
}
protected override void BuildAbstractGetter()
{
BuildAbstractMethod();
}
protected override void BuildAbstractSetter()
{
BuildAbstractMethod();
}
private void GetSqlQueryAttribute()
{
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(SqlQueryAttribute), true);
if (attrs.Length != 0)
_sqlQueryAttribute = (SqlQueryAttribute)attrs[0];
}
private void AddParameter(ParameterInfo pi)
{
Type pType = pi.ParameterType;
if (pType.IsByRef)
pType = pType.GetElementType();
if (TypeHelper.IsScalar(pType))
_paramList.Add(pi);
else if (pType == typeof(DbManager) || pType.IsSubclassOf(typeof(DbManager)))
_createManager = false;
else
_refParamList.Add(pi);
}
private void ProcessParameters()
{
for (int i = 0; i < _parameters.Length; i++)
{
ParameterInfo pi = _parameters[i];
NoMapAttribute[] attrs = (NoMapAttribute[])pi.GetCustomAttributes(typeof(NoMapAttribute), true);
if (attrs.Length == 0)
AddParameter(pi);
else
{
for (int j = 0; j < attrs.Length; ++j)
{
if (!attrs[j].NoMap)
AddParameter(pi);
if (attrs[j] is FormatAttribute)
{
int index = ((FormatAttribute)attrs[j]).Index;
if (index < 0)
index = 0;
else if (index > _formatParamList.Count)
index = _formatParamList.Count;
_formatParamList.Insert(index, pi);
}
else if (attrs[j] is DestinationAttribute)
{
if (_destination != null)
throw new TypeBuilderException(Resources.DataAccessorBuilderTooManyDestinations);
_destination = pi;
}
}
}
}
}
private void CreateDbManager(bool beginException)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
if (_createManager)
{
emit
.ldarg_0
.callvirt (_baseType, "GetDbManager")
.stloc (_locManager);
if (beginException)
emit.BeginExceptionBlock();
}
else
{
for (int i = 0; i < _parameters.Length; i++)
{
Type pType = _parameters[i].ParameterType;
if (pType == typeof(DbManager) || pType.IsSubclassOf(typeof(DbManager)))
{
emit
.ldarg (_parameters[i])
.stloc (_locManager)
;
break;
}
}
}
}
private void SetObjectType()
{
MethodInfo mi = Context.CurrentMethod;
object[] attrs = mi.GetCustomAttributes(typeof(ObjectTypeAttribute), true);
if (attrs.Length == 0)
attrs = mi.DeclaringType.GetCustomAttributes(typeof(ObjectTypeAttribute), true);
else
_explicitObjectType = true;
if (attrs.Length != 0)
_objectType = ((ObjectTypeAttribute)attrs[0]).ObjectType;
if (_objectType == null)
{
Type[] types = TypeHelper.GetGenericArguments(mi.DeclaringType, typeof(DataAccessor));
if (types != null)
_objectType = types[0];
}
}
#region ExecuteReader
private void ExecuteReader()
{
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(CommandBehaviorAttribute), true);
if (attrs.Length == 0)
{
Context.MethodBuilder.Emitter
.callvirt (typeof(DbManager).GetMethod("ExecuteReader", Type.EmptyTypes))
.stloc (Context.ReturnValue)
;
}
else
{
Context.MethodBuilder.Emitter
.ldc_i4_ ((int)((CommandBehaviorAttribute)attrs[0]).CommandBehavior)
.callvirt (typeof(DbManager), "ExecuteReader", typeof(CommandBehavior))
.stloc (Context.ReturnValue)
;
}
}
#endregion
#region ExecuteDataSet
private void ExecuteDataSet(Type returnType)
{
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
EmitHelper emit = Context.MethodBuilder.Emitter;
if (returnType == typeof(DataSet))
{
LoadDestinationOrReturnValue();
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true);
if (attrs.Length == 0)
{
emit
.callvirt (typeof(DbManager), "ExecuteDataSet", typeof(DataSet))
.pop
.end()
;
}
else
{
emit
.ldNameOrIndex(((DataSetTableAttribute)attrs[0]).NameOrIndex)
.callvirt (typeof(DbManager), "ExecuteDataSet", typeof(DataSet), typeof(NameOrIndexParameter))
.pop
.end()
;
}
}
else
{
emit
.pop
.end()
;
LoadDestinationOrReturnValue();
Label l1 = emit.DefineLabel();
Label l2 = emit.DefineLabel();
emit
.callvirt (typeof(DataSet).GetProperty("Tables").GetGetMethod())
.callvirt (typeof(InternalDataCollectionBase).GetProperty("Count").GetGetMethod())
.ldc_i4_0
.ble_s(l1)
.ldloc (_locManager);
LoadDestinationOrReturnValue();
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true);
if (attrs.Length == 0)
{
LoadDestinationOrReturnValue();
emit
.callvirt (typeof(DataSet).GetProperty("Tables").GetGetMethod())
.ldc_i4_0
.callvirt (typeof(DataTableCollection), "get_Item", typeof(int))
.callvirt (typeof(DataTable).GetProperty("TableName").GetGetMethod())
.call (typeof(NameOrIndexParameter), "op_Implicit", typeof(string))
;
}
else
{
emit
.ldNameOrIndex(((DataSetTableAttribute)attrs[0]).NameOrIndex)
;
}
emit
.callvirt (typeof(DbManager), "ExecuteDataSet", typeof(DataSet), typeof(NameOrIndexParameter))
.pop
.br_s (l2)
.MarkLabel (l1)
.ldloc (_locManager);
LoadDestinationOrReturnValue();
emit
.callvirt (typeof(DbManager), "ExecuteDataSet", typeof(DataSet))
.pop
.MarkLabel (l2)
;
}
}
#endregion
#region ExecuteDataTable
private void ExecuteDataTable()
{
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
EmitHelper emit = Context.MethodBuilder.Emitter;
emit
.callvirt (typeof(DbManager), "ExecuteDataTable", typeof(DataTable))
.pop
.end()
;
// When DataSetTableAttribute is present, simply set table name to the name specified.
//
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DataSetTableAttribute), true);
if (attrs.Length != 0)
{
DataSetTableAttribute attr = (DataSetTableAttribute)attrs[0];
if (!attr.NameOrIndex.ByName)
throw new TypeBuilderException(string.Format(
Resources.DataAccessorBuilder_DataSetTableMustBeByName,
Context.CurrentMethod.DeclaringType.Name, Context.CurrentMethod.Name));
LoadDestinationOrReturnValue();
emit
.ldstr(attr.NameOrIndex.Name)
.callvirt (typeof(DataTable), "set_TableName", typeof(string))
;
}
}
#endregion
#region ExecuteScalarList
private void ExecuteScalarList()
{
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ScalarFieldNameAttribute), true);
if (attrs.Length == 0)
{
Context.MethodBuilder.Emitter
.ldloc(_locObjType)
.callvirt(typeof(DbManager), "ExecuteScalarList", typeof(IList), typeof(Type))
.pop
.end()
;
}
else
{
Context.MethodBuilder.Emitter
.ldloc(_locObjType)
.ldNameOrIndex(((ScalarFieldNameAttribute)attrs[0]).NameOrIndex)
.callvirt(typeof(DbManager), "ExecuteScalarList", typeof(IList), typeof(Type), typeof(NameOrIndexParameter))
.pop
.end()
;
}
}
private void ExecuteList()
{
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
Context.MethodBuilder.Emitter
.CastIfNecessary (typeof(IList), MethodReturnType)
.ldloc (_locObjType)
.callvirt (typeof(DbManager), "ExecuteList", typeof(IList), typeof(Type))
.pop
.end()
;
}
#endregion
#region ExecuteDictionary
public FieldBuilder GetIndexField(NameOrIndexParameter[] namesOrIndexes)
{
string id = "index$" + string.Join("%",
Array.ConvertAll<NameOrIndexParameter, string>(namesOrIndexes,
delegate(NameOrIndexParameter nameOrIndex)
{
return nameOrIndex.ToString();
}));
FieldBuilder fieldBuilder = Context.GetField(id);
if (fieldBuilder == null)
{
fieldBuilder = Context.CreatePrivateStaticField(id, typeof(MapIndex));
EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter;
emit
.ldc_i4_ (namesOrIndexes.Length)
.newarr (typeof(NameOrIndexParameter))
;
for (int i = 0; i < namesOrIndexes.Length; i++)
{
emit
.dup
.ldc_i4_(i)
.ldelema(typeof(NameOrIndexParameter));
if (namesOrIndexes[i].ByName)
{
emit
.ldstr(namesOrIndexes[i].Name)
.call(typeof(NameOrIndexParameter), "op_Implicit", typeof(string));
}
else
{
emit
.ldc_i4_(namesOrIndexes[i].Index)
.call(typeof(NameOrIndexParameter), "op_Implicit", typeof(int));
}
emit
.stobj(typeof(NameOrIndexParameter))
.end()
;
}
emit
.newobj (typeof(MapIndex), typeof(NameOrIndexParameter[]))
.stsfld (fieldBuilder)
;
}
return fieldBuilder;
}
/// <summary>
/// Maps primary keys(s) to a scalar field.
/// </summary>
private void ExecuteScalarDictionaryWithPK(
Type keyType,
NameOrIndexParameter scalarField,
Type elementType)
{
CreateReturnTypeInstance();
InitObjectType();
Context.MethodBuilder.Emitter
.ldarg_0
.end()
;
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
Context.MethodBuilder.Emitter
.ldloc (_locObjType)
.LoadType (keyType)
.ldstr (Context.CurrentMethod.Name)
.ldNameOrIndex (scalarField)
.LoadType (elementType)
.callvirt (_baseType, "ExecuteScalarDictionary", _bindingFlags,
typeof(DbManager), typeof(IDictionary), typeof(Type),
typeof(Type), typeof(string), typeof(NameOrIndexParameter), typeof(Type))
;
}
/// <summary>
/// Maps a complex index to a scalar field.
/// </summary>
private void ExecuteScalarDictionaryWithMapIndex(
NameOrIndexParameter[] index,
NameOrIndexParameter scalarField,
Type elementType)
{
_objectType = elementType;
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
Context.MethodBuilder.Emitter
.ldsfld (GetIndexField(index))
.ldNameOrIndex (scalarField)
.ldloc (_locObjType)
.callvirt (typeof(DbManager), "ExecuteScalarDictionary",
typeof(IDictionary), typeof(MapIndex),
typeof(NameOrIndexParameter), typeof(Type))
.pop
.end()
;
}
/// <summary>
/// Maps any single field to any (other) single field.
/// </summary>
private void ExecuteScalarDictionaryWithScalarKey(
NameOrIndexParameter keyField, Type keyType,
NameOrIndexParameter scalarField, Type elementType)
{
_objectType = elementType;
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
Context.MethodBuilder.Emitter
.ldNameOrIndex (keyField)
.LoadType (keyType)
.ldNameOrIndex (scalarField)
.ldloc (_locObjType)
.callvirt (typeof(DbManager), "ExecuteScalarDictionary",
typeof(IDictionary), typeof(NameOrIndexParameter), typeof(Type),
typeof(NameOrIndexParameter), typeof(Type))
.pop
.end()
;
}
/// <summary>
/// Maps primary keys(s) to an object of the specified type.
/// </summary>
private void ExecuteDictionaryWithPK(
Type keyType,
Type elementType)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
_objectType = elementType;
CreateReturnTypeInstance();
InitObjectType();
emit
.ldarg_0
.end()
;
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
if (IsGenericDestinationOrReturnValue())
{
Type[] genericArgs = Context.ReturnValue.LocalType.GetGenericArguments();
Type[] types = new Type[]
{
typeof(DbManager),
typeof(IDictionary<,>).MakeGenericType(genericArgs),
typeof(Type),
typeof(string),
};
MethodInfo method = _baseType.GetMethod("ExecuteDictionary",
_bindingFlags, GenericBinder.Generic, types, null);
if (TypeHelper.IsSameOrParent(typeof(CompoundValue), genericArgs[0]))
method = method.MakeGenericMethod(genericArgs[1]);
else
method = method.MakeGenericMethod(genericArgs);
emit
.ldloc (_locObjType)
.ldstr (Context.CurrentMethod.Name)
.callvirt (method)
;
}
else
emit
.ldloc (_locObjType)
.LoadType (keyType)
.ldstr (Context.CurrentMethod.Name)
.callvirt (_baseType, "ExecuteDictionary", _bindingFlags,
typeof(DbManager), typeof(IDictionary), typeof(Type),
typeof(Type), typeof(string))
;
}
/// <summary>
/// Maps a complex index to an object of the specified type.
/// </summary>
private void ExecuteDictionaryWithMapIndex(
NameOrIndexParameter[] index,
Type elementType)
{
_objectType = elementType;
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
Context.MethodBuilder.Emitter
.ldsfld (GetIndexField(index))
.ldloc (_locObjType)
.ldnull
.callvirt (typeof(DbManager), "ExecuteDictionary",
typeof(IDictionary), typeof(MapIndex), typeof(Type), typeof(object[]))
.pop
.end()
;
}
/// <summary>
/// Maps any single field to object type.
/// </summary>
private void ExecuteDictionaryWithScalarKey(
NameOrIndexParameter keyField,
Type elementType)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
_objectType = elementType;
CreateReturnTypeInstance();
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
LoadDestinationOrReturnValue();
if (IsGenericDestinationOrReturnValue())
{
Type[] genericArgs = Context.ReturnValue.LocalType.GetGenericArguments();
Type[] types = new Type[]
{
typeof(IDictionary<,>).MakeGenericType(genericArgs),
typeof(NameOrIndexParameter),
typeof(Type),
typeof(object[]),
};
MethodInfo method = typeof(DbManager).GetMethod("ExecuteDictionary", _bindingFlags, GenericBinder.Generic, types, null)
.MakeGenericMethod(genericArgs);
emit
.ldNameOrIndex(keyField)
.ldloc (_locObjType)
.ldnull
.callvirt (method)
.pop
.end()
;
}
else
{
emit
.ldNameOrIndex(keyField)
.ldloc (_locObjType)
.ldnull
.callvirt (typeof(DbManager), "ExecuteDictionary", typeof(IDictionary), typeof(NameOrIndexParameter), typeof(Type), typeof(object[]))
.pop
.end()
;
}
}
#endregion
#region ExecuteEnumerable
public void ExecuteEnumerable()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
Type returnType = Context.CurrentMethod.ReturnType;
if (_objectType == null && returnType.IsGenericType)
_objectType = returnType.GetGenericArguments()[0];
if (_objectType == null || _objectType == typeof(object))
ThrowTypeBuilderException(Resources.DataAccessorBuilder_BadListItemType);
Type returnObjectType = returnType.IsGenericType ? returnType.GetGenericArguments()[0] : _objectType;
InitObjectType();
Context.MethodBuilder.Emitter
.ldarg_0
.end()
;
GetSprocNameOrSqlQueryTest();
CallSetCommand();
Type[] genericArgs = new Type[] { returnObjectType };
Type[] types = new Type[] { typeof(DbManager), typeof(Type), typeof(bool), };
MethodInfo method = _baseType
.GetMethod("ExecuteEnumerable", _bindingFlags, GenericBinder.Generic, types, null)
.MakeGenericMethod(genericArgs);
emit
.LoadType (_objectType)
.ldc_i4_1
.callvirt (method)
.stloc (Context.ReturnValue)
;
}
#endregion
#region ExecuteNonQuery
public void ExecuteNonQuery()
{
if (_destination != null)
throw new TypeBuilderException(Resources.DataAccessorBuilder_CantExecuteNonQueryToDestination);
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
MethodInfo mi = typeof(DbManager).GetMethod("ExecuteNonQuery", Type.EmptyTypes);
LocalBuilder locExec = Context.MethodBuilder.Emitter.DeclareLocal(mi.ReturnType);
Context.MethodBuilder.Emitter
.callvirt (mi)
.stloc (locExec)
;
if (Context.ReturnValue != null)
{
Context.MethodBuilder.Emitter
.ldloc (locExec)
.stloc (Context.ReturnValue)
;
}
}
#endregion
#region ExecuteScalar
public void ExecuteScalar()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
Type returnType = Context.CurrentMethod.ReturnType;
Type scalarType;
if (_destination != null)
{
if (_destination.ParameterType.IsByRef)
scalarType = _destination.ParameterType.GetElementType();
else
throw new TypeBuilderException(Resources.DataAccessorBuilder_ScalarDestinationIsNotByRef);
if (returnType != typeof(void) && !TypeHelper.IsSameOrParent(returnType, scalarType))
{
// object Foo(out int num) is valid,
// IConvertible Foo(ref int num) is also ok,
// but string Bar(out DateTime dt) is not
//
throw new TypeBuilderException(string.Format(
Resources.DataAccessorBuilder_IncompatibleDestinationType,
returnType.FullName, Context.CurrentMethod.Name, scalarType.FullName));
}
}
else
scalarType = returnType;
if (_destination != null)
emit
.ldarg (_destination)
;
emit
.ldarg_0
.ldloc (_locManager)
;
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ScalarSourceAttribute), true);
if (attrs.Length == 0)
{
emit
.callvirtNoGenerics (typeof(DbManager), "ExecuteScalar")
;
}
else
{
ScalarSourceAttribute attr = (ScalarSourceAttribute)attrs[0];
emit
.ldc_i4_ ((int)attr.ScalarType)
.ldNameOrIndex (attr.NameOrIndex)
.callvirtNoGenerics (typeof(DbManager), "ExecuteScalar", typeof(ScalarSourceType), typeof(NameOrIndexParameter));
}
MethodInfo converter = GetConverterMethod(scalarType);
if (converter == null)
{
emit
.LoadType (scalarType)
.ldnull
.callvirt (_baseType, "ConvertChangeType", _bindingFlags, typeof (DbManager), typeof (object), typeof (Type), typeof (object))
.unboxIfValueType (scalarType)
;
}
else
{
emit
.ldnull
.callvirt (converter)
;
}
if (_destination != null)
{
emit
.stind (scalarType)
;
// The return value and a destination both are present
//
if (Context.ReturnValue != null)
{
emit
.ldargEx (_destination, false)
;
if (scalarType != returnType)
emit
.boxIfValueType (scalarType)
.CastFromObject (returnType)
;
emit.stloc (Context.ReturnValue)
;
}
}
else
emit
.stloc (Context.ReturnValue)
;
}
#endregion
#region ExecuteObject
public void ExecuteObject()
{
InitObjectType();
GetSprocNameOrSqlQueryTest();
CallSetCommand();
EmitHelper emit = Context.MethodBuilder.Emitter;
if (_destination != null)
{
emit
.ldarg(_destination)
.callvirt(typeof(DbManager), "ExecuteObject", typeof(Object))
;
}
else
{
emit
.ldloc(_locObjType)
.callvirt(typeof(DbManager), "ExecuteObject", typeof(Type))
;
}
if (null != Context.ReturnValue)
{
emit
.castclass(_objectType)
.stloc(Context.ReturnValue)
;
}
else
{
emit
.pop
.end()
;
}
}
#endregion
private void Finally()
{
if (_createManager)
{
Context.MethodBuilder.Emitter
.BeginFinallyBlock()
.ldarg_0
.ldloc (_locManager)
.callvirt (_baseType, "Dispose", _bindingFlags, typeof(DbManager))
.EndExceptionBlock()
;
}
}
private void CreateReturnTypeInstance()
{
if (null == Context.ReturnValue)
return;
if (null != _destination)
{
Context.MethodBuilder.Emitter
.ldarg (_destination)
.CastIfNecessary (Context.ReturnValue.LocalType, _destination.ParameterType)
.stloc (Context.ReturnValue)
;
}
else
{
Type returnType = Context.CurrentMethod.ReturnType;
if (returnType.IsInterface)
{
if (IsInterfaceOf(returnType, typeof(IList)))
returnType = typeof(ArrayList);
else if (IsInterfaceOf(returnType, typeof(IDictionary)))
returnType = typeof(Hashtable);
else if (returnType.GetGenericTypeDefinition() == typeof(IList<>))
returnType = typeof(List<>).MakeGenericType(returnType.GetGenericArguments());
else if (returnType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
returnType = typeof(Dictionary<,>).MakeGenericType(returnType.GetGenericArguments());
}
ConstructorInfo ci = TypeHelper.GetDefaultConstructor(returnType);
if (ci == null)
throw new TypeBuilderException(string.Format(Resources.DataAccessorBuilder_CantCreateTypeInstance,
Context.CurrentMethod.ReturnType.FullName));
Context.MethodBuilder.Emitter
.newobj (ci)
.stloc (Context.ReturnValue)
;
}
}
private Type MethodReturnType
{
get
{
return _destination != null?
_destination.ParameterType:
Context.CurrentMethod.ReturnType;
}
}
private void LoadDestinationOrReturnValue()
{
if (_destination != null)
Context.MethodBuilder.Emitter.ldarg(_destination);
else
Context.MethodBuilder.Emitter.ldloc(Context.ReturnValue);
}
private bool IsGenericDestinationOrReturnValue()
{
return _destination == null?
Context.ReturnValue.LocalType.IsGenericType:
_destination.ParameterType.IsGenericType;
}
private void InitObjectType()
{
Context.MethodBuilder.Emitter
.LoadType (_objectType)
.stloc (_locObjType)
;
}
static int _nameCounter;
static int _uniqueQueryID;
private void GetSprocNameOrSqlQueryTest()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
if (_sqlQueryAttribute != null)
{
emit
.ldloc (_locManager)
;
if (_sqlQueryAttribute.ID != int.MinValue)
{
emit
.ldarg_0
.ldloc (_locManager)
.ldc_i4_ (_sqlQueryAttribute.ID)
.ldc_i4_ (++_uniqueQueryID)
;
}
if (_sqlQueryAttribute.IsDynamic)
{
Type attrType = typeof(SqlQueryAttribute);
FieldBuilder field = Context.CreatePrivateStaticField(attrType + "$" + ++_nameCounter, attrType);
Label isNull = emit.DefineLabel();
emit
.ldsfld (field)
.brtrue_s (isNull)
.ldarg_0
.call (typeof(MethodBase), "GetCurrentMethod")
.castclass (typeof(MethodInfo))
.callvirt (_baseType, "GetSqlQueryAttribute", _bindingFlags, typeof(MethodInfo))
.stsfld (field)
.MarkLabel (isNull)
.ldsfld (field)
.ldarg_0
.ldloc (_locManager)
.callvirt (attrType, "GetSqlText", _bindingFlags, typeof(DataAccessor), typeof(DbManager))
;
}
else
{
emit
.ldstr (_sqlQueryAttribute.SqlText)
;
}
if (_sqlQueryAttribute.ID != int.MinValue)
{
emit
.callvirt (_baseType, "PrepareSqlQuery", _bindingFlags,
typeof(DbManager), typeof(int), typeof(int), typeof(string))
;
}
}
else
{
object[] attrs = Context.CurrentMethod.GetCustomAttributes(typeof(SprocNameAttribute), true);
if (attrs.Length == 0)
{
attrs = Context.CurrentMethod.GetCustomAttributes(typeof(ActionNameAttribute), true);
string actionName = attrs.Length == 0 ?
Context.CurrentMethod.Name : ((ActionNameAttribute)attrs[0]).Name;
// Call GetSpName.
//
emit
.ldloc (_locManager)
.ldarg_0
.ldloc (_locObjType)
.ldstr (actionName)
.callvirt (_baseType, "GetSpName", _bindingFlags, typeof(Type), typeof(string))
;
}
else
{
emit
.ldloc (_locManager)
.ldstr (((SprocNameAttribute)attrs[0]).Name)
;
}
}
// string.Format
//
if (_formatParamList.Count > 0)
{
emit
.ldc_i4_ (_formatParamList.Count)
.newarr (typeof(object))
;
for (int i = 0; i < _formatParamList.Count; i++)
{
ParameterInfo pi = (ParameterInfo)_formatParamList[i];
emit
.dup
.ldc_i4_ (i)
.ldarg (pi)
.boxIfValueType (pi.ParameterType)
.stelem_ref
.end()
;
}
emit
.call (typeof(string), "Format", typeof(string), typeof(object[]))
;
}
}
private void CallSetCommand()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
// Get DiscoverParametersAttribute.
//
object[] attrs =
Context.CurrentMethod.DeclaringType.GetCustomAttributes(typeof(DiscoverParametersAttribute), true);
bool discoverParams = false;
if (_sqlQueryAttribute == null)
{
discoverParams = attrs.Length == 0?
false: ((DiscoverParametersAttribute)attrs[0]).Discover;
attrs = Context.CurrentMethod.GetCustomAttributes(typeof(DiscoverParametersAttribute), true);
if (attrs.Length != 0)
discoverParams = ((DiscoverParametersAttribute)attrs[0]).Discover;
}
LocalBuilder locParams = discoverParams?
BuildParametersWithDiscoverParameters():
BuildParameters();
// Call SetSpCommand.
//
string methodName = _sqlQueryAttribute == null? "SetSpCommand": "SetCommand";
Type paramType = _sqlQueryAttribute == null? typeof(object[]): typeof(IDbDataParameter[]);
emit
.ldloc (locParams)
.callvirt (typeof(DbManager), methodName, _bindingFlags, typeof(string), paramType)
;
}
private LocalBuilder BuildParameters()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
LocalBuilder retParams = emit
.DeclareLocal(typeof(IDbDataParameter[]));
LocalBuilder locParams = _refParamList.Count > 0?
BuildRefParameters():
BuildSimpleParameters();
emit
.ldarg_0
.ldloc (_locManager)
.ldloc (locParams)
.callvirt (_baseType, "PrepareParameters", _bindingFlags, typeof(DbManager), typeof(object[]))
.stloc (retParams)
;
return retParams;
}
private LocalBuilder BuildSimpleParameters()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
// Parameters.
//
LocalBuilder locParams = emit.DeclareLocal(
_sqlQueryAttribute == null? typeof(object[]): typeof(IDbDataParameter[]));
emit
.ldc_i4_ (_paramList.Count)
.newarr (_sqlQueryAttribute == null? typeof(object): typeof(IDbDataParameter))
;
for (int i = 0; i < _paramList.Count; i++)
{
ParameterInfo pi = (ParameterInfo)_paramList[i];
emit
.dup
.ldc_i4_ (i)
;
BuildParameter(pi);
emit
.stelem_ref
.end()
;
}
emit.stloc(locParams);
return locParams;
}
private FieldBuilder CreateStringArrayField(object[] attrs)
{
if (attrs.Length == 0)
return null;
List<string> list = new List<string>();
foreach (Direction attr in attrs)
if (attr.Members != null)
list.AddRange(attr.Members);
if (list.Count == 0)
return null;
list.Sort(string.CompareOrdinal);
string[] strings = list.ToArray();
// There a no limit for a field name length, but Visual Studio Debugger
// may crash on fields with name longer then 256 symbols.
//
string key = "_string_array$" + string.Join("%", strings);
FieldBuilder fieldBuilder = Context.GetField(key);
if (null == fieldBuilder)
{
fieldBuilder = Context.CreatePrivateStaticField(key, typeof(string[]));
EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter;
emit
.ldc_i4_ (strings.Length)
.newarr (typeof(string))
;
for (int i = 0; i < strings.Length; i++)
{
emit
.dup
.ldc_i4_ (i)
.ldstr (strings[i])
.stelem_ref
.end()
;
}
emit
.stsfld (fieldBuilder)
;
}
return fieldBuilder;
}
private FieldBuilder CreateNullValueField(Type type, string value)
{
string key = "_null_value$" + type.FullName + "%" + value;
FieldBuilder fieldBuilder = Context.GetField(key);
if (null == fieldBuilder)
{
fieldBuilder = Context.CreatePrivateStaticField(key, type);
EmitHelper emit = Context.TypeBuilder.TypeInitializer.Emitter;
emit
.LoadType (type)
.call (typeof(TypeDescriptor), "GetConverter", typeof(Type))
.ldstr (value)
.callvirt (typeof(TypeConverter), "ConvertFromInvariantString", typeof(string))
.unbox_any (type)
.stsfld (fieldBuilder)
;
}
return fieldBuilder;
}
private LocalBuilder BuildRefParameters()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
// Parameters.
//
LocalBuilder locParams = emit.DeclareLocal(typeof(object[]));
emit
.ldc_i4_ (_parameters.Length)
.newarr (typeof(object))
;
for (int i = 0; i < _parameters.Length; i++)
{
ParameterInfo pi = _parameters[i];
emit
.dup
.ldc_i4_ (i)
;
if (_paramList.Contains(pi))
{
BuildParameter(pi);
}
else if (_refParamList.Contains(pi))
{
bool mapOutputParameters = false;
string returnValueMember = null;
FieldBuilder fieldBuilder;
Type type =
pi.ParameterType == typeof(DataRow) || pi.ParameterType.IsSubclassOf(typeof(DataRow))?
typeof(DataRow): typeof(object);
emit
.ldarg_0
.ldloc (_locManager)
.ldarg (pi)
;
fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.OutputAttribute), true));
if (fieldBuilder != null)
{
emit.ldsfld (fieldBuilder);
mapOutputParameters = true;
}
else
emit.ldnull.end();
fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.InputOutputAttribute), true));
if (fieldBuilder != null)
{
emit.ldsfld (fieldBuilder);
mapOutputParameters = true;
}
else
emit.ldnull.end();
fieldBuilder = CreateStringArrayField(pi.GetCustomAttributes(typeof(Direction.IgnoreAttribute), true));
if (fieldBuilder != null)
emit.ldsfld (fieldBuilder);
else
emit.ldnull.end();
emit
.ldnull
.callvirt (_baseType, "CreateParameters", _bindingFlags,
typeof(DbManager), type, typeof(string[]), typeof(string[]), typeof(string[]), typeof(IDbDataParameter[]))
;
object[] attrs = pi.GetCustomAttributes(typeof (Direction.ReturnValueAttribute), true);
if (attrs.Length != 0)
returnValueMember = ((Direction.ReturnValueAttribute)attrs[0]).Member;
if (null != returnValueMember || mapOutputParameters)
_mapOutputParameters.Add(new MapOutputParametersValue(returnValueMember, pi));
}
else
{
emit
.ldnull
.end()
;
}
emit
.stelem_ref
.end()
;
}
emit.stloc(locParams);
return locParams;
}
private void LoadParameterOrNull(ParameterInfo pi, Type type)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
object[] attrs = pi.GetCustomAttributes(typeof(ParamNullValueAttribute), true);
object nullValue = attrs.Length == 0?
null: ((ParamNullValueAttribute)attrs[0]).Value;
Label labelNull = emit.DefineLabel();
Label labelEndIf = emit.DefineLabel();
if (pi.Attributes == ParameterAttributes.Out)
{
emit
.ldnull
.end()
;
return;
}
if (nullValue != null)
{
Type nullValueType = type;
bool isNullable = TypeHelper.IsNullable(type);
if (type.IsEnum)
{
nullValueType = Enum.GetUnderlyingType(type);
nullValue = System.Convert.ChangeType(nullValue, nullValueType);
}
else if (isNullable)
{
nullValueType = type.GetGenericArguments()[0];
emit
.ldarga (pi)
.call (type, "get_HasValue")
.brfalse (labelNull)
;
}
if (nullValueType == nullValue.GetType() && emit.LoadWellKnownValue(nullValue))
{
if (nullValueType == typeof(string))
emit
.ldargEx (pi, false)
.call (nullValueType, "Equals", nullValueType)
.brtrue (labelNull)
;
else if (isNullable)
emit
.ldarga (pi)
.call (type, "get_Value")
.beq (labelNull)
;
else
emit
.ldargEx (pi, false)
.beq (labelNull)
;
}
else
{
string nullString = TypeDescriptor.GetConverter(nullValue).ConvertToInvariantString(nullValue);
FieldBuilder staticField = CreateNullValueField(nullValueType, nullString);
MethodInfo miEquals = new TypeHelper(nullValueType).GetPublicMethod("Equals", nullValueType);
if (miEquals == null)
{
// Is it possible?
//
throw new TypeBuilderException(string.Format(
Resources.DataAccessorBuilder_EqualsMethodIsNotPublic, type.FullName));
}
if (isNullable)
emit
.ldsflda (staticField)
.ldarga (pi)
.call (pi.ParameterType, "get_Value")
;
else
emit
.ldsflda (staticField)
.ldarg (pi)
;
if (miEquals.GetParameters()[0].ParameterType.IsClass)
emit
.boxIfValueType(nullValueType)
;
emit
.call (miEquals)
.brtrue (labelNull)
;
}
}
if (type.IsEnum)
emit
.ldloc (_locManager)
.callvirt (typeof (DbManager).GetProperty("MappingSchema").GetGetMethod())
;
emit
.ldargEx(pi, true)
;
if (type.IsEnum)
emit
.ldc_i4_1
.callvirt (typeof (MappingSchema), "MapEnumToValue", typeof (object), typeof (bool))
;
if (nullValue != null)
{
emit
.br (labelEndIf)
.MarkLabel (labelNull)
.ldnull
.MarkLabel (labelEndIf)
;
}
}
private void BuildParameter(ParameterInfo pi)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
Type type = pi.ParameterType;
object[] attrs = pi.GetCustomAttributes(typeof(ParamNameAttribute), true);
string paramName = attrs.Length == 0 ? pi.Name : ((ParamNameAttribute)attrs[0]).Name;
ParameterDirection direction = !type.IsByRef? ParameterDirection.Input:
pi.IsOut? ParameterDirection.Output: ParameterDirection.InputOutput;
emit
.ldloc (_locManager)
.ldc_i4_ ((int)direction)
;
if (paramName[0] != '@')
{
string methodName = _sqlQueryAttribute == null? "GetSpParameterName": "GetQueryParameterName";
emit
.ldarg_0
.ldloc (_locManager)
.ldstr (paramName)
.callvirt (_baseType, methodName, _bindingFlags, typeof(DbManager), typeof(string))
;
}
else
emit.ldstr (paramName);
if (type.IsByRef)
{
if (_outputParameters == null)
_outputParameters = new ArrayList();
_outputParameters.Add(pi);
type = type.GetElementType();
}
LoadParameterOrNull(pi, type);
#if FW3
// Special case for user-defined types.
//
attrs = pi.GetCustomAttributes(typeof(ParamTypeNameAttribute), true);
if (attrs.Length > 0)
{
emit
.ldstr (((ParamTypeNameAttribute)attrs[0]).TypeName)
.callvirt (typeof(DbManager), "Parameter",
typeof(ParameterDirection), typeof(string), typeof(object), typeof(string))
;
}
else
#endif
{
emit
.callvirt (typeof(DbManager), "Parameter",
typeof(ParameterDirection), typeof(string), typeof(object))
;
}
// Check if parameter type/size is specified.
//
attrs = pi.GetCustomAttributes(typeof(ParamDbTypeAttribute), true);
if (attrs.Length > 0)
{
emit
.dup
.ldc_i4_ ((int)((ParamDbTypeAttribute)attrs[0]).DbType)
.callvirt (typeof(IDataParameter), "set_DbType", typeof(DbType))
;
}
attrs = pi.GetCustomAttributes(typeof(ParamSizeAttribute), true);
if (attrs.Length > 0)
{
emit
.dup
.ldc_i4_ (((ParamSizeAttribute)attrs[0]).Size)
.callvirt (typeof(IDbDataParameter), "set_Size", typeof(int))
;
}
}
private LocalBuilder BuildParametersWithDiscoverParameters()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
LocalBuilder locParams = emit.DeclareLocal(typeof(object[]));
emit
.ldc_i4_ (_paramList.Count)
.newarr (typeof(object))
;
for (int i = 0; i < _paramList.Count; i++)
{
ParameterInfo pi = (ParameterInfo)_paramList[i];
emit
.dup
.ldc_i4_ (i)
;
LoadParameterOrNull(pi, pi.ParameterType);
emit
.stelem_ref
.end()
;
}
emit.stloc(locParams);
return locParams;
}
private void StoreParameterValue(LocalBuilder param, ParameterInfo pi, Type type)
{
EmitHelper emit = Context.MethodBuilder.Emitter;
Label labelNull = emit.DefineLabel();
Label labelEndIf = emit.DefineLabel();
object[] attrs = pi.GetCustomAttributes(typeof(ParamNullValueAttribute), true);
object nullValue = attrs.Length == 0? null: ((ParamNullValueAttribute)attrs[0]).Value;
if (nullValue != null)
{
emit
.ldarg_0
.ldloc (_locManager)
.ldloc (param)
.callvirt (typeof(IDataParameter).GetProperty("Value").GetGetMethod())
.ldloc (param)
.callvirt (_baseType, "IsNull", _bindingFlags, typeof(DbManager), typeof(object), typeof(object))
.brtrue (labelNull)
;
}
if (type.IsEnum)
{
emit
.ldloc (_locManager)
.callvirt (typeof(DbManager).GetProperty("MappingSchema").GetGetMethod())
.ldloc (param)
.callvirt (typeof(IDataParameter).GetProperty("Value").GetGetMethod())
.LoadType (type)
.callvirt (typeof(MappingSchema), "MapValueToEnum", typeof(object), typeof(Type))
.CastFromObject (type)
;
}
else
{
emit
.ldarg_0
.ldloc (_locManager)
.ldloc (param)
.callvirt (typeof(IDataParameter).GetProperty("Value").GetGetMethod())
;
MethodInfo converter = GetConverterMethod(type);
if (converter == null)
{
emit
.LoadType (type)
.ldloc (param)
.callvirt (_baseType, "ConvertChangeType", _bindingFlags, typeof(DbManager), typeof(object), typeof(Type), typeof(object))
.unboxIfValueType (type)
;
}
else
{
emit
.ldloc (param)
.callvirt (converter)
;
}
}
if (nullValue != null)
{
emit
.br (labelEndIf)
.MarkLabel (labelNull);
if (nullValue.GetType() != type || !emit.LoadWellKnownValue(nullValue))
{
string nullString = TypeDescriptor.GetConverter(type).ConvertToInvariantString(nullValue);
FieldBuilder staticField = CreateNullValueField(type, nullString);
emit
.ldsfld (staticField)
;
}
emit
.MarkLabel (labelEndIf)
;
}
emit.stind(type);
}
private void GetOutRefParameters()
{
EmitHelper emit = Context.MethodBuilder.Emitter;
if (_outputParameters != null)
{
LocalBuilder param = emit.DeclareLocal(typeof(IDataParameter));
foreach (ParameterInfo pi in _outputParameters)
{
Type type = pi.ParameterType.GetElementType();
emit
.ldarg(pi)
;
// Get parameter.
//
object[] attrs = pi.GetCustomAttributes(typeof(ParamNameAttribute), true);
string paramName = attrs.Length == 0 ?
pi.Name : ((ParamNameAttribute)attrs[0]).Name;
emit
.ldarg_0
.ldloc (_locManager)
;
if (paramName[0] != '@')
{
string methodName = _sqlQueryAttribute == null? "GetSpParameterName": "GetQueryParameterName";
emit
.ldarg_0
.ldloc (_locManager)
.ldstr (paramName)
.callvirt (_baseType, methodName, _bindingFlags, typeof(DbManager), typeof(string))
;
}
else
emit.ldstr (paramName);
emit
.callvirt (_baseType, "GetParameter", _bindingFlags, typeof(DbManager), typeof(string))
.stloc (param)
;
StoreParameterValue(param, pi, type);
}
}
foreach (MapOutputParametersValue v in _mapOutputParameters)
{
emit
.ldloc (_locManager)
.ldstrEx (v.ReturnValueMember)
.ldarg (v.ParameterInfo)
.callvirt (typeof(DbManager), "MapOutputParameters", typeof(string), typeof(object));
}
}
private static bool IsInterfaceOf(Type type, Type interfaceType)
{
Type[] types = type.GetInterfaces();
foreach (Type t in types)
if (t == interfaceType)
return true;
return type == interfaceType;
}
private MethodInfo GetConverterMethod(Type type)
{
if (type.IsEnum)
type = Enum.GetUnderlyingType(type);
Type[] types = new Type[]{ typeof(DbManager), typeof(object), typeof(object) };
return _baseType.GetMethod("ConvertTo" + type.Name, _bindingFlags, null, types, null);
}
}
} |