【问题标题】:Subqueries for querying associations in GORMGORM中查询关联的子查询
【发布时间】:2015-04-30 03:56:44
【问题描述】:

我在 GORM 中有以下域。

class Topic {
static hasMany = [resources: Resource, subscriptions: Subscription]
}

class Resource {
static belongsTo = [resourceOf: Topic]
}

class Subscription {
 static belongsTo = [subscriptionOf: Topic]
}

我一直找不到使用条件/命名子查询运行子查询的语法。例如,如何使用条件在 GORM 中编写以下查询。

select topic.id, 
(select count(*) from Resource where resourceOf.id = topic.id) as numRes,
(select count(*) from Subscription where subscriptionOf.id = topic.id) as numSubs
from topic
where topic.id in (<My topic ids>)
group by topic.id;

这是非常基本的事情,但我找不到相同的文档。

有谁知道如何在 GORM 中使用 namedQueries 来做到这一点?

我的 grails 版本是 2.4.4

【问题讨论】:

    标签: hibernate grails subquery grails-orm


    【解决方案1】:

    您面临的问题是 namedQueries 不应该与投影(摘要)一起使用。退后一步,重新设定您对使用 namedQueries 时可以和应该做什么的期望。

    命名查询是创建标识更大集合子集的查询的便捷方式。将其视为逐步过滤数据。如果您查看文档中的示例,您将看到这一点得到了证明。这使得namedQueries 非常强大,但在特定的用例中。

    来自documentation 的示例:

    // get all old publications with more than 350 pages
    // and the word 'Grails' in the title
    def pubs = Publication.oldPublicationsLargerThan(350).findAllByTitleLike('%Grails%')
    

    另一个例子可能是:

    def divisions = Division.locatedIn('Sweden').havingNoOustandingBalance().havingMoreThanXEmployees(50).currentlyOpen().notOnFire()
    

    在其他用例中,例如使用摘要和预测,它们就不够用了。不是因为它们设计不佳或无能,而是因为它们的设计初衷并非如此。

    确实应该通过createCriteriaHQL 本身创建预测和摘要。

    虽然您可能能够破解 namedQueries 来进行预测和总结,但您可能会与框架作斗争。为正确的工作使用正确的工具,并完成更多工作。

    更新 然而,所有这一切,blog post 解释了如何将投影与命名查询(和标准)一起使用。它应该能让您更好地了解预测在 GORM 中的工作原理。

    【讨论】:

    • 感谢您的解释。它清除了一些东西,但不仅仅是关于命名查询。早些时候我写过criterias/named subqueries。我忘了在最后一句话中重复同样的内容。你能分享如何使用标准吗?
    【解决方案2】:

    您的查询是“给我与给定主题列表匹配的主题以及它们各自的资源和订阅数量。”

    (已编辑以反映 cmets) 我认为这可能对你有用:

    def myTopicIds = ['1', '2']  // search for ids 1 and 2
    def criteria = Topic.createCriteria()
    def results = criteria.list() {
        'in'('id', myTopicIds)  // restrict results to only those matching your given ids
        projections {
            property("id")
            resources {
                countDistinct('id')   
            }
            subscriptions {
                countDistinct('id')   
            }
           groupProperty('id')
        }
    }.collect {
            [
                topicId: it[0],
                numRes: it[1],
                numSubs: it[2]
            ]
        }
    

    collect 更改了结果集合,并允许您将结果作为映射来引用,其中每个项目都有 3 个具有显示名称的键,否则您只能引用无名数组项目。

    【讨论】:

    • 这几乎可以工作了。如果我只查询资源,那么它可以工作,如果我只查询订阅,那么它也可以工作。但在一起我只计算资源。也许是因为他们更多。被触发的查询由内部连接而不是子查询组成,因此分组可能存在问题。
    • 抱歉,请问“仅查询资源”和“仅查询订阅”是什么意思?
    • 我的意思是在标准中只保留resources { count('id', 'numRes') } 或其他。
    • 嗯,我认为count 调用的第二个参数可能是错误的。如果删除 , 'numRes', 'numSubs'groupProperty('id') collect{} 语句会怎样?
    • count 替换为countDistinct 并从count 行中删除第二个参数,然后上面的代码就可以正常工作了。
    【解决方案3】:

    你为什么不尝试这样的事情......

    def exampleSubQuery = new grails.gorm.DetachedCriteria(Resource).build {
       // your criteria here, "normal" GORM
       // and the same for Subscription 
    }
    

    ...然后将此子查询附加到您的主查询中。

    看看这个,可能对你有帮助:Can't get "count" and "groupBy" with Grails DetachedCriteria

    【讨论】:

    • DetachedCriteria 的问题似乎是我无法指定任何参数。但是为了让我能够使用where 进行子查询,我需要参数。链接的答案也面临同样的问题。我尝试使用 DetachedCriteria 进行子查询,但由于无法使用 count(_detachedCriteriaWithParameter_) 之类的内容,因此无法获得计数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 2013-07-14
    • 2020-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多