Entity Framework - Load Reference Keys after dispo

2019-05-30 11:16发布

问题:

I am using ASP.Net / WebForms / Entity Model / Framework 3.5

Here is my project's simple structure Forms > BLL > DAL ( uses entity model )

Here is my DAL's snippet

public class MyDAL : IDisposable
{
    private MyEntities db;
    public BaseDAL()
    {
        db = new MyEntities();
    }

    public User GetUserByID(int userId)
    {
        try
        {
            IQueryable<User> objUser = null;
            objUser  = from res in db.Users
                          where res.UserId == userId
                          select res;

            return objUser.FirstOrDefault();
        }
        catch
        {
            throw;
        }
    }

    public void Dispose()
    {
        db.Dispose();
    }
}

I call the DAL's function from my BLL like this

public class MyBLL
{
    public User GetUserByID(int userId)
    {
        try
        {
            using (MyDAL objMyDAL = new MyDAL())
            {
                return objMyDAL.GetUserByID(userId);
            }
        }
        catch
        {
            throw;
        }
    }
}

I am calling the DAL through using block so MyDAL's Dispose event will fire soon after the BLL returns the User object. So at this point ObjectContext instance gets disposed.

Now in my Web Form, I am calling this function like this to get user information and Group details which is a foreign key of user_Group Table in User table

    protected void Page_Load(object sender, EventArgs e)
    {
        MyBLL objMyBll = new MyBLL();

        User objUser = objMyBll.GetUserByID(123);
        objUser.User_GroupReference.Load(); // ERROR LINE
        int groupId = objUser.User_Group.Group_Id;
    }

When the ode comes on line objUser.User_GroupReference.Load(); I get this exception

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

How to resolve this? If I do not do db.Dispose(); in my DAL's dispose method, it works fine and no exceptions comes. But if I do not dispose the db object there, when & where should I dispose it? And how to access Reference Keys after disposed object context?

回答1:

The exception is fired because lazy loading is fired when you access that navigation property but lazy loading works only within scope of context used to load the entity. If you dispose the context you will lose lazy loading ability. There is no way to use lazy loading after context disposal (except attaching the entity to the new context but it will only work if you detach it from the original context before you dispose it).

In your architecture you must use Include to explicitly load every relation you will need in upper layers. If you want to use lazy loading your context must live for the whole duration of the request. In case of web forms it can be handled for example in BeginRequest and EndRequest event handlers where you create context in BeginRequest and dispose it in EndRequest. The context will be stored in HttpContext.Items. You should get the context from this collection (you can make helper method for that) and pass it to constructor of BLL which will in turn pass it to DAL. Don't access HttpContext.Items from BLL or DAL.