Example #1
0
        private ObjectReader(IDbCommand command, Type type, IDataReader reader)
        {
            var provider = InsightDbProvider.For(command);

            _columns = new List <ColumnInfo>();
            var accessors = new List <Func <object, object> >();

            // create a mapping, and only keep mappings that match our modified schema
            var sourceMappings = ColumnMapping.MapColumns(type, reader).ToList();
            var sourceColumns  = ColumnInfo.FromDataReader(reader);

            IsAtomicType = TypeHelper.IsAtomicType(type);
            if (!IsAtomicType)
            {
                int columnCount = sourceMappings.Count;

                for (int i = 0; i < columnCount; i++)
                {
                    var mapping = sourceMappings[i];
                    var column  = sourceColumns[i];
                    if (column.IsReadOnly && !column.IsIdentity)
                    {
                        continue;
                    }

                    _columns.Add(column);

                    if (mapping == null)
                    {
                        accessors.Add(null);
                    }
                    else
                    {
                        accessors.Add(GenerateAccessor(type, mapping, column));
                    }
                }
            }
            else
            {
                var column = sourceColumns.First();

                _columns.Add(column);
                accessors.Add(GenerateAccessor(type, null, column));
            }

            _accessors = accessors.ToArray();
        }
Example #2
0
        /// <summary>
        /// Maps the columns.
        /// </summary>
        /// <param name="type">The type being mapped.</param>
        /// <param name="reader">The reader being read.</param>
        /// <param name="startColumn">The start column index.</param>
        /// <param name="columnCount">The number of columns.</param>
        /// <param name="structure">The record structure, which may contain custom mapping.</param>
        /// <param name="allowBindChild">True if the context allows binding children (e.g. Merge Outputs)</param>
        /// <returns>The mapping.</returns>
        private static List <FieldMapping> MapColumns(Type type, IDataReader reader, int startColumn, int columnCount, IRecordStructure structure, bool allowBindChild = false)
        {
            // get the mapping from the reader to the type, excluding deep mappings
            var mapping = ColumnMapping.MapColumns(type, reader, startColumn, columnCount, structure);

            if (!allowBindChild)
            {
                for (int i = 0; i < mapping.Count; i++)
                {
                    if (mapping[i] != null && mapping[i].IsDeep)
                    {
                        mapping[i] = null;
                    }
                }
            }

            return(mapping);
        }
        private ObjectReader(IDbCommand command, Type type, IDataReader reader)
        {
            var provider = InsightDbProvider.For(command);

            // create a mapping, and only keep mappings that match our modified schema
            var mappings = ColumnMapping.MapColumns(type, reader).ToList();

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

            IsAtomicType = TypeHelper.IsAtomicType(type);
            if (!IsAtomicType)
            {
                int columnCount = SchemaTable.Rows.Count;
                _accessors   = new Func <object, object> [columnCount];
                _memberTypes = new Type[columnCount];

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

                    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     = (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))
                    {
                        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);

                    _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 };
            }
        }