我的课程看起来像这样
public class Agreement
{
public virtual string ArrgKey { get; set; }
public virtual string SubjectCode { get; set; }
// mapped as a HasMany to AgreementStateCountyRelation
public virtual IList<AgreementStateCountyRelation> StateCounties { get; set; }
}
public class AgreementStateCountyRelation
{
public virtual string ArrgKey { get; set; }
public virtual State State { get; set; } // State has a StateAbbr property
public virtual County County { get; set; }
}
使用Fluent NHibernate,NHibernate映射非常简单。
我正在尝试编写一个查询,查找与州有关的所有协议。除了在where子句中使用之外,我根本不需要StateCounties集合的数据。使用HQL,此查询完全符合我的要求(返回TX的协议并且不会急于加载StateCounties):
var list = session.CreateQuery("select a from Agreement a
join a.StateCounties sc
join sc.State s
where s.StateAbbr = ?")
.SetParameter(0, "TX")
.List<Agreement>();
当我尝试使用条件API时出现问题(我不能在这种情况下使用HQL)。我认为这会产生与HQL相同的查询:
DetachedCriteria dc = DetachedCriteria.For<Agreement>("a");
dc.CreateAlias("a.StateCounties", "sc");
dc.CreateAlias("sc.State", "s");
dc.Add(Restrictions.Eq("s.StateAbbr", "TX"));
var list = dc.GetExecutableCriteria(session).List<Agreement>();
但State的所有属性也放在select子句中(我猜是因为State在where子句中)。此外,作为同一个呼叫的一部分,县是懒惰的(即使我从来不想要或不需要它们)。
如果我指定了投影列表并设置了ResultTransformer,那么我得到的结果与HQL类似(生成相同的SQL):
DetachedCriteria dc = DetachedCriteria.For<Agreement>("a");
dc.CreateAlias("a.StateCounties", "sc");
dc.CreateAlias("sc.State", "s");
dc.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("ArrgKey"), "ArrgKey")
.Add(Projections.Property("SubjectCode"), "SubjectCode"));
dc.SetResultTransformer(Transformers.AliasToBean<Agreement>());
dc.Add(Restrictions.Eq("s.StateAbbr", "TX"));
var agreements = dc.GetExecutableCriteria(session).List<Agreement>();
唯一的区别是StateCounties集合总是为null而不是代理,但这更好,因为我不想意外地延迟加载它们。
所以,我的问题:有没有办法告诉NHibernate在select子句(投影列表)中排除属性(StateCounties),而不是必须指定其中的所有其他属性清单?表示“此关联仅存在于where子句中使用”的内容。 ExcludeFromProjectionList或DoNotPopulate还是我可以在映射或条件中放入HasMany关系的东西?
修改:集合定义为懒惰。
作为一个精简的示例,这不会导致集合加载:
DetachedCriteria dc = DetachedCriteria.For<Agreement>("a");
var agreements = dc.GetExecutableCriteria(session).List<Agreement>();
但这样做:
DetachedCriteria dc = DetachedCriteria.For<Agreement>("a");
dc.CreateAlias("a.StateCounties", "sc");
dc.CreateAlias("sc.State", "s");
var agreements = dc.GetExecutableCriteria(session).List<Agreement>();
我刚发现这个似乎是同一个问题(没有一个好的解决方案):
https://forum.hibernate.org/viewtopic.php?t=959176
另一个有这个问题的人(不幸的是,他不能像我一样设置投影做得更好):
Making hibernate not include fields from joined tables in select clause