NHibernate使用错误的连接生成SQL

时间:2012-02-17 12:04:53

标签: c# fluent-nhibernate nhibernate-mapping linq-to-nhibernate

我有一个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 View上进行“老派”连接。这会导致查询排除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回到另一个方向......

EDIT。似乎没有帮助

3 个答案:

答案 0 :(得分:3)

我认为您需要将Where条款更改为:

.Where(x => x.AssignedUser.Id == userId || 
       (x.CaseView != null && x.CaseView.MooseUserId == userId))

使用当前的Where子句,您告诉NHibernate始终会有CaseView,因为您无条件地访问其属性。根据此信息,NHibernate会优化您的查询,从left outer joininner join(“老派”加入)

答案 1 :(得分:0)

我已使用存储过程实现了此连接。希望NHibernate能尽快解决这个问题。

答案 2 :(得分:0)

尝试使用Fluent NHibernate。像下面这样的东西可以让你进入正确的球场:

var List<WorkflowAction> = FluentSessionManager.GetSession().CreateCriteria<WorkflowAction>()
        .SetFetchMode("CaseView", FetchMode.Eager)
        .SetFetchMode("WorkflowActionType", FetchMode.Eager)
        .SetFetchMode("WorkflowActionPriorityList", FetchMode.Eager)
        .CreateAlias("AssignedUser", "au")
        .CreateAlias("CaseView", "cv")
        .Add(Expression.Or(Expression.Eq("au.Id", userId),  Expression.Eq("cv.MooseUserId", userId)))
        .List<WorkflowAction>();

请记住,我有一个特殊的类,它扩展了FluentSessionManager.GetSession(),我可以使用一个简单的帮助器类或逐页调用它。您对FluentSessionManager的设置可能会有很大差异。但最终在“.CreateCriteria()......”你的代码和我的代码应该匹配。假设“WorkflowAction”是要调用查询的表。