itnifl
asked on
Eagerly loading related objects in entity framework
I do this:
But when trying to access the attached certificate to an alarm, I catch a ObjectDisposedException: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
So I thought I was going to avoid that by using eager loading as shown above.
Any thoughts?
public List<Alarm> GetSystemIndirectAlarms(Guid systemId) {
using (SQLConnectionContext db = new SQLConnectionContext()) {
/* Check if there are alarms on users attached to this system:*/
List<Alarm> lstUserAlarmsOnSystem = (from alarm in db.Alarms.Include(a => a.Certificate).
Include(a => a.Systems).Include(a => a.User)
join usr in db.Users
on alarm.User.UserID equals usr.UserID
join dsu in db.DataSystemUsers
on usr.UserID equals dsu.User.UserID
where dsu.DataSystem.DataSystemId == systemId && (alarm.ApprovedBy == null || alarm.ApprovedBy == Guid.Empty)
select alarm).ToList();
/* Check if there are alarms on certificates attached to this system: */
List<Alarm> certificateAlarmsOnSystem = (from alarm in db.Alarms.Include(a => a.Certificate)
.Include(a => a.Systems).Include(a => a.User)
join cert in db.Certificates
on alarm.CertificatedId equals cert.CertificateId
where cert.Systems.Any(x => x.DataSystemId == systemId) &&
alarm.ApprovedBy == null || alarm.ApprovedBy == Guid.Empty
select alarm).ToList();
if (lstUserAlarmsOnSystem != null && certificateAlarmsOnSystem != null) {
return (lstUserAlarmsOnSystem.Union(certificateAlarmsOnSystem)).ToList();
} else if (lstUserAlarmsOnSystem != null) {
return lstUserAlarmsOnSystem;
} else if (certificateAlarmsOnSystem != null) {
return certificateAlarmsOnSystem;
}
}
//We seem to have found nothing, so lets return an empty list instead of a null value:
return new List<Alarm>();
}
But when trying to access the attached certificate to an alarm, I catch a ObjectDisposedException: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
So I thought I was going to avoid that by using eager loading as shown above.
Any thoughts?
Where, what line of code are you getting the exception on? If there is also an inner exception please post that as well.
ASKER
Exception screen dump:
I have never seen inner exceptions on these type of exceptions.
They simply means that the Entity Framework context used to load the object from database has been disposed and that any further loading of related objects throws this error (since the context is no longer there to do the work). The loading of related objects only when accessed is called lazy loading. In order to eagerly load these objects so that they are available even after the context is disposed, I use the include statements in line 4 and 5, 15 and 16. The context is declared in line two in the code above. It is terminated when the using clause ends.
This has normally worked in other code previously, but then I used lambda and not linq. It shouldn't matter, I thought.
The code that creates the error is the custom ToString method of the Alarm objects I am selecting. It checks if there Alarm.Certificate == null, but Certificate has not yet been loaded by the context even if Certificate was included in the EF query to fetch it (as described above), and the context to load it is disposed.
So back to the original question (and this is Entity Framework specific), why are the objects I want included with the Alarm objects (in this case alarm.Certificate) not being included/loaded when I specify them to be?
I have never seen inner exceptions on these type of exceptions.
They simply means that the Entity Framework context used to load the object from database has been disposed and that any further loading of related objects throws this error (since the context is no longer there to do the work). The loading of related objects only when accessed is called lazy loading. In order to eagerly load these objects so that they are available even after the context is disposed, I use the include statements in line 4 and 5, 15 and 16. The context is declared in line two in the code above. It is terminated when the using clause ends.
This has normally worked in other code previously, but then I used lambda and not linq. It shouldn't matter, I thought.
The code that creates the error is the custom ToString method of the Alarm objects I am selecting. It checks if there Alarm.Certificate == null, but Certificate has not yet been loaded by the context even if Certificate was included in the EF query to fetch it (as described above), and the context to load it is disposed.
So back to the original question (and this is Entity Framework specific), why are the objects I want included with the Alarm objects (in this case alarm.Certificate) not being included/loaded when I specify them to be?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Yes, my next step was to try to use what I knew worked, the method based approach. But actually I wanted to know and learn why the query based approach didn't work. But since I have no more time to dwell into t his, I will accept the workaround as the solution.
Seeming that this may be a bug you may want to place a bug report with Microsoft to get an answer to your question.