首页 文章

流畅的NHibernate引用常量

提问于
浏览
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();

如何实现常量表达式?

3 回答

  • 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的更高版本)

  • 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'");
        }
    }
    

    EDITED: As per comments, there is no .ApplyFilter<TFilter>() on References(), so have updated with what I believe is the way to do it with filters

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

    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 ;你可以这样做

    • Fetch(t => t.Table2).Eager

    • 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 .

  • 1

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

相关问题