/// <summary> /// Creates a deserializer to deserialize an object from an IDataReader. /// </summary> /// <param name="reader">The reader to analyze.</param> /// <param name="type">The type of object to deserialize from the IDataReader.</param> /// <param name="structure">The structure of the object.</param> /// <param name="mappingType">The type of mapping to create.</param> /// <returns> /// A function that takes an IDataReader and deserializes an object of type T. /// The first parameter will be an IDataReader. /// If createNewObject is true, the next parameter will be of type T. /// If useCallback is true, the next parameter will be an Action<object[]>. /// </returns> public static Delegate CreateDeserializer(IDataReader reader, Type type, IRecordStructure structure, SchemaMappingType mappingType) { // process the object graph types var subTypes = structure.GetObjectTypes(); if (subTypes[0] != type) { throw new ArgumentException("The top-level type of the object graph must match the return type of the object.", "structure"); } // if the graph type is not a graph, or just the object, and we don't want a callback function // then just return a one-level graph. if (subTypes.Length == 1 && !mappingType.HasFlag(SchemaMappingType.WithCallback)) { return(CreateClassDeserializer(type, reader, structure, 0, (reader.IsClosed) ? 0 : reader.FieldCount, mappingType.HasFlag(SchemaMappingType.NewObject))); } // we can't deserialize an object graph in an insert/merge because we don't know whether to create subobjects or leave them null. if (!mappingType.HasFlag(SchemaMappingType.NewObject)) { throw new ArgumentException("mappingType must be set to NewObject when deserializing an object graph.", "mappingType"); } // create the graph deserializer if (mappingType.HasFlag(SchemaMappingType.WithCallback)) { return(CreateGraphDeserializerWithCallback(subTypes, reader, structure, mappingType == SchemaMappingType.ExistingObject)); } else { return(CreateGraphDeserializer(subTypes, reader, structure, mappingType == SchemaMappingType.ExistingObject)); } }
/// <summary> /// Get a deserializer to read class T from the given reader. /// </summary> /// <param name="reader">The reader to read from.</param> /// <param name="type">The type of object to deserialize.</param> /// <param name="structure">The structure of the objects in the record.</param> /// <param name="mappingType">The type of mapping to return.</param> /// <returns>A function that can deserialize a T from the reader.</returns> private static Delegate GetDeserializer(IDataReader reader, Type type, IRecordStructure structure, SchemaMappingType mappingType) { if (structure == null) { throw new ArgumentNullException("structure"); } // This method should try to return the deserializer with as little work as possible. // Calculating the SchemaMappingIdentity is relatively expensive, so we will take care of the simple cases first, // Where we can just look up a type in a dictionary. // since these types are single column types, deserializing these types do not depend on the schema that comes back from the database // we don't need to keep a schema identity for these Delegate deserializer = null; if (!_simpleDeserializers.TryGetValue(type, out deserializer) && TypeHelper.IsAtomicType(type)) { deserializer = GetValueDeserializer(type); } // we have a simple deserializer if (deserializer != null) { var genericArgs = structure.GetObjectTypes(); if (genericArgs.Length != 1 || genericArgs[0] != type) { throw new ArgumentException("Column Mapper does not match single column deserialization", "structure"); } return(deserializer); } // at this point, we know that we aren't returning a value type or simple object that doesn't depend on the schema. // so we need to calculate a mapping identity and then create or return a deserializer. SchemaMappingIdentity identity = new SchemaMappingIdentity(reader, structure, mappingType); // try to get the deserializer. if not found, create one. return(_deserializers.GetOrAdd( identity, key => ClassDeserializerGenerator.CreateDeserializer(reader, type, structure, mappingType))); }
/// <summary> /// Creates a deserializer to deserialize an object from an IDataReader. /// </summary> /// <param name="reader">The reader to analyze.</param> /// <param name="type">The type of object to deserialize from the IDataReader.</param> /// <param name="structure">The structure of the object.</param> /// <param name="mappingType">The type of mapping to create.</param> /// <returns> /// A function that takes an IDataReader and deserializes an object of type T. /// The first parameter will be an IDataReader. /// If createNewObject is true, the next parameter will be of type T. /// If useCallback is true, the next parameter will be an Action<object[]>. /// </returns> public static Delegate CreateDeserializer(IDataReader reader, Type type, IRecordStructure structure, SchemaMappingType mappingType) { // process the object graph types var subTypes = structure.GetObjectTypes(); if (subTypes[0] != type) throw new ArgumentException("The top-level type of the object graph must match the return type of the object.", "structure"); // if the graph type is not a graph, or just the object, and we don't want a callback function // then just return a one-level graph. if (subTypes.Length == 1 && !mappingType.HasFlag(SchemaMappingType.WithCallback)) return CreateClassDeserializer(type, reader, structure, 0, (reader.IsClosed) ? 0 : reader.FieldCount, mappingType.HasFlag(SchemaMappingType.NewObject)); // we can't deserialize an object graph in an insert/merge because we don't know whether to create subobjects or leave them null. if (!mappingType.HasFlag(SchemaMappingType.NewObject)) throw new ArgumentException("mappingType must be set to NewObject when deserializing an object graph.", "mappingType"); // create the graph deserializer if (mappingType.HasFlag(SchemaMappingType.WithCallback)) return CreateGraphDeserializerWithCallback(subTypes, reader, structure); else return CreateGraphDeserializer(subTypes, reader, structure); }