我在使用名为
RegistrationRoundId
的基于环境的属性时遇到 EF Core DbContext 问题,该属性可以在环境上下文中由 RegistrationRoundIdProvider
更改。 RegistrationRoundId
用于 DbContext 的全局查询过滤器,当我请求一个嵌套对象依赖于 RegistrationRoundId
的查询,然后使用 RegistrationRoundId
提供程序更改环境 RegistrationRound
并请求相同的查询时,结果嵌套实体似乎被缓存并与依赖于新 RegistrationRoundId
值的新实体相关联。我尝试将 RegistrationRoundId
声明为 DbContext 的属性并遵循 EF Core 约定,但问题仍然存在。但是,我注意到问题在两种情况下消失了:当我使用 AsNoTracking() 扩展方法时,当我在两个不同的范围内请求两个查询时,我假设这会导致在每个范围内创建一个新的 DbContext 实例。有人可以解释为什么会出现这个问题以及如何解决这个问题吗?
我想知道是否有专业的建议而不是手动和重复的解决方法
这是我的代码片段,显示了问题
// here the parent context of the registration round id, says id1
r = lst.Select(e => (object)new
{
e.Id,
e.StudyYearId,
countRequest = e.Requests.Count,
// requests related to id1 will be present alone here
requests = e.Requests.Select(e => e.RegistrationRoundId).ToList()
})
.FirstOrDefault();
// says id2
using (_currentRegistrationRound.Change(rs[1].Id))
{
r1 = (await qryM.ToListAsync())
.Select(e => (object)new
{
e.Id,
e.StudyYearId,
countRequest = e.Requests.Count,
//here the requests are related to id1 and id2
requests = e.Requests.Select(e => e.RegistrationRoundId).ToList()
})
.FirstOrDefault();
}
// says id3
using (_currentRegistrationRound.Change(Guid.NewGuid()))
{
r2 = (await qryM.ToListAsync())
.Select(e => (object)new
{
e.Id,
e.StudyYearId,
countRequest = e.Requests.Count,
// here the id3 has no related requests, however, id1 and id2 related requests
//are present !!
requests = e.Requests.Select(e => e.RegistrationRoundId).ToList()
})
.FirstOrDefault();
更新
我在 DdContext 中使用了一个简单的依赖属性:
public Guid RegistrationRoundId {get; set;}
并用于检查不幸显示相同错误结果的行为
见下图:
但是,我注意到问题在两种情况下消失了:当我使用
扩展方法时,当我在两个不同的范围内请求两个查询时,我假设这会导致AsNoTracking()
的新实例被创建每个范围。有人可以解释为什么会出现这个问题以及如何解决这个问题吗?DbContext
好了,你看到了问题的原因——跟踪查询.
当您使用跟踪查询和生成的物化实体实例(由于
ToList{Async}
调用)时,即使在数据库查询上应用了全局查询过滤器,结果也会合并到缓存的实体实例中(客户端获胜),而不是替换它们。也没有过滤应用于已经加载的实体。所有这一切都是由于 EF Core 导航修复,并且不要忘记我们可以手动将实例添加到这些跟踪的集合中,同样,不会应用过滤。
查看 Filtered include 文档中的以下段落,因为这两个功能使用同一个过滤子系统(全局查询过滤器只是自动添加过滤器,而在过滤包含中它们是手动指定的):
注意
在跟踪查询的情况下,由于导航修复,Filtered Include 的结果可能出乎意料。之前查询过并存储在 Change Tracker 中的所有相关实体都将出现在 Filtered Include 查询的结果中,即使它们不符合过滤器的要求。在这些情况下使用过滤包含时,请考虑使用
查询或重新创建NoTracking
。DbContext
至于解决方案,如您所见,文档建议使用
NoTracking
查询,因此要么像您已经做的那样添加 AsNoTracking()
,要么使用投影 (Select
) 查询(直接在 LINQ to Entities 查询源上,无需中间 ToList{Async}
和类似),这是您获得所需确切数据的唯一方法。没有涉及 EF Core 跟踪的解决方案,因为该行为是“设计使然”的,而不是错误,并且不太可能更改。