Example #1
0
        /// <summary>
        /// Emits the code to get a value from a type, allowing dot accessors to select children.
        /// </summary>
        /// <param name="type">The base type.</param>
        /// <param name="memberName">The name of the member in the form a.b.c.d.</param>
        /// <param name="il">The ILGenerator to use,</param>
        /// <param name="readyToSetLabel">The label to jump to if any of the non-terminal accesses result (a.b.c) in null.</param>
        internal static void EmitGetValue(Type type, string memberName, ILGenerator il, Label?readyToSetLabel = null)
        {
            ClassPropInfo pi          = null;
            var           memberNames = SplitMemberName(memberName).ToArray();

            Label nullLabel = il.DefineLabel();

            // emit the code to get the value
            for (int i = 0; i < memberNames.Length; i++)
            {
                var member = memberNames[i];

                // if the value on the stack can be null, do a null check here
                if (pi != null && !pi.MemberType.GetTypeInfo().IsValueType)
                {
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Brfalse, nullLabel);
                }

                pi = FindMember(type, member);
                if (pi == null || !pi.CanGetMember)
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Get method {0} not found on {1}", member, type));
                }

                pi.EmitGetValue(il);

                type = pi.MemberType;
            }

            // emit the code to handle nulls
            var memberType = pi.MemberType;

            if (memberNames.Length > 1)
            {
                var doneLabel = il.DefineLabel();
                il.Emit(OpCodes.Br, doneLabel);

                // if any of the prefix values are null, then we emit the default of the final type
                il.MarkLabel(nullLabel);
                il.Emit(OpCodes.Pop);
                il.Emit(OpCodes.Ldnull);
                if (readyToSetLabel != null)
                {
                    il.Emit(OpCodes.Br, readyToSetLabel.Value);
                }

                il.MarkLabel(doneLabel);
            }

            // if this is a value type, then box the value so the compiler can check the type and we can call methods on it
            if (memberType.GetTypeInfo().IsValueType)
            {
                il.Emit(OpCodes.Box, memberType);
            }
        }
Example #2
0
        /// <summary>
        /// Generates an accessor for a property in the object.
        /// </summary>
        /// <param name="type">The type of object being read.</param>
        /// <param name="mapping">The column mapping.</param>
        /// <param name="columnInfo">The column information.</param>
        /// <returns>An accessor function or null if there is no mapping.</returns>
        private static Func <object, object> GenerateAccessor(Type type, FieldMapping mapping, ColumnInfo columnInfo)
        {
            if (mapping == null)
            {
                return(null);
            }

            ClassPropInfo propInfo = mapping.Member;

            // create a new anonymous method that takes an object and returns the value
            var dm = new DynamicMethod(string.Format(CultureInfo.InvariantCulture, "GetValue-{0}-{1}", type.FullName, Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);
            var il = dm.GetILGenerator();

            // convert the object reference to the desired type
            il.Emit(OpCodes.Ldarg_0);
            if (type.IsValueType)
            {
                // access the field/property of a value type
                var valueHolder = il.DeclareLocal(type);
                il.Emit(OpCodes.Unbox_Any, type);
                il.Emit(OpCodes.Stloc, valueHolder);
                il.Emit(OpCodes.Ldloca_S, valueHolder);
            }
            else
            {
                il.Emit(OpCodes.Isinst, type);                                  // cast object -> type
            }
            // get the value from the object
            var readyToSetLabel = il.DefineLabel();

            ClassPropInfo.EmitGetValue(type, mapping.PathToMember, il, readyToSetLabel);
            if (mapping.Member.MemberType.IsValueType)
            {
                il.Emit(OpCodes.Unbox_Any, mapping.Member.MemberType);
            }

            // if the type is nullable, handle nulls
            Type sourceType     = propInfo.MemberType;
            Type targetType     = columnInfo.ColumnType;
            Type underlyingType = Nullable.GetUnderlyingType(sourceType);

            if (underlyingType != null)
            {
                // check for not null
                Label notNullLabel = il.DefineLabel();

                var nullableHolder = il.DeclareLocal(propInfo.MemberType);
                il.Emit(OpCodes.Stloc, nullableHolder);
                il.Emit(OpCodes.Ldloca_S, nullableHolder);
                il.Emit(OpCodes.Call, sourceType.GetProperty("HasValue").GetGetMethod());
                il.Emit(OpCodes.Brtrue_S, notNullLabel);

                // it's null, just return null
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ret);

                il.MarkLabel(notNullLabel);

                // it's not null, so unbox to the underlyingtype
                il.Emit(OpCodes.Ldloca, nullableHolder);
                il.Emit(OpCodes.Call, sourceType.GetProperty("Value").GetGetMethod());

                // at this point we have de-nulled value, so use those converters
                sourceType = underlyingType;
            }

            // if the serializer isn't the default ToStringSerializer, and it can serialize the type properly, then use it
            // otherwise we'll use coersion or conversion
            var  targetDbType = DbParameterGenerator.LookupDbType(targetType);
            bool canSerialize = sourceType != typeof(string) &&
                                mapping.Serializer.GetType() != typeof(ToStringObjectSerializer) &&
                                mapping.Serializer.CanSerialize(sourceType, targetDbType);

            if (sourceType != targetType && canSerialize)
            {
                if (sourceType.IsValueType)
                {
                    il.Emit(OpCodes.Box, sourceType);
                }
                il.EmitLoadType(sourceType);
                StaticFieldStorage.EmitLoad(il, mapping.Serializer);
                il.Emit(OpCodes.Call, typeof(ObjectReader).GetMethod("SerializeObject", BindingFlags.NonPublic | BindingFlags.Static));
            }
            else
            {
                // attempt to convert the value
                // either way, we are putting it in an object variable, so box it
                if (TypeConverterGenerator.EmitConversionOrCoersion(il, sourceType, targetType))
                {
                    il.Emit(OpCodes.Box, targetType);
                }
                else
                {
                    il.Emit(OpCodes.Box, sourceType);
                }
            }

            il.MarkLabel(readyToSetLabel);
            il.Emit(OpCodes.Ret);

            return((Func <object, object>)dm.CreateDelegate(typeof(Func <object, object>)));
        }
