流畅的NHibernate引用常量

时间:2013-09-03 08:36:38

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

我有一个映射在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();

如何实现常量表达式?

3 个答案:

答案 0 :(得分: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>()上没有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)(以及类似的加入策略)
  3. 在没有指示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。

答案 1 :(得分:1)

您可能需要查看可以提供纯SQL的Formula(string formula)。如果在映射级别上过滤数据是个好主意,那么另一个问题是恕我直言......例如看看here

答案 2 :(得分:1)

我注意到你的映射指定了Nullable并且没有急切的提取(默认情况下它将是延迟加载的)。因此,如果您确实想要生成评论中显示的sql,则无法使用简单的session.Get<Table1>()来执行此操作。即使你改变了映射,它就像这样:

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

您最有可能在输出的sql中使用左外连接。你可以使用内连接强制获取(没有下载任何额外的NHibernate插件)的唯一方法是使用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与过滤器的组合将是最好的(假设您可以获得更流畅的NHibernate的更高版本)