12

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

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),但它MyObject与 HBM 映射无关。

此查询返回一个IList<MyObject>using a SELECT ... FROM MyObject WHERE EXISTS (subquery for DatabaseView here)。如何重新编写它以返回相同的数据但使用 JOIN 而不是子查询?

4

3 回答 3

8

在 NHibernate 5.1+ 中,QueryOver/Criteria 可以通过Entity Join进行:

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();

标准示例:

int associatedId = 123;
var results = session.CreateCriteria<MyObject>("alias")
    .CreateEntityAlias(
            "viewAlias",
            Restrictions.EqProperty("viewAlias.ObjectId", "alias.ObjectId")
            && Restrictions.Eq("viewAlias.AssociationId", associatedId),
            JoinType.InnerJoin,
            typeof(DatabaseView).FullName)
    .List();
于 2018-04-19T05:39:03.233 回答
6

您可以在 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 查询

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

此外,您可以使用 Criteria API 映射 Access="noop" 2 路关系,而无需放入您的 POCO 类:

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

于 2011-07-25T22:13:38.333 回答
3

我意识到这个问题已经有 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>

然后我们只需要myObjectViewsLoadQuery在原始 SQL 中定义我们的 named 来向 NH 解释如何连接这两者:

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

我们现在可以假装在我们的查询中有一个名为MyViewsrelated MyObjectto的“真实”集合:DatabaseView

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 或各种类似的活动,那么这非常有效。

于 2016-08-31T19:07:25.620 回答