/// <summary> /// Coerces an IDataReader to try and load an object using name/property matching /// </summary> public static void Load <T>(this IDataReader rdr, T item, List <string> ColumnNames) //mike added ColumnNames { Type iType = typeof(T); PropertyInfo[] cachedProps = iType.GetProperties(); FieldInfo[] cachedFields = iType.GetFields(); PropertyInfo currentProp; FieldInfo currentField = null; for (int i = 0; i < rdr.FieldCount; i++) { string pName = rdr.GetName(i); currentProp = cachedProps.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); //mike if the property is null and ColumnNames has data then look in ColumnNames for match if (currentProp == null && ColumnNames != null && ColumnNames.Count > i) { currentProp = cachedProps.First(x => x.Name == ColumnNames[i]); } //if the property is null, likely it's a Field if (currentProp == null) { currentField = cachedFields.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); } if (currentProp != null && !DBNull.Value.Equals(rdr.GetValue(i))) { Type valueType = rdr.GetValue(i).GetType(); if (valueType == typeof(Boolean)) { string value = rdr.GetValue(i).ToString(); currentProp.SetValue(item, value == "1" || value == "True", null); } else if (currentProp.PropertyType == typeof(Guid)) { currentProp.SetValue(item, rdr.GetGuid(i), null); } else if (Objects.IsNullableEnum(currentProp.PropertyType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentProp.PropertyType), rdr.GetValue(i)); currentProp.SetValue(item, nullEnumObjectValue, null); } else if (currentProp.PropertyType.IsEnum) { var flags = currentProp.PropertyType.GetCustomAttributes(typeof(FlagsAttribute), false); Object enumValue; if (flags.Length > 0) { // Find the static TryParse() method. var tryParseInfo = currentProp.PropertyType.BaseType.GetMethods(BindingFlags.Static | BindingFlags.Public)[1];// currentProp.PropertyType.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public); if (tryParseInfo == null) { break; } var parseMethod = tryParseInfo.MakeGenericMethod(currentProp.PropertyType); var methodParams = new[] { rdr.GetValue(i), false, Activator.CreateInstance(currentProp.PropertyType, true) }; parseMethod.Invoke(null, methodParams); enumValue = methodParams[2]; //Enum.TryParse<Enum>(rdr.GetValue(i), false, out enumValue); } else { enumValue = Enum.ToObject(currentProp.PropertyType, rdr.GetValue(i)); } currentProp.SetValue(item, enumValue, null); } else { var val = rdr.GetValue(i); var valType = val.GetType(); var attribs = currentProp.GetCustomAttributes( typeof(SubSonic.SqlGeneration.Schema.SubSonicTypeConversionAttribute), true ); //try to assign it if (attribs != null && attribs.Length == 1) { // ZJG: Use the conversion method provided via this type's metadata. var converter = (SubSonic.SqlGeneration.Schema.SubSonicTypeConversionAttribute)attribs[0]; var newVal = converter.Convert( val, SubSonic.SqlGeneration.Schema.TypeConversionDirection.DatabaseToProperty ); currentProp.SetValue(item, newVal, null); } else if (currentProp.PropertyType.IsAssignableFrom(valueType)) { currentProp.SetValue(item, val, null); } else { currentProp.SetValue(item, val.ChangeTypeTo(currentProp.PropertyType), null); } } } else if (currentField != null && !DBNull.Value.Equals(rdr.GetValue(i))) { Type valueType = rdr.GetValue(i).GetType(); if (valueType == typeof(Boolean)) { string value = rdr.GetValue(i).ToString(); currentField.SetValue(item, value == "1" || value == "True"); } else if (currentField.FieldType == typeof(Guid)) { currentField.SetValue(item, rdr.GetGuid(i)); } else if (Objects.IsNullableEnum(currentField.FieldType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentField.FieldType), rdr.GetValue(i)); currentField.SetValue(item, nullEnumObjectValue); } else { var val = rdr.GetValue(i); var valType = val.GetType(); //try to assign it if (currentField.FieldType.IsAssignableFrom(valueType)) { currentField.SetValue(item, val); } else { currentField.SetValue(item, val.ChangeTypeTo(currentField.FieldType)); } } } } if (item is IActiveRecord) { var arItem = (IActiveRecord)item; arItem.SetIsLoaded(true); arItem.SetIsNew(false); } }
/// <summary> /// Coerces an IDataReader to try and load an object using name/property matching /// </summary> public static void Load <T>(this IDataReader rdr, T item, List <string> ColumnNames) //mike added ColumnNames { Type iType = typeof(T); PropertyInfo[] cachedProps = iType.GetProperties(); FieldInfo[] cachedFields = iType.GetFields(); PropertyInfo currentProp; FieldInfo currentField = null; for (int i = 0; i < rdr.FieldCount; i++) { string pName = rdr.GetName(i); currentProp = cachedProps.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); //mike if the property is null and ColumnNames has data then look in ColumnNames for match if (currentProp == null && ColumnNames != null && ColumnNames.Count > i) { currentProp = cachedProps.First(x => x.Name == ColumnNames[i]); } //if the property is null, likely it's a Field if (currentProp == null) { currentField = cachedFields.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); } if (currentProp != null && !DBNull.Value.Equals(rdr.GetValue(i))) { Type valueType = rdr.GetValue(i).GetType(); if (valueType == typeof(Boolean)) { string value = rdr.GetValue(i).ToString(); currentProp.SetValue(item, value == "1" || value == "True", null); } else if (currentProp.PropertyType == typeof(Guid)) { currentProp.SetValue(item, rdr.GetGuid(i), null); } else if (Objects.IsNullableEnum(currentProp.PropertyType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentProp.PropertyType), rdr.GetValue(i)); currentProp.SetValue(item, nullEnumObjectValue, null); } else { var val = rdr.GetValue(i); var valType = val.GetType(); //try to assign it if (val.GetType().IsAssignableFrom(valueType)) { currentProp.SetValue(item, val, null); } else { currentProp.SetValue(item, rdr.GetValue(i).ChangeTypeTo(valueType), null); } } } else if (currentField != null && !DBNull.Value.Equals(rdr.GetValue(i))) { Type valueType = rdr.GetValue(i).GetType(); if (valueType == typeof(Boolean)) { string value = rdr.GetValue(i).ToString(); currentField.SetValue(item, value == "1" || value == "True"); } else if (currentField.FieldType == typeof(Guid)) { currentField.SetValue(item, rdr.GetGuid(i)); } else if (Objects.IsNullableEnum(currentField.FieldType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentField.FieldType), rdr.GetValue(i)); currentField.SetValue(item, nullEnumObjectValue); } else { currentField.SetValue(item, rdr.GetValue(i).ChangeTypeTo(valueType)); } } } if (item is IActiveRecord) { var arItem = (IActiveRecord)item; arItem.SetIsLoaded(true); arItem.SetIsNew(false); } }
/// <summary> /// Coerces an IDataReader to try and load an object using name/property matching /// </summary> /// <remarks> /// WARNING: There is a bug in this method. If the passed in ColumnNames and the actual column /// order in the data reader aren't the same (which they may not be if you are doing some table /// joins and a projection into an object) /// then this method might put the wrong data into the wrong properties of the object. /// The passed in "ColumnNames" aren't actually the DB column names, they are the projection /// object's property names. This code is assuming that the object's properties are in the same /// order as the DB query's returned columns. (Jeff V.) /// </remarks> public static void Load <T>(this IDataReader rdr, T item, List <string> ColumnNames, PropertyInfo[] cachedProps, FieldInfo[] cachedFields) //mike added ColumnNames { Type iType = typeof(T); // Avoid enumerating properties looking for matching name (performs poorly on large result sets) Dictionary <string, PropertyInfo> cachedPropsByLowerName = cachedProps.ToDictionary(x => x.Name.ToLower(), x => x); Dictionary <string, FieldInfo> cachedFieldsByLowerName = cachedFields.ToDictionary(x => x.Name.ToLower(), x => x); List <string> columnNamesLower = ColumnNames == null ? new List <string>() : ColumnNames.Select(x => x.ToLower()).ToList(); PropertyInfo currentProp; FieldInfo currentField = null; for (int i = 0; i < rdr.FieldCount; i++) { /* These 2 lines can cause a bug, because it tries to find an object property named the same as * a DB column name, which isnt always what the user wanted. Take for example: * * var o = from t in db.SomeTable * where t.COL1 == 'foo' * select new() * { * COL1 = t.COL2, * COL2 = t.COL1 * } * * In this case, the object returned by this method will end up with the properties mapped in reverse * (o.COL1 = t.COL1, o.COL2 = t.COL2 instead of the requested o.COL1 = t.COL2, o.COL2 = t.COL1) * * (Jeff V.) */ string pName = rdr.GetName(i); string pNameLower = pName.ToLower(); //currentProp = cachedProps.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); cachedPropsByLowerName.TryGetValue(pNameLower, out currentProp); //mike if the property is null and ColumnNames has data then look in ColumnNames for match /* This can cause a bug because it assumes ColumnNames is in the same order as the columns * returned by the database, which is not always true. * * It will assign 'rdr.GetValue(i)' to the object property named 'ColumnNames[i]' * but there is no guarantee that rdr's columns and ColumnNames' columns are actually in * the same order as defined by the projection. This leads to some values being assigned * the the wrong property. * * (Jeff V.) */ if (currentProp == null && ColumnNames != null && ColumnNames.Count > i) { //currentProp = cachedProps.First(x => x.Name == ColumnNames[i]); cachedPropsByLowerName.TryGetValue(columnNamesLower[i], out currentProp); } //if the property is null, likely it's a Field if (currentProp == null) { cachedFieldsByLowerName.TryGetValue(pNameLower, out currentField); } //currentField = cachedFields.SingleOrDefault(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase)); var value = rdr.GetValue(i); if (currentProp != null && !DBNull.Value.Equals(value)) { Type valueType = value.GetType(); if (valueType == typeof(Boolean)) { string valueStr = value.ToString(); currentProp.SetValue(item, valueStr == "1" || valueStr == "True", null); } else if (currentProp.PropertyType == typeof(Guid)) { if (rdr[i] is Guid) { currentProp.SetValue(item, rdr.GetGuid(i), null); } else { string guidInString = rdr.GetString(i); Guid guid = new Guid(guidInString); currentProp.SetValue(item, guid, null); } } else if (Objects.IsNullableEnum(currentProp.PropertyType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentProp.PropertyType), value); currentProp.SetValue(item, nullEnumObjectValue, null); } else if (currentProp.PropertyType.IsEnum) { var enumValue = Enum.ToObject(currentProp.PropertyType, value); currentProp.SetValue(item, enumValue, null); } else { //try to assign it if (currentProp.PropertyType.IsAssignableFrom(valueType)) { currentProp.SetValue(item, value, null); } else { currentProp.SetValue(item, value.ChangeTypeTo(currentProp.PropertyType), null); } } } else if (currentField != null && !DBNull.Value.Equals(value)) { Type valueType = value.GetType(); if (valueType == typeof(Boolean)) { string valueStr = value.ToString(); currentField.SetValue(item, valueStr == "1" || valueStr == "True"); } else if (currentField.FieldType == typeof(Guid)) { currentField.SetValue(item, rdr.GetGuid(i)); } else if (Objects.IsNullableEnum(currentField.FieldType)) { var nullEnumObjectValue = Enum.ToObject(Nullable.GetUnderlyingType(currentField.FieldType), value); currentField.SetValue(item, nullEnumObjectValue); } else { //try to assign it if (currentField.FieldType.IsAssignableFrom(valueType)) { currentField.SetValue(item, value); } else { currentField.SetValue(item, value.ChangeTypeTo(currentField.FieldType)); } } } } if (item is IActiveRecord) { var arItem = (IActiveRecord)item; arItem.SetIsLoaded(true); arItem.SetIsNew(false); } }