NHibernate 正在生成带有错误连接的 SQL
我有一个 NHibernate Linq 查询,它没有按照我的预期工作。
问题似乎来自于在 where 子句中使用左连接表中的可空 int 列。这导致连接就像内部连接一样。
var list = this.WorkflowDiaryManager.WorkflowActionRepository.All
.Fetch(x => x.CaseView)
.Fetch(x => x.WorkflowActionType)
.ThenFetchMany(x => x.WorkflowActionPriorityList)
.Where(x => x.AssignedUser.Id == userId || x.CaseView.MooseUserId == userId)
由此生成的 SQL 看起来像(从连接开始 - 您不需要查看所有选择)
from Kctc.WorkflowAction workflowac0_
left outer join Kctc.WorkflowCaseView workflowca1_ on workflowac0_.CaseId=workflowca1_.CaseId
left outer join Kctc.WorkflowActionType workflowac2_ on workflowac0_.WorkflowActionTypeId=workflowac2_.WorkflowActionTypeId
left outer join Kctc.WorkflowActionPriority workflowac3_ on workflowac2_.WorkflowActionTypeId=workflowac3_.WorkflowActionTypeId
,Kctc.WorkflowCaseView workflowca4_
where workflowac0_.CaseId=workflowca4_.CaseId
and (workflowac0_.AssignedUser=@p0 or workflowca4_.[MooseUserId]=@p1);
@p0 = 1087 [Type: Int32 (0)],
@p1 = 1087 [Type: Int32 (0)]
因此导致问题的部分是上面代码片段的第 5 行。正如您所看到的,NHibernate 正在尝试在我的 WorkflowCaseView 视图上执行“老式”连接。这会导致查询排除 WorkflowAction 表中没有 CaseId 的其他有效操作。
谁能解释为什么 NHibernate 编写这个 SQL,以及我如何鼓励它生成更好的查询?
谢谢!
WorkflowActionMap 中的重要位
Table("Kctc.WorkflowAction");
Id(x => x.Id).GeneratedBy.Identity().Column("WorkflowActionId");
References(x => x.WorkflowActionType).Column("WorkflowActionTypeId").Unique();
References(x => x.CompletedBy).Column("CompletedBy");
References(x => x.CaseView).Column("CaseId").Not.Update().Unique();
References(x => x.AssignedUser).Column("AssignedUser");
WorkflowCaseViewMap 中的重要位
Table("Kctc.WorkflowCaseView");
Id(x => x.Id).Column("CaseId");
Map(x => x.MooseUserId).Nullable();
看着这个,我想知道我是否应该有一个 HasMany 以其他方式返回...
编辑。似乎没有帮助
I have an NHibernate Linq query which isn't working how I would expect.
The problem seems to come from using a nullable int column from a left joined table in the where clause. This is causing the join to act like an inner join.
var list = this.WorkflowDiaryManager.WorkflowActionRepository.All
.Fetch(x => x.CaseView)
.Fetch(x => x.WorkflowActionType)
.ThenFetchMany(x => x.WorkflowActionPriorityList)
.Where(x => x.AssignedUser.Id == userId || x.CaseView.MooseUserId == userId)
The SQL produced by this looks like (from the join onwards - you don't need to see all the selects)
from Kctc.WorkflowAction workflowac0_
left outer join Kctc.WorkflowCaseView workflowca1_ on workflowac0_.CaseId=workflowca1_.CaseId
left outer join Kctc.WorkflowActionType workflowac2_ on workflowac0_.WorkflowActionTypeId=workflowac2_.WorkflowActionTypeId
left outer join Kctc.WorkflowActionPriority workflowac3_ on workflowac2_.WorkflowActionTypeId=workflowac3_.WorkflowActionTypeId
,Kctc.WorkflowCaseView workflowca4_
where workflowac0_.CaseId=workflowca4_.CaseId
and (workflowac0_.AssignedUser=@p0 or workflowca4_.[MooseUserId]=@p1);
@p0 = 1087 [Type: Int32 (0)],
@p1 = 1087 [Type: Int32 (0)]
So the part that is causing the problem is line 5 of the snippet above. As you can see, NHibernate is trying to do an 'old-school' join on my WorkflowCaseView View. This causes the query to exclude otherwise valid actions which do not have a CaseId in the WorkflowAction table.
Could anyone explain why NHibernate is writing this SQL, and how I might encourage it to produce a better query?
Thanks!
Important bits from WorkflowActionMap
Table("Kctc.WorkflowAction");
Id(x => x.Id).GeneratedBy.Identity().Column("WorkflowActionId");
References(x => x.WorkflowActionType).Column("WorkflowActionTypeId").Unique();
References(x => x.CompletedBy).Column("CompletedBy");
References(x => x.CaseView).Column("CaseId").Not.Update().Unique();
References(x => x.AssignedUser).Column("AssignedUser");
Important bits from WorkflowCaseViewMap
Table("Kctc.WorkflowCaseView");
Id(x => x.Id).Column("CaseId");
Map(x => x.MooseUserId).Nullable();
Looking at this, I wonder if I should have a HasMany going back the other way...
EDIT. Doesn't seem to help
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为您需要将
Where
子句更改为:使用当前的
Where
子句,您告诉 NHibernate 总会有一个CaseView
,因为您无条件访问其属性。根据此信息,NHibernate 将您的查询从左外连接
优化为内连接
(即“老式”连接)I think you need to change your
Where
clause to this:With your current
Where
clause you tell NHibernate that there always will be aCaseView
, because you unconditionally access its properties. Based on this information NHibernate optimizes your query from aleft outer join
to aninner join
(which the "old-school" join is)我已经使用存储过程实现了此连接。希望 NHibernate 能够尽快修复这个错误。
I have implemented this join using a stored procedure. Hopefully NHibernate will fix this bug soon.
尝试使用 Fluent NHibernate。类似下面的内容应该让您处于正确的位置:
请记住,我有一个扩展 FluentSessionManager.GetSession() 的特殊类,我可以在其中直接使用简单的帮助程序类或逐页调用它。您的 FluentSessionManager 设置可能有很大不同。但最终在“.CreateCriteria()...”你的代码和我的应该匹配。假设“WorkflowAction”是调用查询的表。
Try using Fluent NHibernate. Something like the following should get you in the right ball park:
Keep in mind, I have a special class that extends FluentSessionManager.GetSession() where I can call it directly with a simple helper class or on a page by page basis. Your setup of the FluentSessionManager may be considerably different. But ultimately at ".CreateCriteria()..." your code and mine should match. Assuming "WorkflowAction" is the table the query is being called against.