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(); }
/// <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 }; } }