I often use the System.Data.Entity.DbExtensions Include() method to cause complex entity fields to be included in query results from my repositories. However, when I project my entities into new classes, I seem to lose this "concretization" of included complex entity fields. For example, say I wanted to return an Event object from my repo, and be able to access the complex entity field Assessment:
public class EventRepository {
...
public IList<Event> GetEvents() {
using (var context = new MyDatabaseContext()) {
return context.Events
.Include(evnt => evnt.ActualAssessment)
.ToList();
}
}
...
}
I can then run the following code without a hitch because of the Include I used above:
var repoEvents = new EventRepository();
var events = repoEvents.GetEvents();
Console.WriteLine(events[0].ActualAssessment.AssessmentDate.ToString());
But say I now want to project the Events into a wrapper object ExtendedEvent with some extra info, like this:
public class EventRepository {
...
public IList<ExtendedEvent> GetExtendedEvents() {
using (var context = new MyDatabaseContext()) {
return context.Events
.Include(evnt => evnt.ActualAssessment)
.Select(evnt => new {
TheEvent = evnt,
SomeExtraData = 123
})
.ToList()
.Select(evntInfo => {
return new ExtendedEvent {
TheEvent = evntInfo.TheEvent,
SomeExtraData = evntInfo.SomeExtraData
};
})
.ToList();
}
}
...
}
I now try and run this code:
var repoEvents = new EventRepository();
var extendedEvents = repoEvents.GetExtendedEvents();
Console.WriteLine(extendedEvents[0].TheEvent.ActualAssessment.AssessmentDate.ToString());
This gives me the error "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." - so ActualAssessment has not been eager-loaded despite my use of Include, apparently because I projected it into a new wrapper object. How can I cause ActualAssessment to be included?
Yes, Include is ignored in projections. What you can try is to make the related navigation property part of your projection into the anonymous object:
public IList<ExtendedEvent> GetExtendedEvents() {
using (var context = new MyDatabaseContext()) {
return context.Events
.Select(evnt => new {
TheEvent = evnt,
SomeExtraData = 123,
ActualAssessment = evnt.ActualAssessment
})
.ToList()
.Select(evntInfo => {
return new ExtendedEvent {
TheEvent = evntInfo.TheEvent,
SomeExtraData = evntInfo.SomeExtraData
};
})
.ToList();
}
}
The ActualAssessment will be attached to the context and automatic relationship fixup will popolate TheEvent.ActualAssessment if
As a side note: You can use AsEnumerable() instead of the first ToList() to avoid the unnecessary overhead of creating a list of anonymous objects.
Edit
For a many-to-many relationship or in case of disabled change tracking you must set the navigation property after the DB query is materialized, like so for example:
.Select(evntInfo => {
evntInfo.TheEvent.ActualAssessment = evntInfo.ActualAssessment;
return new ExtendedEvent {
TheEvent = evntInfo.TheEvent,
SomeExtraData = evntInfo.SomeExtraData
};
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With