/// <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&lt;object[]&gt;.
		/// </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);
		}
        /// <summary>
        /// Initializes a new instance of the SchemaMappingIdentity class.
        /// </summary>
        /// <param name="schemaIdentity">The identity of the schema to map to.</param>
        /// <param name="recordReader">The reader to use to read the objects from the stream.</param>
        /// <param name="mappingType">The type of mapping operation.</param>
        public SchemaMappingIdentity(SchemaIdentity schemaIdentity, IRecordReader recordReader, SchemaMappingType mappingType)
        {
            if (recordReader == null)
            {
                throw new ArgumentNullException("recordReader");
            }

            // save the values away for later
            RecordReader    = recordReader;
            _mappingType    = mappingType;
            _schemaIdentity = schemaIdentity;

            // we know that we are going to store this in a hashtable, so pre-calculate the hashcode
            unchecked
            {
                // base the hashcode on the mapping type, target graph, and schema contents
                _hashCode  = (int)_mappingType;
                _hashCode *= 13;
                _hashCode += RecordReader.GetHashCode();
                _hashCode *= 13;
                _hashCode += schemaIdentity.GetHashCode();
            }
        }
		/// <summary>
		/// Creates a deserializer to deserialize an object from an IDataReader.
		/// </summary>
		/// <typeparam name="T">The type of object to be returned from the function.</typeparam>
		/// <param name="reader">The reader to analyze.</param>
		/// <param name="type">The type of object to deserialize from the IDataReader.</param>
		/// <param name="withGraph">The type of the graph of object to be returned, or null/typeof(T) to deserialize just the top-level object.</param>
		/// <param name="idColumns">An optional mapping of type to Id columns used for splitting and object graph.</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&lt;object[]&gt;.
		/// </returns>
		public static Delegate CreateDeserializer(IDataReader reader, Type type, Type withGraph, Dictionary<Type, string> idColumns, SchemaMappingType mappingType)
		{
			// if the graph isn't specified, look for a defaultgraphattribute, or just do a one-level graph
			if (withGraph == null)
			{
				DefaultGraphAttribute defaultGraph = type.GetCustomAttributes(typeof(DefaultGraphAttribute), true).OfType<DefaultGraphAttribute>().FirstOrDefault();
				if (defaultGraph != null)
					withGraph = defaultGraph.GetGraphTypes()[0];
				else
					withGraph = typeof(Graph<>).MakeGenericType(type);
			}

			// make sure that withGraph is a graph
			if (!withGraph.IsSubclassOf(typeof(Graph)))
				throw new ArgumentException("withGraph passed in must be of Graph<T>", "withGraph");

			// process the object graph types
			Type[] subTypes = withGraph.GetGenericArguments();
			if (subTypes[0] != type)
				throw new ArgumentException("The top-level type of the object graph must match the return type of the object.", "withGraph");

			// 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, 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, idColumns);
			else
				return CreateGraphDeserializer(subTypes, reader, idColumns);
		}
        /// <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)));
        }
Beispiel #5
0
        /// <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&lt;object[]&gt;.
        /// </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>
 /// Initializes a new instance of the SchemaMappingIdentity class.
 /// </summary>
 /// <param name="reader">The reader to construct from.</param>
 /// <param name="recordReader">The reader to use to read the objects from the stream.</param>
 /// <param name="mappingType">The type of mapping operation.</param>
 public SchemaMappingIdentity(IDataReader reader, IRecordReader recordReader, SchemaMappingType mappingType)
     : this(new SchemaIdentity(reader), recordReader, mappingType)
 {
 }