我有一个使用NH 3.1的项目,到目前为止一直使用QueryOver语法。
这个项目的一个方面存在于一个组织范围的数据库中,我只读访问并使用完全不同的DBMS(Oracle vs MSSQL)。所以我使用标准的多对多表将我的对象(Foos)的引用存储到它们的对象(Bars)
FooBars
FooID int not null PK
BarID int not null PK
而我的域对象,而不是Iset<Bar>
而是有一个ISet<int> BarIDs
,它被手动映射到FooBars
表。这可以防止NH尝试做不可能的事情并一直加入Bars表(我可以使用BarRepository.Get()稍后检索Bars的细节,如果我需要它们,在这种情况下,我会不,因为我只需要ID来过滤返回的对象列表。
鉴于IList<int> SelectedBars
如何撰写QueryOver<Foo>
,其中BarIDs
包含SelectedBars
中的任何元素?
SQL就像
...FROM foos INNER JOIN foobars on foo.fooID = foobars.fooID WHERE barID IN ( ... )
答案 0 :(得分:2)
QueryOver无法实现。两年前,我有一个similar question about filtering value collections。 (注意:QueryOver基于Criteria API)。
我不是百分百肯定,但它可能适用于HQL。它更强大。
您可以在QueryOver条件中包含SQL语句。
我真的不明白为什么你不将它映射为实体列表。有延迟加载以避免不必要的加载 - 虽然有时会有一些折衷。您无需访问数据库即可访问NH代理的ID。映射ID通常会让生活更加艰难。
答案 1 :(得分:1)
尝试:
session.QueryOver<Foo>()
.JoinQueryOver(x => x.FooBars)
.WhereRestrictionOn(x => x.BarId).IsIn( ... )
答案 2 :(得分:0)
3年后,我回来报告我是如何解决这个问题的。
public class Foo :Entity {
public virtual ISet<FooBar> BarIDs { get; protected internal set; }
} ...
public class FooBar :Entity {
protected internal FooBar() { }
protected internal FooBar(Foo f, int BarID) { ... }
public virtual Foo Foo { get; protected internal set; }
public virtual int BarID { get; protected internal set; }
}
这基本上是斯特凡所建议的,以及相关帖子中暗示的内容。您只需要花费额外实体并引用它的开销。请记住,我存储BarID而不是完整的Bar对象,因为我处理两个数据库之间的硬边界:条形图存储在与Foos不同的平台上的完全不同的数据库中。当然,除了告诉Foo有一个ISet<Bar>
之外你还好得多。
通过SelectedBarIDs查找Foos非常简单,就像Thilak建议的那样:
session.QueryOver<Foo>().JoinQueryOver<FooBar>(f => f.BarIDs).
WhereRestrictionOn(b => b.BarID).IsIn(...)...
这是一个有趣的问题,跨越这样的数据库边界。我不能说我喜欢这样做,但是如果其他人打算花时间维护一个酒吧列表并让它供我使用,那对我来说将是一个巨大的资源浪费相同。因此,使用包装器类的效率很低,这是非常容易证明的成本。