/// <summary> /// Gets one instance of <typeparamref name="T"/> from data reader. /// </summary> /// <typeparam name="T">Type of an instance.</typeparam> /// <param name="reader">Source data reader.</param> /// <param name="ctorParamMappings">Column constructor parameter mappings.</param> /// <param name="propMappings">Property column mappings.</param> /// <param name="breakAfterFirst">true to break after the first read record; false to not. if false throws exception if more than one record.</param> /// <returns>A single instance read from reader or null.</returns> private static T GetInstance <T>(DbDataReader reader, ColumnConstructorParameterMappingCollection <T> ctorParamMappings, IEnumerable <PropertyColumnMapping> propMappings, bool breakAfterFirst) where T : class { T instance = null; if (reader.HasRows) { //// create activator to create instance with constructor var activator = ActivatorFactory.GetActivator <T>(ctorParamMappings.Constructor); Dictionary <string, int> propertyColumnLookupTable = null; //// if contains property mappings, get lookup table if (propMappings != null) { propertyColumnLookupTable = GetColumnIndexLookupTable(reader, propMappings.Select(x => x.ColumnName)); } /// mappings between ctor params and columns var ctorColumnLookupTable = GetColumnIndexLookupTable(reader, ctorParamMappings.Select(x => x.ColumnName)); bool first = true; while (reader.Read()) { if (!first) { throw new InvalidOperationException("Reader contains more than expected 1 record."); } object[] arguments = null; //// get constructor arguments if (ctorParamMappings.HasParameters) { arguments = GetConstructorParameters(reader, ctorColumnLookupTable, ctorParamMappings); } //// create instance instance = activator.Invoke(arguments); //// if contains property mappings, read values if (propMappings != null) { ReadData(instance, reader, propMappings, propertyColumnLookupTable); } if (breakAfterFirst) { break; } first = false; } } return(instance); }
/// <summary> /// Gets all instances from data reader. /// </summary> /// <typeparam name="T">Type of an object read.</typeparam> /// <param name="reader">The source <see cref="DbDataReader"/> instance.</param> /// <param name="ctorMappings">The mappings between constructor arguments and columns.</param> /// <param name="propMappings">The mappings between properties and columns.</param> /// <returns>A enumerable of <typeparamref name="T"/> instances.</returns> public static IEnumerable <T> GetRecords <T>(this DbDataReader reader, ColumnConstructorParameterMappingCollection <T> ctorMappings, IEnumerable <PropertyColumnMapping> propMappings) where T : class { if (reader == null) { throw new ArgumentNullException("reader"); } if (ctorMappings == null) { throw new ArgumentNullException("ctorMappings"); } var result = new List <T>(); if (reader.HasRows) { var activator = ActivatorFactory.GetActivator <T>(ctorMappings.Constructor); Dictionary <string, int> propertyColumnLookupTable = null; //// if contains property mappings, get lookup table if (propMappings != null) { propertyColumnLookupTable = GetColumnIndexLookupTable(reader, propMappings.Select(x => x.ColumnName)); } /// mappings between ctor params and columns var ctorColumnLookupTable = GetColumnIndexLookupTable(reader, ctorMappings.Select(x => x.ColumnName)); while (reader.Read()) { object[] arguments = null; //// get constructor arguments if (ctorMappings.HasParameters) { arguments = GetConstructorParameters(reader, ctorColumnLookupTable, ctorMappings); } var instance = activator.Invoke(arguments); //// if contains property mappings, read values if (propMappings != null) { ReadData(instance, reader, propMappings, propertyColumnLookupTable); } result.Add(instance); } } return(result); }
/// <summary> /// Gets first instance from data reader. /// </summary> /// <typeparam name="T">Type of an object read.</typeparam> /// <param name="reader">The source <see cref="DbDataReader"/> instance.</param> /// <param name="ctorMappings">The mappings between constructor arguments and columns.</param> /// <param name="propMappings">The mappings between properties and columns.</param> /// <returns>A first <typeparamref name="T"/> instance or default <typeparamref name="T"/>.</returns> public static T GetFirstRecord <T>(this DbDataReader reader, ColumnConstructorParameterMappingCollection <T> ctorMappings, IEnumerable <PropertyColumnMapping> propMappings = null) where T : class { if (reader == null) { throw new ArgumentNullException("reader"); } if (ctorMappings == null) { throw new ArgumentNullException("ctorMappings"); } return(GetInstance <T>(reader, ctorMappings, propMappings, true)); }
/// <summary> /// Gets the object array of constructor arguments. /// </summary> /// <typeparam name="T">Type of an instance.</typeparam> /// <param name="reader">Source data reader.</param> /// <param name="lookupTable">Column name column ordinal lookup table.</param> /// <param name="ctorMappings">Column constructor parameter mappings.</param> /// <returns>Object array of constructor parameters.</returns> private static object[] GetConstructorParameters <T>(DbDataReader reader, Dictionary <string, int> lookupTable, ColumnConstructorParameterMappingCollection <T> ctorMappings) where T : class { object[] args = new object[ctorMappings.Count]; foreach (var mapping in ctorMappings) { int ordinal = lookupTable[mapping.ColumnName]; //// read value object value = GetValue(reader, mapping.CanBeNull, ordinal, mapping.ColumnName); //// if mappings does not accept nulls, but null was read //// throw exception if (!mapping.CanBeNull && value == null) { throw new NullReferenceException(String.Format("Constructor parameter does not accept null references, but null was read from column {0}.", mapping.ColumnName)); } //// if value is not null, perform value check if (value != null) { value = CheckValue(value, mapping.ConstructorParameterType); } //// store to arguments array args[mapping.ConstructorParameterIndex] = value; } return(args); }