简体   繁体   中英

“The ObjectContext instance has been disposed” for non-EF entities

I'm using Entity Framework 6 to query some objects via a stored procedure which returns a Complex object. Before returning these objects to client, I "translate" them into client-specific entities.

On the server side, I have the following code to get complex objects of type DBMeeting from the database:

public static IEnumerable<Meeting> GetMeetings()
{
    using(var context = new MyDataContext())
    {
        var dbMeetings = context.GetMeetings(null, null);
        var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings);
        return result;
    }
}

And the TranslateMeetings method:

internal static IEnumerable<Meeting> TranslateMeetings(IEnumerable<DBMeeting> dbMeetings)
{
    foreach (var dbMeeting in dbMeetings)
    {
        yield return TranslateMeeting(dbMeeting);
    }
}

internal static Meeting TranslateMeeting(DBMeeting dbMeeting)
{
    return new Meeting
    {
        Id = dbMeeting.ID,
        Name = dbMeeting.Name,
        Description = dbMeeting.Description
        // other properties
    };
}

Now on the client side when I call GetMeetings() and try to enumerate through the list, I get an InvalidOperationException saying:

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

I specifically don't want to run a .ToList() on the server side because I want to the enumeration to happen on the client side. In my TranslateMeetings() method however, I'm creating new Meeting objects which are NOT mapped to my model in any way. So why does it require the context to exist still? Why is EF trying to keep track of non-mapped ( Meeting ) objects?

The issue is that Entity Framework uses deferred evaluation. It won't try to get the objects out of the database until it absolutely has to.

In additon, by using yield return in your TranslateMeetings method, you're using deferred evaluation there to. The code in that method is not run until an you actually iterate over it.

So by the time you return the result the call still hasn't been made to the database. Later on, when you try and iterate over the result , the TranslateMeetings method will then try to iterate over the dbMeetings object. That will trigger entity framework to execute the SQL and try to populate the dbMeetings . But by then the context has been disposed of, so the call fails.

I know you said you didn't want to run .ToList(), but that's pretty much what you have to do. You can't defer evaluation until after the context has been disposed of! The client (I assume this is an API?) can't be the one to execute the Entity Framework. It just doesn't work like that. The client needs to be receiving populated objects.

Well that's because you've disposed the EF context once the end of the using scope is reached:

using(var context = new MyDataContext())
{
    var dbMeetings = context.GetMeetings(null, null);
    var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings);
    return result;
}

And you're trying to access to the entities later , when you enumerate the IEnumerable .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM