我有一个映射在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();
如何实现常量表达式?
答案 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
;你可以用
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 :(得分: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的更高版本)