NHibernate使用QueryOver和Future连接两个集合

时间:2017-06-30 12:26:38

标签: c# sql sql-server nhibernate

我有Project实体和ProjectRole以及ProjectUser实体:

public class Project {
    ...
    public virtual IList<ProjectRole> Roles { get; set; }
    public virtual IList<ProjectUser> ProjectUsers { get; set; }
}

public class ProjectRole {
    public int ProjectID { get; set; }
    public int RoleID { get; set; }
}

public class ProjectUser {
    public int ProjectID { get; set; }
    public int UserID { get; set; }
}

可以通过他的RoleID或特别是他的UserID将用户分配给Project。

我想让所有项目满足以下两个要求: 用户位于分配给项目的角色(角色集合)或用户直接分配给项目(ProjectUsers)

我发现我不能做两个左连接,因为&#34;无法取出多个包&#34;:

ProjectRole prAlias = null;
ProjectUser puAlias = null;
var projects = s.QueryOver<Project>()
    .Left.JoinAlias(p => p.Roles, () => prAlias)
    .Left.JoinAlias(p => p.ProjectUsers, () => puAlias)
    .Where(p => p.DeletedDate == null)
    .And(() => puAlias.UserID == loggedUserID)
        Restrictions.Or(
            Restrictions.On(() => prAlias.RoleID).IsIn(userRoles),
            Restrictions.Where(() => puAlias.UserID == loggedUserID)
        );

我尝试使用两个单独的查询和未来:

var projectsForUserRoles = s.QueryOver<Project>()
    .Left.JoinAlias(p => p.Roles, () => prAlias)
    .Where(p => p.DeletedDate == null)
    .And(() => prAlias.RoleID).IsIn(userRoles))
    .Future();


var projectsForUser = s.QueryOver<Project>()
    .Left.JoinAlias(p => p.ProjectUsers, () => puAlias)
    .Where(p => p.DeletedDate == null)
    .And(() => puAlias.UserID == loggedUserID)
    .Future();

var projects = projectsForUserRoles.ToList();

但是通过这种方式我只能从 projectsForUserRoles 查询中获得结果,而不是 projectsForUser 。两个查询分别工作正常 - 第一个返回3个记录,第二个返回2个记录。我想得到的是具有明显结果的那些(5条记录)的总和:

SELECT DISTINCT p.ProjectID, p.ProjectName FROM
Projects p
LEFT JOIN ProjectRoles pr ON pr.ProjectID = p.ProjectID
LEFT JOIN ProjectUsers pu ON pu.ProjectID = p.ProjectID
WHERE p.DeletedDate IS NULL
AND(
    pr.RoleID IN (SELECT ur.RoleID FROM UserRoles ur WHERE ur.UserID = 1) 
    OR pu.UserID = 1
)

我错过了什么?我应该如何在同一个实体Project上链接两个查询?

1 个答案:

答案 0 :(得分:1)

你有没有尝试完成内存中的工作?对于你的情况,它看起来很合理。

using System.Linq;

// ...

var projects = projectsForUserRoles.Union(projectsForUser).ToList();

这就是Najera in his comment的建议,但是对于这种情况,无需关心覆盖GetHascodeEquals:第一级缓存将确保您获得相同的引用实体。

现在看起来很奇怪&#34;不止一个包&#34;当你只是过滤它们时,限制就开始了。但是消息告诉你正在抓取。我不太了解,因此无法帮助您更改它仅用于过滤,而不是提取。

使用我会写:

using System.Linq;
using NHibernate.Linq;

// ...

var projects = s.Query<Project>()
    .Where(p => p.DeletedDate == null)
    .Where(
        p => p.ProjectUsers.Any(pu => pu.UserID == loggedUserID) ||
            p.Roles.Any(pr => userRoles.Contains(pr.RoleID)))
    .ToList();