예제 #1
0
        /// <summary>
        /// Extracts a full object from the current record in a DataReader, mapping return columns to object constructer arguments.
        /// Use this for mapping to immutable types.
        /// </summary>
        public static T ConstructObject <T>(this IDataReader reader, DataMappingOptions options = null)
        {
            if (options == null)
            {
                options = new DataMappingOptions();
            }

            Type type = typeof(T);

            var ctor = type.GetConstructors()
                       .OrderByDescending(x => x.GetParameters().Length)
                       .FirstOrDefault();

            var ctorParameters = ctor.GetParameters();

            var columns = from DataRow row in reader.GetSchemaTable().Rows
                          select new
            {
                Name         = row["ColumnName"].ToString().ToLower(),
                Ordinal      = Convert.ToInt32(row["ColumnOrdinal"]),
                DatabaseType = (Type)row["DataType"]
            };

            var mappings = (from parameter in ctorParameters
                            join column in columns on parameter.Name.ToLower() equals column.Name
                            select new
            {
                Ordinal = column.Ordinal,
                DatabaseType = column.DatabaseType,
                ParameterType = parameter.ParameterType
            }).ToList();

            // Validate
            if (ctorParameters.Length > mappings.Count)
            {
                throw new InvalidOperationException(
                          "Invalid mappings detected.  Attempting to construct an object of type " + type.FullName + " with missing parameter information.\r\n" +
                          "Ctor parameters: " + String.Join(", ", ctorParameters.Select(x => string.Format("{0} {1}", x.ParameterType, x.Name))) + "\r\n" +
                          "Database fields: " + String.Join(", ", columns.Select(x => string.Format("{0} {1}", x.DatabaseType, x.Name))));
            }

            var parameterValues = mappings.Select(mapping => GetValueFromDataReader(reader, mapping.Ordinal, mapping.DatabaseType, mapping.ParameterType, options))
                                  .ToArray();

            var result = ctor.Invoke(parameterValues);

            return((T)result);
        }
예제 #2
0
        /// <summary>
        /// Extracts a full object from the current record in a DataReader, mapping return columns to object properties.
        /// Allows custom mappings of DataReader field values to an object result value via customMappings argument.
        /// </summary>
        public static T GetObject <T>(this IDataReader reader, IDictionary <string, Func <IDataReader, string, object> > customMappings = null, DataMappingOptions options = null)
            where T : new()
        {
            Type type = typeof(T);
            T    obj  = new T();

            if (options == null)
            {
                options = new DataMappingOptions();
            }

            var schema = reader.GetSchemaTable();

            foreach (DataRow row in schema.Rows)
            {
                var column  = row["ColumnName"].ToString();
                var ordinal = Convert.ToInt32(row["ColumnOrdinal"]);
                var dbType  = (Type)row["DataType"];
                var prop    = type.GetProperty(column);

                if (prop != null && prop.CanWrite)
                {
                    if (customMappings != null && customMappings.ContainsKey(column))
                    {
                        object value = customMappings[column](reader, column);
                        prop.SetValue(obj, value);
                    }
                    else
                    {
                        object value = GetValueFromDataReader(reader, ordinal, dbType, prop.PropertyType, options);

                        if (value != null)
                        {
                            prop.SetValue(obj, value);
                        }
                    }
                }
            }

            return(obj);
        }
예제 #3
0
        private static object GetValueFromDataReader(IDataReader reader, int column, Type sourceType, Type destinationType, DataMappingOptions options)
        {
            object value = reader.GetValue(column);

            if (value == DBNull.Value)
            {
                value = null;
            }

            if (value != null)
            {
                if (sourceType != destinationType)
                {
                    if (destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        destinationType = Nullable.GetUnderlyingType(destinationType);
                    }
                }

                if (sourceType == typeof(DateTime))
                {
                    //all of our dataTime values from SQL Server will be interpreted as local time because there is no offset stored, but many of the values are actually UTC, so we need to be able to read them correctly
                    value = DateTime.SpecifyKind((DateTime)value, options.ReadDateTimeAs);
                }

                if (destinationType.IsEnum)
                {
                    if (value is string)
                    {
                        value = Enum.Parse(destinationType, value.ToString(), true);
                    }
                    else
                    {
                        var iValue = Convert.ChangeType(value, Enum.GetUnderlyingType(destinationType));
                        value = Enum.ToObject(destinationType, iValue);
                    }
                }
                else if (sourceType != destinationType)
                {
                    if (destinationType == typeof(string))
                    {
                        value = value.ToString();
                    }
                    else
                    {
                        value = Convert.ChangeType(value, destinationType);
                    }
                }
            }

            return(value);
        }