Entity Framework - Eagerly load object graph using stored procedures

前端 未结 3 1135
情歌与酒
情歌与酒 2021-02-06 10:11

Background

I am changing my LINQ-to-SQL code in my project to Entity Framework. Most of the change over was relatively simple, however, I have run into

3条回答
  •  孤独总比滥情好
    2021-02-06 10:27

    It can be done in a fairly simple way but takes some manual effort. Here is an MSDN post on handling stored procedures with multiple result sets which shows both a code first and database first approach.

    Example:

    Load EntityB proc:

    create proc dbo.Get_EntityB_by_EntityAId( @aId int )
    as
    
    select distinct
        b.EntityBId
        , b.Description
    from
        EntityA a
        left outer join EntityB b
         on a.PrimaryEntityB_EntityBId = b.EntityBId
        left outer join EntityB b2
         on a.AlternativeEntityB_EntityBId = b2.EntityBId
    where
        a.EntityAId = @aId
    go
    

    Load EntityA proc (which calls load B proc)

    create proc dbo.Get_EntityA_by_Id( @id int )
    as
    
    -- use a select statement
    select 
        a.EntityAId
        , a.Description
        , a.PrimaryEntityB_EntityBId
        , a.AlternativeEntityB_EntityBId
    from
        EntityA a
    where
        a.EntityAId = @id
    
    -- and/or other sprocs
    exec dbo.Get_EntityB_by_EntityAId @id
    
    go
    

    Entity classes

    [Table("EntityA")]
    public partial class EntityA
    {
        public int EntityAId { get; set; }
        public string Description { get; set; }
    
    
        public virtual EntityB PrimaryEntityB { get; set; }
    
        public virtual EntityB AlternativeEntityB { get; set; }
    }
    
    
    [Table("EntityB")]
    public partial class EntityB
    {
        public int EntityBId { get; set; }
        public string Description { get; set; }
    
        [InverseProperty("PrimaryEntityB")]
        public virtual ICollection EntityAsViaPrimary { get; set; }
        [InverseProperty( "AlternativeEntityB" )]
        public virtual ICollection EntityAsViaAlternative { get; set; }
    }
    

    Method that calls sproc and handles results (for this method, you could return the one EntityA if you'd like)

    public static void EagerLoadEntityA( int aId )
    {
        using( var db = new TestEntities() )
        {
            // if using code first
            db.Database.Initialize( false );
    
            var cmd = db.Database.Connection.CreateCommand();
            cmd.CommandText = "dbo.Get_EntityA_by_Id";
    
            db.Database.Connection.Open();
    
            try
            {
                var reader = cmd.ExecuteReader();
    
                var objContext = ( ( IObjectContextAdapter )db ).ObjectContext;
    
                var aEntities = objContext
                    .Translate( reader, "EntityAs", MergeOption.AppendOnly );
    
                reader.NextResult();
    
                var bEntities = objContext
                    .Translate( reader, "EntityBs", MergeOption.AppendOnly );
    
            }
            finally
            {
                db.Database.Connection.Close();
            }
        }
    }
    

    Usage:

    EagerLoadEntityA( 1234 );
    var entityA = db.EntityAs.Find( 1234 ); // cached
    var primB = entityA.PrimaryEntityB; // this is already loaded
    

提交回复
热议问题