Force inner join from EF Cores Include() on optional relationship
我们将关系从必需更改为可选,现在由EF Core的Include()生成的结果SQL执行的是左外部联接,而不是内部联接。问题在于那些可选实体上具有必需的查询过滤器。
假设我们有以下内容;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class First { public int? SecondId { get; set; } } public class Second { public First First { get; set; } public int ThirdId { get; set; } } public class Third { public Second Second { get; set; } public string Tenant { get; set; } } public class MyContext : DbContext { protected readonly string _tenant; ... modelBuilder.Entity<Third>(p => { p.HasQueryFilter(x => Tenant == _tenant); }); ... } |
然后我们执行以下操作:
1 | MyContext.First.Include(p => p.Second).ThenInclude(p => p.Third); |
由于该关系是可选的,因此这将产生一个LEFT OUTER JOIN。然后,这当然会绕过查询过滤器。有没有办法使它包括一个INNER JOIN呢?
当前,这可以通过在稍后的位置添加更多条件来解决:
1 | .Where(p => p.Second.Third.Tenant == _tenant); |
但这是不希望的,因为在某些情况下,_tenant为空,然后将提供错误的数据。
我知道我可以翻转它并去
1 | MyContext.Third.Include() ... |
但这也是不可取的,因为在这种情况下,First首先有很多其他相关数据,我不想无休止地将Include()。ThenInclude()链接到荒谬的地步。
我可以强制使用可选实体进行内部联接吗?还是我必须为此手动编写SQL?
Can I force inner joins with optional entities?
不能。而且你不应该。因为虽然
我看到的问题是您似乎正在尝试使用
因此,您需要的是查询过滤器。
实际的问题是EF Core全局查询过滤器不支持基于导航属性的条件。这就是为什么这种情况下的人们破坏规范化(引入冗余)并将
话虽这么说,显式查询过滤器(
1 .Where(p => p.Second.Third.Tenant == _tenant);But this is undesirable since in some edge cases the _tenant is null and will then give the wrong data.
好吧,您只需要考虑可选关系的正确条件即可,例如
1 | .Where(p => p.SecondId == null || p.Second.Third.Tenant == _tenant); |
但这实际上显示了每个实体上都没有