如何在计划的实体框架对象中包括复杂的实体字段?
我经常使用System.Data.Entity.DbExtensions
Include()
方法使复杂的实体字段包含在我的存储库的查询结果中.但是,当我将实体投影到新类中时,似乎丢失了包含复杂实体字段的这种具体化".例如,假设我想从我的仓库中返回一个Event
对象,并且能够访问复杂实体字段Assessment
:
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();
}
}
...
}
由于上面使用的Include
,我随后可以顺利运行以下代码:
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());
但是说我现在想将Event
s投影到带有一些额外信息的包装对象ExtendedEvent
中,例如:
But say I now want to project the Event
s 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());
这给了我错误"ObjectContext实例已被处置,并且不能再用于需要连接的操作". -因此,尽管我使用了Include
,但尚未立即加载ActualAssessment
,这显然是因为我将其投影到了新的包装器对象中.如何使ActualAssessment
被包含?
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?
是的,Include
在投影中被忽略.您可以尝试的是使相关导航属性成为投影到匿名对象中的一部分:
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();
}
}
ActualAssessment
将附加到上下文,并且自动关系修复将填充TheEvent.ActualAssessment
如果
The ActualAssessment
will be attached to the context and automatic relationship fixup will popolate TheEvent.ActualAssessment
if
- 您不会禁用更改跟踪
- 这种关系不是多对多的
请注意:您可以使用AsEnumerable()
而不是第一个ToList()
来避免创建匿名对象列表的不必要的开销.
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.
修改
对于多对多关系或在禁用更改跟踪的情况下,必须在实现数据库查询后设置导航属性,例如:
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
};
})