具有逻辑并使用导航属性的 EF Core NotMapped Getter语言 - 分离的实体不支持延迟加载



我有一个模型Activity它有一些导航属性。

使用 EF 时,我正在使用延迟加载代理来获取所有属性。

属性Status使用导航属性ApprovalStatus

当获取状态为 true 的 LINQ 条件的活动时,它会引发错误

系统无效操作异常:生成警告错误 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadWarning: 尝试在 上延迟加载导航属性"批准状态" 类型为"活动代理"的分离实体。不支持延迟加载 对于分离的实体或加载了 'AsNoTracking(('.">

模型:

public class Activity {
...
public virtual ICollection<Approver> ApprovalStatus {get; set;}

[NotMapped]
public bool? Status {
get {
if (ApprovalStatus.Any(x => ...) return false;
if (ApprovalStatus.All(x => ...) return true;
return null;
}
}
}

我尝试执行的查询:

applicationDbContext.Activities.Where(a => a.Status == true);

但是,如果我将活动转换为条件之前的列表,它会起作用。

applicationDbContext.Activities.ToList().Where(a => a.Status == true);

我的猜测是这是EF Core 2.x。我建议避免使用这种类型的查询表达式,因为 EF Core 3 中的自动查询计算发生了更改,以阻止人们依赖它。我怀疑也存在错误的边缘情况,例如您遇到的客户端评估认为实体是分离的。

在性能方面,从长远来看,依赖延迟加载会受到伤害。您可以考虑集中规则(如 status(的一个选项是将它们反映为域中的表达式/函数。 这适用于布尔表达式,因此需要安排您的"状态"检查以断言特定组合:

public class Activity {
...
public virtual ICollection<Approver> ApprovalStatus {get; set;}
public static Func<Activity, bool> IsApproved() {
return (Activity a) => (a.ApprovalStatus.All(x => ...) 
&& !a.ApprovalStatus.Any(x => ...);
public static Func<Activity, bool> IsRejected() {
return (Activity a) => (!a.ApprovalStatus.All(x => ...) 
|| a.ApprovalStatus.Any(x => ...);
}
}

然后在食用时:

applicationDbContext.Activities.Where(Activity.IsApproved());

您仍然可以在代码中使用用于延迟计算的 unmap 属性:

[NotMapped]
public bool? Status
{
get 
{ 
if(IsApproved().Invoke(this))
return true;
if(IsRejected().Invoke(this))
return false;
return null;
}
}

这种方法的一个警告是,使用Where子句,您不能轻易否定或组合额外的OR条件。例如,以下内容不起作用:

applicationDbContext.Activities.Where(!Activity.IsApproved());

我进行了一些挖掘,看看是否有办法获得它,以便表达式可以是这样的:

applicationDbContext.Activities.Where(x => x.IsApproved());

通过静态扩展方法返回表达式,但我无法获得任何工作。可能有一些 Func/Expression 黑魔法可以工作,并且实际上可以通过 Linq2Entity 实现,但即使是这样,我也希望它看起来很可怕。

IMO 的最佳选择是根据需要使用可用属性编写表达式。 即:

applicationDbContext.Activities.Where(a => (a.ApprovalStatus.All(x => ...) 
&& !a.ApprovalStatus.Any(x => ...)
// ...
);

能够重用表达式可能会很好,但上述选项将是最灵活和性能最佳的选项。

最新更新