实体框架和强制内连接
我的 Table1 具有以下关系(它们不是强制的,它们只是为导航属性创建关系)
Table1 (*)->(1) Table2 Table1 (*)->(1) Table3 Table1 (*)->(1) Table4 Table1 (*)->(1) Table5
使用急切加载代码看起来像
IQueryable<Table1> query = context.Table1s;
query = query.Include(Table1 => Table1.Table2);
query = query.Include(Table1 => Table1.Table3);
query = query.Include(Table1 => Table1.Table4);
query = query.Include(Table1 => Table1.Table5);
query = query.Where(row => row.Table1Id == table1Id);
query.Single();
我尝试组织 Include() 语句的每一种方式,包含的第一个表在其生成的 TSQL 和其余的是左外连接(我希望所有这些都是左外连接)。我不是实体拆分,它们只是带有 FK 的普通表。
如果 DefaultIfEmpty() 是唯一的解决方案,有人可以解释为什么除了第一个表之外的所有表都提供了预期的 SQL 吗?
我的理解是,导航属性的默认行为是 LEFT OUTER,但我无法获取所有属性来生成默认值。
任何帮助将不胜感激。
先感谢您!
----- 创建了 TSQL(为简洁起见进行了修改,但结构相同) ----------
(@p__linq__0 int)SELECT [Limit1].[Table1Id] AS [Table1Id], [Limit1].[OtherData] AS [OtherData] FROM ( SELECT TOP (2) [Extent1].[Table1Id] AS [Table1Id], [Extent1].[OtherData] As [OtherData] FROM [dbo].[Table1] AS [Extent1] INNER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2Id] = [Extent2].[Table2Id] LEFT OUTER JOIN [dbo].[Table3] AS [Extent3] ON [Extent1].[Table3Id] = [Extent3].[Table3Id] LEFT OUTER JOIN [dbo].[Table4] AS [Extent4] ON [Extent1].[Table4Id] = [Extent4].[Table4Id] LEFT OUTER JOIN [dbo].[Table5] AS [Extent5] ON [Extent1].[Table5Id] = [Extent5].[Table5Id] WHERE [Extent1].[Table1Id] = @p__linq__0 ) AS [Limit1]
I have Table1 with the following relationships (they are not enforced they only create the relationship for the navigation properties)
Table1 (*)->(1) Table2 Table1 (*)->(1) Table3 Table1 (*)->(1) Table4 Table1 (*)->(1) Table5
Using eager loading code looks like
IQueryable<Table1> query = context.Table1s;
query = query.Include(Table1 => Table1.Table2);
query = query.Include(Table1 => Table1.Table3);
query = query.Include(Table1 => Table1.Table4);
query = query.Include(Table1 => Table1.Table5);
query = query.Where(row => row.Table1Id == table1Id);
query.Single();
Every way I try to organize the Include() statements, the first table included has an Inner Join in its generated TSQL and the remaining are Left Outer Join (I expect Left Outer for all of them). I am not Entity Splitting, they are just plain tables with FKs.
If DefaultIfEmpty() is the only solution, can someone explain the reason why when all but the first table included provide the SQL expected?
My understanding is that default behavior for a Navigation Property is LEFT OUTER but I cannot get ALL properties to generate the default.
Any help would be MUCH appreciated.
Thank you in advance!
----- Created TSQL (modified for brevity but structure the same) -------
(@p__linq__0 int)SELECT [Limit1].[Table1Id] AS [Table1Id], [Limit1].[OtherData] AS [OtherData] FROM ( SELECT TOP (2) [Extent1].[Table1Id] AS [Table1Id], [Extent1].[OtherData] As [OtherData] FROM [dbo].[Table1] AS [Extent1] INNER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2Id] = [Extent2].[Table2Id] LEFT OUTER JOIN [dbo].[Table3] AS [Extent3] ON [Extent1].[Table3Id] = [Extent3].[Table3Id] LEFT OUTER JOIN [dbo].[Table4] AS [Extent4] ON [Extent1].[Table4Id] = [Extent4].[Table4Id] LEFT OUTER JOIN [dbo].[Table5] AS [Extent5] ON [Extent1].[Table5Id] = [Extent5].[Table5Id] WHERE [Extent1].[Table1Id] = @p__linq__0 ) AS [Limit1]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
EF 似乎使用
INNER JOIN
来包含必需,使用LEFT OUTER JOIN
包含可选导航属性。示例:如果我将
Customer
定义为Order
上的 required 属性......并发出此查询...
...I得到这个 SQL:
如果我将模型配置
.HasRequired(o => o.Customer)
更改为......我得到完全相同的查询,除了
INNER JOIN [ dbo].[Customers] AS [Extent2]
替换为:From模型观点这是有道理的,因为您说如果您将关系定义为必需,那么没有
客户
就永远不会有订单
。如果您通过删除数据库中的强制措施来规避此要求,并且如果您实际上有没有客户的订单,那么您就违反了您自己的模型定义。如果您遇到这种情况,唯一的解决方案可能是使这种关系成为可选。我认为无法控制使用
Include
时创建的 SQL。EF seems to use
INNER JOIN
for including a required andLEFT OUTER JOIN
for including an optional navigation property. Example:If I define
Customer
as a required property onOrder
......and issue this query...
...I get this SQL:
If I change in the model configuration
.HasRequired(o => o.Customer)
to...... I get exactly the same query except that
INNER JOIN [dbo].[Customers] AS [Extent2]
is replaced by:From model viewpoint it makes sense because you are saying that there can never be an
Order
without aCustomer
if you define the relationship as required. If you circumvent this requirement by removing the enforcement in the database and if you actually have then orders without a customer you violate your own model definition.Only solution is likely to make the relationship optional if you have that situation. I don't think it is possible to control the SQL that is created when you use
Include
.在 EF 中执行
IQueryable.Include()
时,如果没有导航属性基于强制关系,则 EF 将使用第一个表。它期望在架构中至少强制执行一种关系,并且应首先使用IQueryable.Include()
编码关系,然后使用Include()
添加其他表代码>in EF when doing
IQueryable.Include()
if none of the navigation properties are based on an enforced relationship then EF will use the first table. It expects that at least one of the relationships is enforced in the schema and that one should be coded with theIQueryable.Include()
first, then add the other tables withInclude()
如果您有一个表结构,如何强制实体框架进行内联接:
当您想要查找已通过特定测试的学生,您在逻辑上会执行类似以下操作:
重点是您从 StudentEntity 开始,并根据链下的连接添加一些条件。但由于要安排的学生是可选的,因此 EF 会生成 LEFT OUTER Join。
相反,你应该从链条的下游开始并逐步建立。例如:
当您尝试查询具有测试标准的学生时,从班级开始是很奇怪的。但它实际上使 LINQ 变得更简单。
因为学生不必有时间表,但是...班级必须有测试,班级必须有 ScheduleID,时间表必须有 StudentID,所以您可以一直获得内部联接。
诚然,这个学校的例子很抽象,但这个想法适用于我处理过相同类型关系的其他例子。
How to force Entity Framework to do Inner Joins if you have a table structure such that:
When you want to look up Students who have passed particular Tests, you would logically do something like:
The point being that you start with a StudentEntity and put in some conditions based on the joins down the chain. But because a Student to Schedule is optional, E.F. generates LEFT OUTER Joins.
Instead, you should start lower down the chain and build up. For example:
It is weird to start with a Class when you are trying to query for Students with Test Criteria. But it actually makes the LINQ simpler.
Because of the Student does not have to have a Schedule, but... a Class has to have Test(s), and a Class must have a ScheduleID, and Schedules must have a StudentID, you get Inner Joins all the way around.
Granted, this school example is abstract, but the idea holds true to other examples I have worked with the same types of relationships.