使用 QueryOver,如何根据方法参数有条件地过滤结果?

Using QueryOver, how do I conditionally filter results based on a method argument?

对于我正在进行的项目,我最近一直在使用 NHibernate 中的 QueryOver 语法,但遇到了一个障碍,我没有找到任何关于如何解决的文本.

在我正在处理的项目中,我有一个存储库方法来将一组人分配给一个项目。存储库方法如下所示(当前 非功能性 代码)

public static IEnumerable<ProjectAssignment> GetProjectAssignments(int projectId, bool includeAlternates)
{
    using (ISession session = DataContext.GetSession())
    {
        List<ProjectAssignment> results = session
            .QueryOver<ProjectAssignment>()
            .Where(p => p.ProjectId == projectId)
                // Problem statement!
                .And(p => includeAlternates || !p.IsAlternate)
            .List().ToList();

        return results;
    }
}

我的 ProjectAssignment class 和它的映射一样不重要,因为根据我今天早些时候提出的问题,这个问题很明显:includeAlternates 布尔值没有映射到我的ProjectAssignment class,也不应该;它是函数的参数。

我想问的是:

Query all Project Assignments
    Where the project ID is the one I want
    And if alternate assignments are included, just include the assignment, 
        otherwise only include the assignment if it's not an alternate assignment
    And return that list from the query.

为了做到这一点,,NHibernate 的一个新概念。但是,在阅读了其他一些问题之后,我在两个关键点上非常非常非常 不清楚,并且试图找到官方文档也没有帮助,因为它是以一种方式编写的我发现完全不透明:

所以,对于我的问题:

NHibernate 将尝试解析为 SQL 您在条件中包含的内容,并且将无法解析,因为它不是您的映射的一部分,或者在该上下文中对解析器没有意义,这可能是您的错误正在经历。 投影对 NHibernate 来说根本不是一个新概念,但我看不出它们与您当前的情况有何关系。

您的代码应该更像下面的内容,其中您根据布尔值将条件包含到 QueryOver 中或不包含:

public static IEnumerable<ProjectAssignment> GetProjectAssignments(int projectId, bool includeAlternates)
{
    using (ISession session = DataContext.GetSession())
    {
        var query = session.QueryOver<ProjectAssignment>()
                       .Where(p => p.ProjectId == projectId);

        if (!includeAlternates) 
        {
            query.And(p => !p.IsAlternate);
        }

        List<ProjectAssignment> results = query.List().ToList();
        return results;
    }
}

What is a Projection, exactly? One source said, 'it's like a SELECT statement in SQL'. Another has likened it to a LINQ .Select() call, where it's actually just doing a transformation. These are two completely different things as far as I'm aware, so one of those sources has got to be wrong.

我认为在您的其他问题的上下文中,评论指的是 NHibernate NHibernate.Criterion.Projections class。此 class' 成员可与 QueryOver 或 Criteria 查询一起使用,最终从使用 NHibernate 映射的实体生成 SQL。

这是一个使用条件 API 和 Projections.Property 方法的示例:

session.CreateCriteria(typeof(Person))
    .SetProjection(
        Projections.Property("FirstName"))
    .List<string>();

由于 QueryOver 是建立在条件 API 之上的,当 QueryOver 不支持您尝试为某些人执行的操作时,您仍然可以 "drop into" Projections.* 方法原因。您的最后一个问题就是一个很好的例子;执行以下操作不适用于 QueryOver:

session.QueryOver<Person>()
    .Select(p => p.LastName + ", " + p.FirstName)
        .List<string>();

但是,这将:

session.QueryOver<Person>()
    .Select(Projections.SqlFunction(
        "concat",
        NHibernateUtil.String,
        Projections.Property<Person>(p => p.LastName),
        Projections.Constant(", "),
        Projections.Property<Person>(p => p.FirstName)))
    .List<string>();

使用投影往往更冗长但更强大。您还应该能够将表达式与各种 Projections 方法一起使用,从而消除对字符串的需要。

Fredy 的回答解决了真正的问题,所以我会从我的回答中省略那部分。