忽略连接实体的全局查询过滤器
Posted
技术标签:
【中文标题】忽略连接实体的全局查询过滤器【英文标题】:Ignore global query filter for joined entities 【发布时间】:2020-11-22 17:36:45 【问题描述】:全局查询过滤器在实现租户和软删除功能时非常方便。
但我的问题是,例如,当我使用连接编写查询时
dbContext
.entity1
.Include("entity2.entity3.entity4")
.Where(something)
.select(something)
.toList();
这些实体中的每一个都有全局过滤器,然后在生成的 SQL 中,我为每个 JOIN 获得一个完整的子查询,它选择该实体的所有字段并检查全局过滤器。
但我不想那样。我希望全局过滤器仅适用于查询的根实体 (entity1),并且所有其他实体正常加入。
顺便说一句,实体的关系是:
1 个实体4 -> N 个实体3 1 个实体3 -> N 个实体2 1 个实体2 -> N 个实体1在我的例子中,每个实体都会设置其“租户”字段,当软删除一个实体时,该软删除会级联到它的所有子项和子项。 因为为每个连接检查这些字段完全是浪费时间。
【问题讨论】:
也许你可以试试IgnoreQueryFilters()
禁用全局过滤器。docs.microsoft.com/en-us/ef/core/querying/…。
不能这样做。我需要那些全局过滤器,但我只需要将它们应用于 FROM 实体。它们不得应用于 JOIN 实体
【参考方案1】:
目前您不能忽略Include
中的查询过滤器。在 EF Core 存储库中有 an issue 关于改进查询过滤器,但它不会进入 EF Core 5。
一种可能有帮助的方法是运行多个查询并依靠 EF Core 的关系修复功能将事物连接在一起(我在我的文章 EF Core In depth – what happens when EF Core reads from the database? 中解释了关系修复)。
这是一个执行两个查询的示例,其中关系修复将连接在一起。
var mainEntities = dbContext.entity1
.Where(something)
.Select(something) //But must contain the ent1 primary key, e.g. Id
.ToList();
var ent2list = dbContext.entity2.IgnoreQueryFilters()
.Include("entity3.entity4")
.Where(ent2 => mainEntities.Select(ent1 => ent1.Id).Contains(ent2.Id)
.ToList();
在此 EF Core 的关系修复结束时,将在适当的 entity1 实例中填充 entity2 导航属性。注意:如果您使用 AsNoTracking
,则关系修复不起作用。
【讨论】:
我认为您在示例中犯了一些错误。第一个查询真的需要 .toList();。在第一个查询中选择指向 entity2 的外键不是更重要吗?以这种方式更改您的示例后,我得到与以前相同的结果,但生成了不同的 SQL 查询。但我不知道该查询是否更快 不,您需要 entity1 查询上的 .ToList() 。您的问题是如何使用查询过滤器加载 entity1,然后在没有查询过滤器的情况下加载 entity2、3、4。你没有问性能。为了提高性能,我认为您需要查看实体的设计和软删除以在性能上产生任何重大差异。 这其实是一个很有启发性的细节,知道的人并不多。但从乔恩那里看到它并不奇怪。 :) 嗨@Leaky。您可能会喜欢我的文章“EF Core 从数据库读取时会发生什么?” thereformedprogrammer.net/… 了解有关 EF Core 查询和身份解析的更多信息。【参考方案2】:我能够使用显式加载来做到这一点。
我不确定这是否能解决您的问题,但我已经使用 ef 5.0.13 进行了测试,它对我有用。
db.Entry(entity01).Reference(t => t.entity02).Query().IgnoreQueryFilters().Load();
【讨论】:
以上是关于忽略连接实体的全局查询过滤器的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 获取一个查询以检查 QueryBuilder 是不是存在两个关系中的至少一个而不忽略其他过滤器
在 Spring Data rest json Response 中动态过滤实体字段