NHibernate QueryOver 子查询 [英] NHibernate QueryOver Subquery

查看:18
本文介绍了NHibernate QueryOver 子查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过类似的问题,但找不到简单的解释.我可能会错过它,但我保证我看过.实际上,我什至找不到其他文档,只有一篇博文迅速掩盖了所有内容,并假设您熟悉其他形式的 NH.

I've looked at the similar questions, but can't find a simple explanation. I could have missed it, but I promise I looked. Actually I can't even find the documentation other than a single blog post that glosses over everything rapidly and assumes you're familiar with other forms of NH.

鉴于 ProgramTopic 之间的多对多,其中后者位于 Topics 的层次结构中,我想检索给定Topic 的所有Programs,可能包括它的子主题.由于一个程序可能会列在给定父主题的多个子主题下,我需要使用子查询或处理必须使用不同的(并且 TransformUsing(Transformers.DistinctRootEntity) 的简单方法没有不行).

Given a many-to-many between Program and Topic, where the latter is in a hierarchy of Topics, I want to retrieve all the Programs for a given Topic, possibly including its subtopics. Since a program may be listed under multiple sub-topics of a given parent topic, I need to use a subquery or deal with having to use distinct (and the simple approach of TransformUsing(Transformers.DistinctRootEntity) didn't work).

原始 SQL 应该类似于

Raw SQL should be something like

SELECT ProgramId, Title, bar, baz, foo FROM Programs 
WHERE ProgramId IN 
 (SELECT ProgramId from Program_Topics WHERE TopicId IN (1, 2, ...))

将结果转换为模型类型以传输到视图.我最初的尝试是这样的:

The results are cast into a model type for transfer to the view. My initial attempt was this:

ProgramDTO pDTO = null;

/* topicIds is List<int> passed into function */

var query = Session.QueryOver<Program>()
.JoinQueryOver<Topic>(p => p.Topics)
.WhereRestrictionOn(pt => pt.Id).IsInG<int>(topicIds)     
.TransformUsing(Transformers.DistinctRootEntity)
.SelectList(list => list
        .Select(program => program.Id).WithAlias(() => pDTO.Id)
        .Select(program => program.Title).WithAlias(() => pDTO.Title)
        .Select(program => program.Location).WithAlias(() => pDTO.Location)
        .Select(program => program.Description).WithAlias(() => pDTO.Description)
)
.TransformUsing(Transformers.AliasToBean(typeof(ProgramDTO)));

return query.List<ProgramDTO>();    

显然,这运行的是连接而不是子查询,但我找不到这样的多对多子查询的示例.

Obviously this runs a join instead of a subquery, but I can't find an example of doing a subquery with a many-to-many like this.

public class Program : Entity {
    public virtual ISet<Topic> Topics { get; protected internal set; }
     ...
}

public class Topic : Entity {
    public virtual ISet<Program> Programs { get; protected internal set; }
    public virtual Topic ParentTopic { get; protected internal set; }
    ...
}

推荐答案

好吧,对这个问题进行了更多讨论,虽然我不喜欢结果的一部分,但它确实有效:

Well, hashed at this some more, and while I don't like one part of the results, it does work:

var distinctProgIdsSubQuery = QueryOver.Of<Program>().
JoinQueryOver<Topic>(p => p.Topics).
WhereRestrictionOn(pt => pt.Id).IsIn(topicIds)
.Select(Projections.Distinct(Projections.Property<Program>(p => p.Id)));


ProgramDTO pDTO = null;
var progQuery = Session.QueryOver<Program>()
    .WithSubquery.WhereProperty(p => p.Id).In(distinctProgIdsSubQuery)
    .SelectList(list => list
        .Select(program => program.Id).WithAlias(() => pDTO.Id)
        .Select(...)
        )
    .TransformUsing(Transformers.AliasToBean(typeof(ProgramDTO)));


return progQuery.List<ProgramDTO>();

这会产生

SELECT this_.ProgramId as y0_, ...
FROM Programs this_ 
WHERE this_.ProgramId in (
        SELECT distinct this_0_.ProgramId as y0_ 
        FROM
            Programs this_0_ 
        inner join
            Programs_Topics topics3_ 
                on this_0_.ProgramId=topics3_.ProgramId 
        inner join
            Topics topic1_ 
                on topics3_.TopicId=topic1_.TopicId 
        WHERE
            topic1_.TopicId in (
                @p1, @p2, ...
            )
    ) 

这可能是 NH 的限制,但是没有需要在子查询中加入 Programs 表.我试图从另一个方向写这个——也就是说,创建一个 QueryOver.Of(),但我无法弄清楚如何在最后选择程序 ID——select 只给我 TopicIds,即使这样查询仍然连接所有三个表.

This may be a limitation of NH, but there's no need to join the Programs table in the subquery. I tried to write this from the other direction -- that is, to create a QueryOver.Of<Topic>(), but I could not figure out how to select the program IDs at the end -- select was only giving me the TopicIds, and even then the query was still joining all three tables.

我不确定 MS-SQL 的查询优化器是否会避免无用的连接,但如果我们不必依赖它就好了.

I'm not sure if MS-SQL's query optimizer will avoid the useless join or not, but it would be nice if we didn't have to rely on it.

不过,就目前而言,这是有效的,希望其他人比我试图解决这个问题时更少头疼.

For now though, this works, and hopefully someone else has fewer headaches than I did trying to figure this out.

这篇关于NHibernate QueryOver 子查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