Example #3
0
        private ObjectReader(IDbCommand command, Type type, IDataReader reader)
        {
            var provider = InsightDbProvider.For(command);

            // copy the schema and fix it
            SchemaTable = reader.GetSchemaTable().Copy();
            FixupSchemaNumericScale();
            FixupSchemaRemoveReadOnlyColumns();

            IsAtomicType = TypeHelper.IsAtomicType(type);
            if (!IsAtomicType)
            {
                // create a mapping, and only keep mappings that match our modified schema
                var mappings = ColumnMapping.Tables.CreateMapping(type, reader, null, null, null, 0, reader.FieldCount, true)
                               .Where(m => m != null).ToArray();

                int columnCount = SchemaTable.Rows.Count;
                _accessors   = new Func <object, object> [columnCount];
                _memberTypes = new Type[columnCount];

                for (int i = 0; i < columnCount; i++)
                {
                    var columnName = SchemaTable.Rows[i]["ColumnName"].ToString();
                    var mapping    = mappings.FirstOrDefault(m => String.Compare(m.ColumnName, columnName, StringComparison.OrdinalIgnoreCase) == 0);
                    if (mapping == null)
                    {
                        continue;
                    }
                    ClassPropInfo propInfo = mapping.ClassPropInfo;

                    // create a new anonymous method that takes an object and returns the value
                    var dm = new DynamicMethod(string.Format(CultureInfo.InvariantCulture, "GetValue-{0}-{1}", type.FullName, Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);
                    var il = dm.GetILGenerator();

                    // convert the object reference to the desired type
                    il.Emit(OpCodes.Ldarg_0);
                    if (type.IsValueType)
                    {
                        // access the field/property of a value type
                        var valueHolder = il.DeclareLocal(type);
                        il.Emit(OpCodes.Unbox_Any, type);
                        il.Emit(OpCodes.Stloc, valueHolder);
                        il.Emit(OpCodes.Ldloca_S, valueHolder);
                    }
                    else
                    {
                        il.Emit(OpCodes.Isinst, type);                                                          // cast object -> type
                    }
                    // get the value from the object
                    propInfo.EmitGetValue(il);

                    // if the type is nullable, handle nulls
                    Type sourceType     = propInfo.MemberType;
                    Type targetType     = (Type)SchemaTable.Rows[i]["DataType"];
                    Type underlyingType = Nullable.GetUnderlyingType(sourceType);
                    if (underlyingType != null)
                    {
                        // check for not null
                        Label notNullLabel = il.DefineLabel();

                        var nullableHolder = il.DeclareLocal(propInfo.MemberType);
                        il.Emit(OpCodes.Stloc, nullableHolder);
                        il.Emit(OpCodes.Ldloca_S, nullableHolder);
                        il.Emit(OpCodes.Call, sourceType.GetProperty("HasValue").GetGetMethod());
                        il.Emit(OpCodes.Brtrue_S, notNullLabel);

                        // it's null, just return null
                        il.Emit(OpCodes.Ldnull);
                        il.Emit(OpCodes.Ret);

                        il.MarkLabel(notNullLabel);

                        // it's not null, so unbox to the underlyingtype
                        il.Emit(OpCodes.Ldloca, nullableHolder);
                        il.Emit(OpCodes.Call, sourceType.GetProperty("Value").GetGetMethod());

                        // at this point we have de-nulled value, so use those converters
                        sourceType = underlyingType;
                    }

                    if (sourceType != targetType && !sourceType.IsValueType && sourceType != typeof(string))
                    {
                        // if the provider type is Xml, then serialize the value
                        var serializerMethod = mapping.Serializer.GetMethod("Serialize", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(Type) }, null);
                        if (serializerMethod == null)
                        {
                            throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Serializer type {0} needs the method 'public static string Serialize(object, Type)'", mapping.Serializer.Name));
                        }

                        il.EmitLoadType(sourceType);
                        il.Emit(OpCodes.Call, serializerMethod);
                    }
                    else
                    {
                        // attempt to convert the value
                        // either way, we are putting it in an object variable, so box it
                        if (TypeConverterGenerator.EmitConversionOrCoersion(il, sourceType, targetType))
                        {
                            il.Emit(OpCodes.Box, targetType);
                        }
                        else
                        {
                            il.Emit(OpCodes.Box, sourceType);
                        }
                    }

                    il.Emit(OpCodes.Ret);

                    _memberTypes[i] = propInfo.MemberType;
                    _accessors[i]   = (Func <object, object>)dm.CreateDelegate(typeof(Func <object, object>));
                }
            }
            else
            {
                // we are working off a single-column atomic type
                _memberTypes = new Type[1] {
                    type
                };
                _accessors = new Func <object, object>[] { o => o };
            }
        }
Example #4
0
        private static DynamicMethod CreateClassDeserializerDynamicMethod(Type type, IDataReader reader, IRecordStructure structure, int startColumn, int columnCount, bool createNewObject, bool isRootObject, bool allowBindChild)
        {
            // if there are no columns detected for the class, then the deserializer is null
            if (columnCount == 0 && !isRootObject)
            {
                return(null);
            }

            var mappings = MapColumns(type, reader, startColumn, columnCount, structure, allowBindChild && isRootObject);

            // need to know the constructor for the object (except for structs)
            bool            isStruct    = type.GetTypeInfo().IsValueType;
            ConstructorInfo constructor = createNewObject ? SelectConstructor(type) : null;

            // the method can either be:
            // createNewObject => Func<IDataReader, T>
            // !createNewObject => Func<IDataReader, T, T>
            // create a new anonymous method that takes an IDataReader and returns the given type
            var dm = new DynamicMethod(
                String.Format(CultureInfo.InvariantCulture, "Deserialize-{0}-{1}", type.FullName, Guid.NewGuid()),
                type,
                createNewObject ? new[] { typeof(IDataReader) } : new[] { typeof(IDataReader), type },
                true);

            // get the il generator and put some local variables on the stack
            var il                  = dm.GetILGenerator();
            var localIndex          = il.DeclareLocal(typeof(int));
            var localResult         = il.DeclareLocal(type);
            var localValue          = il.DeclareLocal(typeof(object));
            var localIsNotAllDbNull = il.DeclareLocal(typeof(bool));

            // initialization
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Stloc, localIndex);

            /////////////////////////////////////////////////////////////////////
            // read all of the values into local variables
            /////////////////////////////////////////////////////////////////////
            il.BeginExceptionBlock();
            var localValues = new LocalBuilder[mappings.Count];

            for (int index = 0; index < columnCount; index++)
            {
                var mapping = mappings[index];
                if (mapping == null)
                {
                    continue;
                }

                var member = mapping.Member;

                localValues[index] = il.DeclareLocal(member.MemberType);

                // need to call IDataReader.GetItem to get the value of the field
                il.Emit(OpCodes.Ldarg_0);
                IlHelper.EmitLdInt32(il, index + startColumn);

                // before we call it, put the current index into the index local variable
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc, localIndex);

                // now call it
                il.Emit(OpCodes.Callvirt, _iDataReaderGetItem);

                // if handling a subobject, we check to see if the value is null
                if (startColumn > 0)
                {
                    var afterNullCheck = il.DefineLabel();
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Ldsfld, typeof(DBNull).GetField("Value"));
                    il.Emit(OpCodes.Ceq);
                    il.Emit(OpCodes.Brtrue, afterNullCheck);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Stloc, localIsNotAllDbNull);
                    il.MarkLabel(afterNullCheck);
                }

                // store the value as a local variable in case type conversion fails
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc, localValue);

                // convert the value and store it locally
                Type sourceType = reader.GetFieldType(index + startColumn);
                TypeConverterGenerator.EmitConvertValue(il, member.Name, sourceType, member.MemberType, mapping.Serializer);
                il.Emit(OpCodes.Stloc, localValues[index]);
            }

            /////////////////////////////////////////////////////////////////////
            // catch translation exceptions and rethrow
            /////////////////////////////////////////////////////////////////////
            il.BeginCatchBlock(typeof(Exception));                                              // stack => [Exception]
            il.Emit(OpCodes.Ldloc, localIndex);                                                 // push loc.0, stack => [Exception][index]
            il.Emit(OpCodes.Ldarg_0);                                                           // push arg.0, stack => [Exception][index][reader]
            il.Emit(OpCodes.Ldloc, localValue);                                                 // push loc.3, stack => [Exception][index][reader][value]
            il.Emit(OpCodes.Call, TypeConverterGenerator.CreateDataExceptionMethod);
            il.Emit(OpCodes.Throw);                                                             // stack => DataException
            il.EndExceptionBlock();

            /////////////////////////////////////////////////////////////////////
            // if this was a subobject and all of the values are null, then return the default for the object
            /////////////////////////////////////////////////////////////////////
            if (startColumn > 0)
            {
                var afterNullExit = il.DefineLabel();
                il.Emit(OpCodes.Ldloc, localIsNotAllDbNull);
                il.Emit(OpCodes.Brtrue, afterNullExit);
                TypeHelper.EmitDefaultValue(il, type);
                il.Emit(OpCodes.Ret);
                il.MarkLabel(afterNullExit);
            }

            /////////////////////////////////////////////////////////////////////
            // call the constructor
            /////////////////////////////////////////////////////////////////////
            if (createNewObject)
            {
                if (isStruct)
                {
                    il.Emit(OpCodes.Ldloca_S, localResult);
                    il.Emit(OpCodes.Initobj, type);
                    if (constructor != null)
                    {
                        il.Emit(OpCodes.Ldloca_S, localResult);
                    }
                }

                // if there is a constructor, then populate the values
                if (constructor != null)
                {
                    foreach (var p in constructor.GetParameters())
                    {
                        var mapping = mappings.Where(m => m != null).SingleOrDefault(m => m.Member.Name.IsIEqualTo(p.Name));
                        if (mapping != null)
                        {
                            il.Emit(OpCodes.Ldloc, localValues[mappings.IndexOf(mapping)]);
                        }
                        else
                        {
                            TypeHelper.EmitDefaultValue(il, p.ParameterType);
                        }
                    }
                }

                if (isStruct)
                {
                    if (constructor != null)
                    {
                        il.Emit(OpCodes.Call, constructor);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Newobj, constructor);
                    il.Emit(OpCodes.Stloc, localResult);
                }
            }
            else
            {
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Stloc, localResult);
            }

            /////////////////////////////////////////////////////////////////////
            // for anything not passed to the constructor, copy the local values to the properties
            /////////////////////////////////////////////////////////////////////
            for (int index = 0; index < columnCount; index++)
            {
                var mapping = mappings[index];
                if (mapping == null)
                {
                    continue;
                }

                var member = mapping.Member;
                if (!member.CanSetMember)
                {
                    continue;
                }

                // don't set values that have already been set
                if (constructor != null && constructor.GetParameters().Any(p => p.Name.IsIEqualTo(mapping.Member.Name)))
                {
                    continue;
                }

                // load the address of the object we are working on
                if (isStruct)
                {
                    il.Emit(OpCodes.Ldloca_S, localResult);
                }
                else
                {
                    il.Emit(OpCodes.Ldloc, localResult);
                }

                // for deep mappings, go to the parent of the field that we are trying to set
                var nextLabel = il.DefineLabel();
                if (mapping.IsDeep)
                {
                    ClassPropInfo.EmitGetValue(type, mapping.Prefix, il);

                    // if the mapping parent is nullable, check to see if it is null.
                    // if so, pop the parent off the stack and move to the next field
                    if (!ClassPropInfo.FindMember(type, mapping.Prefix).MemberType.GetTypeInfo().IsValueType)
                    {
                        var notNullLabel = il.DefineLabel();
                        il.Emit(OpCodes.Dup);
                        il.Emit(OpCodes.Brtrue, notNullLabel);
                        il.Emit(OpCodes.Pop);
                        il.Emit(OpCodes.Br, nextLabel);
                        il.MarkLabel(notNullLabel);
                    }
                }

                // load the value from the local and set it on the object
                il.Emit(OpCodes.Ldloc, localValues[index]);
                member.EmitSetValue(il);
                il.MarkLabel(nextLabel);

                /////////////////////////////////////////////////////////////////////
                // stack should be [target] and ready for the next column
                /////////////////////////////////////////////////////////////////////
            }

            /////////////////////////////////////////////////////////////////////
            // load the return value from the local variable
            /////////////////////////////////////////////////////////////////////
            il.Emit(OpCodes.Ldloc, localResult);                                                        // ld loc.1 (target), stack => [target]
            il.Emit(OpCodes.Ret);

            // create the function
            return(dm);
        }
