/// <summary> /// Returns an object reader for the given type that matches the given schema. /// </summary> /// <param name="reader">The reader containing the schema to analyze.</param> /// <param name="type">The type to analyze.</param> /// <returns>An ObjectReader for the schema and type.</returns> public static ObjectReader GetObjectReader(IDataReader reader, Type type) { SchemaIdentity schemaIdentity = new SchemaIdentity(reader); SchemaMappingIdentity mappingIdentity = new SchemaMappingIdentity(schemaIdentity, type, null, SchemaMappingType.ExistingObject); return _readerDataCache.GetOrAdd(mappingIdentity, i => new ObjectReader(i, reader)); }
/// <summary> /// Initializes a new instance of the ObjectListDbDataReader class. /// </summary> /// <param name="schemaTable">The IDbDataReader schema table to use (get it from Sql Server).</param> /// <param name="listType">The type of the list to bind to.</param> /// <param name="list">The list of objects.</param> public ObjectListDbDataReader(DataTable schemaTable, Type listType, IEnumerable list) { _schemaTable = schemaTable; _listType = listType; _list = list.GetEnumerator(); _isValueType = _listType.IsValueType || listType == typeof(string); // SQL Server tells us the precision of the columns // but the TDS parser doesn't like the ones set on money, smallmoney and date // so we have to override them _schemaTable.Columns["NumericScale"].ReadOnly = false; foreach (DataRow row in _schemaTable.Rows) { string dataType = row["DataTypeName"].ToString(); if (String.Equals(dataType, "money", StringComparison.OrdinalIgnoreCase)) row["NumericScale"] = 4; else if (String.Equals(dataType, "smallmoney", StringComparison.OrdinalIgnoreCase)) row["NumericScale"] = 4; else if (String.Equals(dataType, "date", StringComparison.OrdinalIgnoreCase)) row["NumericScale"] = 0; } // if this is not a value type, then we need to have methods to pull values out of the object if (!_isValueType) { // generate an identity for the schema and a key for our accessors SchemaIdentity identity = new SchemaIdentity(schemaTable); Tuple<Type, SchemaIdentity> key = new Tuple<Type, SchemaIdentity>(listType, identity); _readerData = _readerDataCache.GetOrAdd(key, k => CreateFieldReaderData(k.Item1, k.Item2)); } }
/// <summary> /// Returns an object reader for the given type that matches the given schema. /// </summary> /// <param name="command">The command associated with the reader.</param> /// <param name="reader">The reader containing the schema to analyze.</param> /// <param name="type">The type to analyze.</param> /// <returns>An ObjectReader for the schema and type.</returns> public static ObjectReader GetObjectReader(IDbCommand command, IDataReader reader, Type type) { SchemaIdentity schemaIdentity = new SchemaIdentity(reader); var key = Tuple.Create(schemaIdentity, type); return _readerDataCache.GetOrAdd(key, k => new ObjectReader(command, k.Item2, reader)); }
/// <summary> /// Create accessors to pull data from the object of the given type for the given schema. /// </summary> /// <param name="type">The type to analyze.</param> /// <param name="identity">The schema identity to analyze.</param> /// <returns>A list of accessor functions to get values from the type.</returns> private FieldReaderData CreateFieldReaderData(Type type, SchemaIdentity identity) { FieldReaderData readerData = new FieldReaderData(); readerData.Accessors = new List<Func<object, object>>(); readerData.MemberTypes = new List<Type>(); for (int i = 0; i < identity.SchemaTable.Rows.Count; i++) { // get the name of the column string name = _schemaTable.Rows[i]["ColumnName"].ToString(); // create a new anonymous method that takes an object and returns the value var dm = new DynamicMethod(string.Format(CultureInfo.InvariantCulture, "GetValue-{0}-{1}", type.FullName, Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // push object argument il.Emit(OpCodes.Isinst, type); // cast object -> type // get the value from the object ClassPropInfo propInfo = new ClassPropInfo(type, name); propInfo.EmitGetValue(il); propInfo.EmitBox(il); il.Emit(OpCodes.Ret); readerData.MemberTypes.Add(propInfo.MemberType); readerData.Accessors.Add((Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>))); } return readerData; }