Reputation: 163
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?
Upvotes: 1
Views: 689
Reputation: 9916
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.
Upvotes: 4
Reputation: 48975
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
.
Upvotes: 0