4

我有一张用 Fluent NHibernate 映射的表。此表必须通过 ID 连接到另一个表,但还必须根据一组常量值过滤该表上的连接值。考虑以下 SQL:

SELECT * 
FROM 
    Table1 
INNER JOIN 
    Table2 ON 
    Table1.Table2Id = Table2.Id 
    AND Table2.Category = 'A constant expression' 
    AND Table2.Language = 'A constant expression'

我对 Table1 的流畅映射目前如下所示:

References(a => a.Table2).Nullable().Columns("Table2Id").ReadOnly();

如何实现常量表达式?

4

3 回答 3

2

听起来您可以使用过滤器来执行此操作。

首先,您需要定义过滤器类型

public class SpecificCategoryFilter : FilterDefinition
{
    public SpecificCategoryFilter()
    {
        WithName("SpecificCategory").WithCondition("Category = 'A constant expression'");
    }
}

public class SpecificLanguageFilter : FilterDefinition
{
    public SpecificLanguageFilter()
    {
        WithName("SpecificLanguage").WithCondition("Language = 'A constant expression'");
    }
}

已编辑:根据评论,没有.ApplyFilter<TFilter>()on References(),所以更新了我认为使用过滤器的方法

过滤器需要在流畅的映射中应用

public class Table2Map : ClassMap<Table2>
{
    public Table2Map()
    {
        // Other mappings here...

        ApplyFilter<SpecificCategoryFilter>();
        ApplyFilter<SpecificLanguageFilter>();
    }
}

最后,当您打开会话时,您需要启用过滤器

using (var session = sessionFactory.OpenSession())
{
    session.EnableFilter("SpecificCategory");
    session.EnableFilter("SpecificLanguage");
}

如果您正在使用 的实现ICurrentSessionContext并且过滤器应该始终应用,那么您可以在从调用返回的会话中启用过滤器ICurrentSessionContext.CurrentSession()

现在,在查询 时Table1,为了激活过滤器Table2,您需要指示 NHibernate 加入到引用的Table2; 你可以使用

  1. Fetch(t => t.Table2).Eager
  2. JoinQueryOver(t => t.Table2)(以及类似的加入策略)

在没有指示 NHibernate 进行连接的情况下,默认情况下会延迟加载引用,因此不会在查询中应用过滤器。缺点是Table2会急切地获取,但我不知道以其他方式应用过滤器的方法。以下查询

session.QueryOver<Table1>().Inner.JoinQueryOver(t => t.Table2).List();

结果类似于 SQL

SELECT
    this_.Id as Id0_1_,
    this_.Table2Id as Table3_0_1_,
    table2_.Id as Id1_0_,
    table2_.Category as Category1_0_,
    table2_.Language as Language1_0_ 
FROM
    Table1 this_ 
inner join
    Table2 table2_ 
        on this_.Table2Id=table2_.Id 
WHERE
    table2_.Category = 'A constant expression' 
    and table2_.Language = 'A constant expression'

这类似于您在问题中遇到的 SQL。

于 2013-09-05T09:39:43.097 回答
1

我注意到您的映射指定 Nullable 并且没有急切获取(默认情况下它将被延迟加载)。因此,如果您确实想生成您在评论中显示的 sql,您将无法使用简单的session.Get<Table1>(). 即使您将映射更改为如下所示:

References(a => a.Table2).Nullable().Columns("Table2Id").ReadOnly().Fetch.Join;

您很可能最终会在输出的 sql 中使用左外连接。您能够通过内部连接强制获取(无需下载任何额外的 NHibernate 插件)的唯一方法是使用 a session.QueryOver(您也可以使用 session.Query 和 NHibernate linq 扩展来执行此操作)。如果是这种情况,那么您也可以在 QueryOver 查询中指定一组常量。

public class GetTableQuery
{
    private readonly string _category;
    private readonly string _language;

    public GetTableQuery(string category, string language)
    {
        _category = category;
        _language = language;
    }

    public IEnumerable<Table1> Execute(ISession session)
    {
        var returnList = session.QueryOver<Table1>()
            .Inner.JoinQueryOver(t1 => t1.Table2)
            .Where(t2 => t2.Category == _category && t2.Language == _language)
            .List();

        return returnList;
    }
}

我认为 Russ 展示的 ApplyFilter 方法确实使模型检索变得更加简单,并且它对代码的可重用性非常有用(如果您有其他具有类别和语言的表),但是由于您的表引用是可为空的引用,因此您必须无论如何都要使用查询。也许 QueryOver 与过滤器的组合是最好的(假设您可以获得更高版本的 fluent NHibernate)

于 2013-09-06T09:44:16.557 回答
1

您可能想看看在Formula(string formula)哪里可以提供纯 SQL。如果在映射级别过滤数据是一个好主意,恕我直言,这是另一个问题......作为一个例子,看看这里

于 2013-09-03T16:12:26.217 回答