实体框架核心:如何确保加载导航属性



假设我有以下型号:

public class Subject
{
private List<SubjectResponse> responses;
public int Id { get; private set; }
public IEnumerable<SubjectResponse> Responses => responses.ToList();
public void Foo()
{
// How do I check here if Responses fully has been loaded?
foreach (var response in Responses)
{
// ...
}
}
}
public class SubjectResponse
{
public int Id { get; private set; }
}

如何检查是否已在Foo()中加载所有响应?我可能会检查if (Responses is null),但这并不是在所有情况下都有效。

以下是一个可能出错的最小示例。在一个真正的应用程序中,响应可以加载在一个完全不同的地方。但是h这显示了EF如何修复响应,因此它可以包含条目,但不能包含所有条目。

public async Task Bar()
{
var response = await dbContext.SubjectResponses.SingleAsync(s => s.Id == 1);
var subject = await dbContext.Subjects.SingleAsync(s => s.Id == 1);
subject.Foo();
// subject.Responses now has a count if 1, when there might actually be more responses.
}

我不想使用延迟加载,因为这会影响性能(而且延迟加载不会异步加载相关实体(。Eager和Explicit加载都很好。

编辑:我主要寻找的是一种检查导航属性是否已完全加载的方法,这样我就可以加载它。

您无法检测是否所有相关实体都经过了实体框架。

所显示的内容之所以有效,是因为dbContext.SubjectResponses.SingleAsync(s => s.Id == 1)中的实体的SubjectId为1,并且将被缓存,然后依次附加到dbContext.Subjects.SingleAsync(s => s.Id == 1)的结果。

EF和您的代码都无法知道所有SubjectId为1的SubjectResponses都已从数据库加载,因此您必须显式加载它们:

var subject = await dbContext.Subjects.SingleAsync(s => s.Id == 1);
await dbContext.Entity(subject)
.Reference(s => s.responses)
.LoadAsync();

但你不能这样做,因为Subject.responses是私有的,所以你必须在实体的Foo()方法中这样做,你必须将DbContext注入实体,这将变得一团糟。

为什么不务实地做呢?事先将Responses作为公共自动属性,将Include()作为相关实体:

var subject = await dbContext.Subjects.Include(s => s.Responses).SingleAsync(s => s.Id == 1);

如果相关实体(或实体集合(尚未加载(包含(,则可能引发异常,请参阅不可为null的属性和初始化。

以下是一对多关系的示例:

class MyEntity
{
// Assume read-only access.
public IReadOnlyList<MyRelatedEntity> MyRelatedEntities => 
_myRelatedEntities?.ToList().AsReadOnly() ??
throw new InvalidOperationException("MyRelatedEntities not loaded.");
private readonly IEnumerable<MyRelatedEntity>? _myRelatedEntities = null;
}
class MyRelatedEntity
{
public MyEntity MyEntity
{
get => _myEntity ?? 
throw new InvalidOperationException("MyEntity not loaded.");
set => _myEntity = value;
}
private MyEntity? _myEntity = null;
}

实体框架核心将自动设置支持字段,您可以检测相关实体是否已加载。

不幸的是,这种方法不适用于可选的关系,或者至少我还没有弄清楚如何做到这一点

最新更新