Example #5
0
        /// <summary>
        /// Creates a converter from output parameters to an object of a given type.
        /// </summary>
        /// <param name="command">The command to analyze for the results.</param>
        /// <param name="type">The type to put the values into.</param>
        /// <returns>The converter method.</returns>
        private static Action <IDbCommand, object> CreateClassOutputParameterConverter(IDbCommand command, Type type)
        {
            // get the parameters
            List <IDataParameter> parameters = command.Parameters.Cast <IDataParameter>().ToList();

            // if there are no output parameters, then return an empty method
            if (!parameters.Cast <IDataParameter>().Any(p => p.Direction.HasFlag(ParameterDirection.Output)))
            {
                return (IDbCommand c, object o) => { }
            }
            ;

            // create a dynamic method
            Type typeOwner = type.HasElementType ? type.GetElementType() : type;

            // start creating a dynamic method
            var dm = new DynamicMethod(String.Format(CultureInfo.InvariantCulture, "CreateOutputParameters-{0}", Guid.NewGuid()), null, new[] { typeof(IDbCommand), typeof(object) }, typeOwner, true);
            var il = dm.GetILGenerator();

            var localParameters = il.DeclareLocal(typeof(IDataParameterCollection));

            // get the parameters collection from the command into loc.0
            il.Emit(OpCodes.Ldarg_0);                                                                           // push arg.0 (command), stack => [command]
            il.Emit(OpCodes.Callvirt, _iDbCommandGetParameters);                                                // call getparams, stack => [parameters]
            il.Emit(OpCodes.Stloc, localParameters);

            // go through all of the mappings
            var mappings = ColumnMapping.MapParameters(type, command, parameters);

            for (int i = 0; i < mappings.Count; i++)
            {
                var finishLabel = il.DefineLabel();

                // if there is no parameter for this property, then skip it
                var mapping = mappings[i];
                if (mapping == null)
                {
                    continue;
                }

                // if the property is readonly, then skip it
                var prop = mapping.Member;
                if (!prop.CanSetMember)
                {
                    continue;
                }

                // if the parameter is not output, then skip it
                IDataParameter parameter = parameters[i];
                if (parameter == null || !parameter.Direction.HasFlag(ParameterDirection.Output))
                {
                    continue;
                }

                // push the object on the stack. we will need it to set the value below
                il.Emit(OpCodes.Ldarg_1);

                // if this is a deep mapping, then get the parent object, and do a null test if its not a value type
                if (mapping.IsDeep)
                {
                    ClassPropInfo.EmitGetValue(type, mapping.Prefix, il);

                    if (!ClassPropInfo.FindMember(type, mapping.Prefix).MemberType.GetTypeInfo().IsValueType)
                    {
                        il.Emit(OpCodes.Dup);
                        var label = il.DefineLabel();
                        il.Emit(OpCodes.Brtrue, label);
                        il.Emit(OpCodes.Pop);               // pop the object before finishing
                        il.Emit(OpCodes.Br, finishLabel);
                        il.MarkLabel(label);
                    }
                }

                // get the parameter out of the collection
                il.Emit(OpCodes.Ldloc, localParameters);
                il.Emit(OpCodes.Ldstr, parameter.ParameterName);                 // push (parametername)
                il.Emit(OpCodes.Callvirt, _iDataParameterCollectionGetItem);

                // get the value out of the parameter
                il.Emit(OpCodes.Callvirt, _iDataParameterGetValue);

                // emit the code to convert the value and set it on the object
                TypeConverterGenerator.EmitConvertAndSetValue(il, _dbTypeToTypeMap[parameter.DbType], mapping);
                il.MarkLabel(finishLabel);
            }

            il.Emit(OpCodes.Ret);

            return((Action <IDbCommand, object>)dm.CreateDelegate(typeof(Action <IDbCommand, object>)));
        }
