Entity framework Code First - configure mapping for SqlQuery

前端 未结 4 726
无人共我
无人共我 2020-12-05 15:24

I\'m using Entity Framework 5 (with Code First approach) to populate a class of mine from a legacy stored procedure with parameters, and this is working fine (details follow

4条回答
  •  春和景丽
    2020-12-05 16:17

    Meanwhile, you can use this method. Few tests (because it worked for my classes) but not to difficult to fix if needed... It need a context (to retrieve mapped custom types) and it need a different connection to run a datareader on it at the same time.

    Usage:
    List students = Mapper.Map(context, (new SchoolContext()).Database.Connection, "Select * from Students");

    public static class Mapper
    {
        /// 
        /// Maps the result of a query into entities.
        /// 
        /// 
        /// The context.
        /// The connection to run the query. Must be different from the one on the context.
        /// The SQL query.
        /// An entity list
        /// 
        /// context
        /// or
        /// queryConnection
        /// or
        /// sqlQuery
        /// 
        public static List Map(DbContext context, DbConnection queryConnection, string sqlQuery) where T:new()
        {
            if (context == null) 
                throw new ArgumentNullException("context");
            if (queryConnection == null)
                throw new ArgumentNullException("queryConnection");
            if (sqlQuery == null) 
                throw new ArgumentNullException("sqlQuery");
    
            var connectionState = queryConnection.State;
    
            if (connectionState != ConnectionState.Open)
                queryConnection.Open();
    
            DbCommand command = queryConnection.CreateCommand();
            command.CommandText = sqlQuery;
            DbDataReader reader = command.ExecuteReader();
    
            List entities = new List();
    
            while (reader.Read())
            {
                entities.Add(InternalMap(context, reader));
            }
    
            if (connectionState != ConnectionState.Open)
                queryConnection.Close();
    
            return entities;
    
        }
    
        private static T InternalMap(DbContext context, DbDataReader reader) where T: new()
        {
    
            T entityObject = new T();
    
            InternalMapEntity(context, reader, entityObject);
    
            return entityObject;
        }
    
        private static void InternalMapEntity(DbContext context, DbDataReader reader, object entityObject)
        {
    
            ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
            var metadataWorkspace = ((EntityConnection)objectContext.Connection).GetMetadataWorkspace();
    
            IEnumerable entitySetMappingCollection = metadataWorkspace.GetItems(DataSpace.CSSpace).Single().EntitySetMappings;
            IEnumerable associationSetMappingCollection = metadataWorkspace.GetItems(DataSpace.CSSpace).Single().AssociationSetMappings;
    
            var entitySetMappings = entitySetMappingCollection.First(o => o.EntityTypeMappings.Select(e => e.EntityType.Name).Contains(entityObject.GetType().Name));
    
            var entityTypeMapping = entitySetMappings.EntityTypeMappings[0];
            string tableName = entityTypeMapping.EntitySetMapping.EntitySet.Name;
            Console.WriteLine(tableName);
    
            MappingFragment mappingFragment = entityTypeMapping.Fragments[0];
    
            foreach (PropertyMapping propertyMapping in mappingFragment.PropertyMappings)
            {
                object value = Convert.ChangeType(reader[((ScalarPropertyMapping) propertyMapping).Column.Name], propertyMapping.Property.PrimitiveType.ClrEquivalentType);
                entityObject.GetType().GetProperty(propertyMapping.Property.Name).SetValue(entityObject, value, null);
                Console.WriteLine("{0} {1} {2}", propertyMapping.Property.Name, ((ScalarPropertyMapping)propertyMapping).Column, value);
            }
    
            foreach (var navigationProperty in entityTypeMapping.EntityType.NavigationProperties)
            {
                PropertyInfo propertyInfo = entityObject.GetType().GetProperty(navigationProperty.Name);
    
                AssociationSetMapping associationSetMapping = associationSetMappingCollection.First(a => a.AssociationSet.ElementType.FullName == navigationProperty.RelationshipType.FullName);
    
                // associationSetMapping.AssociationTypeMapping.MappingFragment.PropertyMappings contains two elements one for direct and one for inverse relationship
                EndPropertyMapping propertyMappings = associationSetMapping.AssociationTypeMapping.MappingFragment.PropertyMappings.Cast().First(p => p.AssociationEnd.Name.EndsWith("_Target"));
    
                object[] key = propertyMappings.PropertyMappings.Select(c => reader[c.Column.Name]).ToArray();
                object value = context.Set(propertyInfo.PropertyType).Find(key);
                propertyInfo.SetValue(entityObject, value, null);
            }
    
        }
    }
    

提交回复
热议问题