NHibernate QueryOver加入不相关的实体

时间:2011-06-16 20:32:03

标签: nhibernate queryover

我有以下查询可以获得我想要的结果:

int associatedId = 123;

MyObject alias = null;

var subQuery = QueryOver.Of<DatabaseView>()
    .Where(view => view.AssociatedId == associatedId)
    .And(view => view.ObjectId == alias.ObjectId)
    .Select(view => view.ObjectId);

var results = session.QueryOver<MyObject>(() => alias)
    .WithSubquery.WhereExists(subQuery)
    .List();

DatabaseView已被映射为实际的NHibernate实体(因此我可以将其与QueryOver一起使用),但它与HBM映射中的MyObject无关。

此查询使用SELECT ... FROM MyObject WHERE EXISTS(此处为DatabaseView的子查询)返回IList。如何重新编写此信息以返回相同的信息,而不是使用JOIN?

4 个答案:

答案 0 :(得分:7)

您可以在NHibernate 3 +

中使用Linq加入不相关的实体

有趣的是,您使用join查询表达式元素:

from type1 in Repository.Query<MyType1>() 
join type2 in Repository.Query<MyType2>() 
on type1.Id equals type2.Id

注意:Repository.Query只是从会话中返回一个IQueryable Query

我希望QueryOver有一个解决方案,因为我并不总是希望在我的域中建模双向关系,但它们仍然可用于查询。

此外,您可以使用Criteria API映射Access =“noop”双向关系,而无需放入POCO类:

http://ayende.com/blog/4054/nhibernate-query-only-properties

答案 1 :(得分:3)

在NHibernate 5.1中,可以通过Entity Join查询QueryOver:

int associatedId = 123;

MyObject alias = null;
DatabaseView viewAlias = null;

var results = session.QueryOver<MyObject>(() => alias)
    .JoinEntityAlias(() => viewAlias, () => viewAlias.ObjectId == alias.ObjectId && viewAlias.AssociatedId == associatedId)
    .List();

答案 2 :(得分:2)

我意识到这个问题已经有5年了,“正确”的回答肯定是你无法用QueryOver做到这一点,正如其他答案所示。但是,如果 真的 需要此功能(就像我一样),我找到了一个不错的解决方法。

解决方案是在映射XML中使用带有本机SQL的“加载器查询”来生成相关集合(请参阅http://nhibernate.info/doc/nhibernate-reference/querysql.html#querysql-load)。在OP的具体示例中,您将继续按照建议将DatabaseView映射为实体,然后在映射中编写以下内容:

<class name="MyObject"...>
    ...
    <set name="MyViews" inverse="true">
        <key column="ObjectId" foreign-key="none"/>
        <one-to-many class="MyObject"/>
        <loader query-ref="myObjectViewsLoadQuery"/>
    </set>
</class>

然后我们只需要在原始SQL中定义我们的命名myObjectViewsLoadQuery来向NH解释如何加入这两个:

<sql-query name="myObjectViewsLoadQuery">
    <load-collection alias="view" role="MyObject.MyViews"/>
    SELECT view.*
    FROM DatabaseView view
    WHERE view.ObjectId = :id
</sql-query>

我们现在可以假装在我们的查询中有一个名为MyViews的“真实”集合,其中MyObjectDatabaseView相关联:

MyObject alias = null;
DatabaseView view = null;
var results = session.QueryOver<MyObject>(() => alias)
     .JoinAlias( () => alias.MyViews, () => view )
     //.Where( () => view.Property == "myValue" ) // optionally, restrict the view etc.
     .List();

当然,如果你只关心一个“优雅”的查询,这将是一个很大的麻烦。但是,如果您使用QueryOver的原因是您希望能够接受任意输入表达式以过滤您的DatabaseView或各种类似的活动,那么这非常有效。

答案 3 :(得分:-1)

使用QueryOver,Criteria或Linq无法做到这一点。唯一可以做到这一点的方法是通过HQL。

http://www.codewrecks.com/blog/index.php/2009/09/04/theta-join-in-hql-join-with-unrelated-entities/