Example #6
0
        private static Action <IDbCommand, object> CreateClassInputParameterGenerator(IDbCommand command, Type type)
        {
            var provider   = InsightDbProvider.For(command);
            var parameters = provider.DeriveParameters(command);

            // special case if the parameters object is an IEnumerable or Array
            // look for the parameter that is a Structured object and pass the array to the TVP
            // note that string supports ienumerable, so exclude atomic types
            var enumerable = type.GetInterfaces().FirstOrDefault(i => i.GetTypeInfo().IsGenericType&& i.GetGenericTypeDefinition() == typeof(IEnumerable <>));

            if (enumerable != null && type != typeof(string) && parameters.OfType <IDataParameter>().Where(p => p.Direction.HasFlag(ParameterDirection.Input)).Count() == 1)
            {
                return((IDbCommand cmd, object o) =>
                {
                    // don't use the provider above. The command may be unwrapped by the time we get back here
                    var tableParameter = InsightDbProvider.For(cmd).CloneParameter(cmd, parameters.OfType <IDataParameter>().Single(p => p.Direction.HasFlag(ParameterDirection.Input)));
                    cmd.Parameters.Add(tableParameter);
                    ListParameterHelper.ConvertListParameter(tableParameter, o, cmd);
                });
            }

            // get the mapping of the properties for the type
            var mappings = ColumnMapping.MapParameters(type, command, parameters);

            // start creating a dynamic method
            Type typeOwner = type.HasElementType ? type.GetElementType() : type;
            var  dm        = new DynamicMethod(String.Format(CultureInfo.InvariantCulture, "CreateInputParameters-{0}", Guid.NewGuid()), null, new[] { typeof(IDbCommand), typeof(object) }, typeOwner, true);
            var  il        = dm.GetILGenerator();

            // copy the parameters into the command object
            var parametersLocal = il.DeclareLocal(typeof(IDataParameter[]));

            StaticFieldStorage.EmitLoad(il, provider);
            il.Emit(OpCodes.Ldarg_0);
            StaticFieldStorage.EmitLoad(il, parameters);
            il.Emit(OpCodes.Call, typeof(InsightDbProvider).GetMethod("CopyParameters", BindingFlags.NonPublic | BindingFlags.Instance));
            il.Emit(OpCodes.Stloc, parametersLocal);

            // go through all of the mappings
            for (int i = 0; i < mappings.Count; i++)
            {
                var mapping     = mappings[i];
                var dbParameter = parameters[i];

                // if there is no mapping for the parameter
                if (mapping == null)
                {
                    // sql will silently eat table parameters that are not specified, and that can be difficult to debug
                    if (provider.IsTableValuedParameter(command, dbParameter))
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Table parameter {0} must be specified", dbParameter.ParameterName));
                    }

                    // unspecified input parameters get skipped
                    if (dbParameter.Direction == ParameterDirection.Input)
                    {
                        parameters[i] = null;
                    }

                    continue;
                }

                var memberType = mapping.Member.MemberType;
                var serializer = mapping.Serializer;

                // get the parameter
                il.Emit(OpCodes.Ldloc, parametersLocal);
                il.Emit(OpCodes.Ldc_I4, i);
                il.Emit(OpCodes.Ldelem, typeof(IDataParameter));

                // look up the best type to use for the parameter
                DbType sqlType = LookupDbType(memberType, serializer, dbParameter.DbType);

                // give the provider an opportunity to fix up the template parameter (e.g. set UDT type names)
                provider.FixupParameter(command, dbParameter, sqlType, memberType, mapping.Member.SerializationMode);

                // give a chance to override the best guess parameter
                DbType overriddenSqlType = sqlType;
                if (sqlType != DbTypeEnumerable)
                {
                    overriddenSqlType = ColumnMapping.MapParameterDataType(memberType, command, dbParameter, sqlType);
                }

                ///////////////////////////////////////////////////////////////
                // We have a parameter, start handling all of the other types
                ///////////////////////////////////////////////////////////////
                if (overriddenSqlType != sqlType)
                {
                    sqlType            = overriddenSqlType;
                    dbParameter.DbType = sqlType;
                }

                ///////////////////////////////////////////////////////////////
                // Get the value from the object onto the stack
                ///////////////////////////////////////////////////////////////
                il.Emit(OpCodes.Ldarg_1);
                if (type.GetTypeInfo().IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, type);
                }

                ///////////////////////////////////////////////////////////////
                // Special case support for enumerables. If the type is -1 (our workaround, then call the list parameter method)
                ///////////////////////////////////////////////////////////////
                if (sqlType == DbTypeEnumerable)
                {
                    // we have the parameter and the value as object, add the command
                    ClassPropInfo.EmitGetValue(type, mapping.PathToMember, il);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Call, typeof(ListParameterHelper).GetMethod("ConvertListParameter", BindingFlags.Static | BindingFlags.NonPublic));
                    continue;
                }

                Label readyToSetLabel = il.DefineLabel();
                ClassPropInfo.EmitGetValue(type, mapping.PathToMember, il, readyToSetLabel);

                // special conversions for timespan to datetime
                if ((sqlType == DbType.Time && dbParameter.DbType != DbType.Time) ||
                    (dbParameter.DbType == DbType.DateTime || dbParameter.DbType == DbType.DateTime2 || dbParameter.DbType == DbType.DateTimeOffset))
                {
                    IlHelper.EmitLdInt32(il, (int)dbParameter.DbType);
                    il.Emit(OpCodes.Call, typeof(TypeConverterGenerator).GetMethod("ObjectToSqlDateTime"));
                }

                // if it's class type, boxed value type (in an object), or nullable, then we have to check for null
                var nullableUnderlyingType = Nullable.GetUnderlyingType(memberType);
                if (!memberType.GetTypeInfo().IsValueType || nullableUnderlyingType != null)
                {
                    Label notNull = il.DefineLabel();

                    // check to see if it's not null
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Brtrue, notNull);

                    // it's null. replace the value with DbNull
                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ldsfld, _dbNullValue);

                    // value is set to null. ready to set the property.
                    il.Emit(OpCodes.Br, readyToSetLabel);

                    // we know the value is not null
                    il.MarkLabel(notNull);
                }

                // some providers (notably npgsql > 4.0) don't convert enums to ints, so we do it for them
                if ((memberType != null && memberType.GetTypeInfo() != null && memberType.GetTypeInfo().IsEnum) ||
                    (nullableUnderlyingType != null && nullableUnderlyingType.GetTypeInfo() != null && nullableUnderlyingType.GetTypeInfo().IsEnum))
                {
                    var enumType = nullableUnderlyingType ?? memberType;

                    // ClassPropInfo.EmitGetValue has the enum boxed, so unbox, cast, and re-box
                    switch (dbParameter.DbType)
                    {
                    case DbType.Int16:
                        il.Emit(OpCodes.Unbox_Any, enumType);
                        il.Emit(OpCodes.Conv_I2);
                        il.Emit(OpCodes.Box, typeof(Int16));
                        break;

                    case DbType.Int32:
                        il.Emit(OpCodes.Unbox_Any, enumType);
                        il.Emit(OpCodes.Conv_I4);
                        il.Emit(OpCodes.Box, typeof(Int32));
                        break;

                    case DbType.Int64:
                        il.Emit(OpCodes.Unbox_Any, enumType);
                        il.Emit(OpCodes.Conv_I8);
                        il.Emit(OpCodes.Box, typeof(Int64));
                        break;
                    }
                }

                ///////////////////////////////////////////////////////////////
                // if this is a linq binary, convert it to a byte array
                ///////////////////////////////////////////////////////////////
                if (memberType == TypeHelper.LinqBinaryType)
                {
                    il.Emit(OpCodes.Callvirt, TypeHelper.LinqBinaryToArray);
                }
                else if (memberType == typeof(XmlDocument))
                {
                    // we are sending up an XmlDocument. ToString just returns the classname, so use the outerxml.
                    il.Emit(OpCodes.Callvirt, memberType.GetProperty("OuterXml").GetGetMethod());
                }
                else if (memberType == typeof(XDocument))
                {
                    // we are sending up an XDocument. Use ToString.
                    il.Emit(OpCodes.Callvirt, memberType.GetMethod("ToString", new Type[] { }));
                }
                else if (serializer != null && serializer.CanSerialize(memberType, sqlType))
                {
                    il.EmitLoadType(memberType);
                    StaticFieldStorage.EmitLoad(il, serializer);
                    il.Emit(OpCodes.Call, typeof(DbParameterGenerator).GetMethod("SerializeParameterValue", BindingFlags.NonPublic | BindingFlags.Static));
                }

                ///////////////////////////////////////////////////////////////
                // p.Value = value
                ///////////////////////////////////////////////////////////////
                // push parameter is at top of method
                // value is above
                il.MarkLabel(readyToSetLabel);
                if (memberType == typeof(string))
                {
                    il.Emit(OpCodes.Call, typeof(DbParameterGenerator).GetMethod("SetParameterStringValue", BindingFlags.NonPublic | BindingFlags.Static));
                }
                else if ((memberType == typeof(Guid?) || (memberType == typeof(Guid))) && dbParameter.DbType != DbType.Guid && command.CommandType == CommandType.StoredProcedure)
                {
                    il.Emit(OpCodes.Call, typeof(DbParameterGenerator).GetMethod("SetParameterGuidValue", BindingFlags.NonPublic | BindingFlags.Static));
                }
                else
                {
                    il.Emit(OpCodes.Callvirt, _iDataParameterSetValue);
                }
            }

            il.Emit(OpCodes.Ret);

            return((Action <IDbCommand, object>)dm.CreateDelegate(typeof(Action <IDbCommand, object>)));
        }
		/// <summary>
		/// Create accessors to pull data from the object of the given type for the given schema.
		/// </summary>
		/// <param name="type">The type to analyze.</param>
		/// <param name="identity">The schema identity to analyze.</param>
		/// <returns>A list of accessor functions to get values from the type.</returns>
		private FieldReaderData CreateFieldReaderData(Type type, SchemaIdentity identity)
		{
			FieldReaderData readerData = new FieldReaderData();

			readerData.Accessors = new List<Func<object, object>>();
			readerData.MemberTypes = new List<Type>();

			for (int i = 0; i < identity.SchemaTable.Rows.Count; i++)
			{
				// get the name of the column
				string name = _schemaTable.Rows[i]["ColumnName"].ToString();

				// create a new anonymous method that takes an object and returns the value
				var dm = new DynamicMethod(string.Format(CultureInfo.InvariantCulture, "GetValue-{0}-{1}", type.FullName, Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);
				var il = dm.GetILGenerator();

				il.Emit(OpCodes.Ldarg_0);						// push object argument
				il.Emit(OpCodes.Isinst, type);					// cast object -> type

				// get the value from the object
				ClassPropInfo propInfo = new ClassPropInfo(type, name);
				propInfo.EmitGetValue(il);
				propInfo.EmitBox(il);

				il.Emit(OpCodes.Ret);

				readerData.MemberTypes.Add(propInfo.MemberType);
				readerData.Accessors.Add((Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>)));
			}

			return readerData;
		}