Grails GORM“或”不使用关联

Posted

技术标签:

【中文标题】Grails GORM“或”不使用关联【英文标题】:Grails GORM 'or' not working with associations 【发布时间】:2012-05-10 06:43:23 【问题描述】:

在以下示例中,我希望 Product.searchAll 匹配两者 添加剂和产品,但似乎忽略了eq('name', taste)

class Additive 
    String flavor
    static belongsTo = [product:Product]


class Product 
    String name
    static hasMany = [additives:Additive]

    static constraints = 
            name nullable:true
    

    static namedQueries = 
        searchAll  taste ->
            or 
                eq('name', taste)
                additives  eq('flavor', taste) 
            
        
        searchAdditives  taste ->
            additives  eq('flavor', taste) 
        
        searchProducts  taste ->
            eq('name', taste)
        
    


class SearchSpec extends grails.plugin.spock.IntegrationSpec 
    def choc, muff

    def 'searchAll should return products and additives that match - THIS FAILS'() 
        setup:
            createTestProducts()
        expect:
            Product.searchAll("chocolate").list() == [choc, muff]
    


    def 'searchProducts should return only products that match - THIS PASSES'() 
        setup:
            createTestProducts()
        expect:
            Product.searchProducts("chocolate").list() == [choc]
    

    def 'searchAdditives should return only additives that match - THIS PASSES'() 
        setup:
            createTestProducts()
        expect:
            Product.searchAdditives("chocolate").list() == [muff]
    

    private def createTestProducts() 
        // create chocolate
        choc = new Product(name:'chocolate').save(failOnError:true, flush:true)
        // create a chocoloate-flavored muffin
        muff = new Product(name:'muffin').addToAdditives(flavor:'chocolate').save(failOnError:true, flush:true)
    

生成的SQL如下:

select this_.id as id1_1_, this_.version as version1_1_,
this_.name as name1_1_, additives_1_.id as id0_0_,
additives_1_.version as version0_0_, additives_1_.flavor as
flavor0_0_, additives_1_.product_id as product4_0_0_ from product
this_ inner join additive additives_1_ on
this_.id=additives_1_.product_id where (this_.name=? or
(additives_1_.flavor=?))

我的语法有问题,还是 Grails、GORM 或 H2 有问题?

【问题讨论】:

【参考方案1】:

快速查看您的查询,我的猜测是 Grails / GORM 正在执行inner join。仅当表之间存在关系时,内连接才匹配。在上面的示例中,该查询从不匹配choc,因为choc 没有任何关联的添加剂。

所以,失败的不是or,而是实际的查询。启动 localhost:8080/yourapp/dbConsole 并运行相同的查询,但没有 where 语句。您应该看到您只获得了含有一种或多种添加剂的产品。

我相信(未经测试)您可以使用如下语法强制LEFT JOIN

import org.hibernate.criterion.CriteriaSpecification
...

    searchAll  taste ->
        createAlias("additives", "adds", CriteriaSpecification.LEFT_JOIN)
        or 
            eq('name', taste)
            eq('adds.flavor', taste)
        
    

这应该强制左(或外)连接,允许没有匹配添加剂的产品。注意:使用外连接时可能会得到重复的结果,但这取决于您的特定使用场景。

【讨论】:

感谢您的提示 - 将进行调查! 开箱即用 - 感谢您的帮助!您认为这是 Grails 2 中的错误吗?很确定这在 1.3.7 中适用于 HSQLDB。 如果我记得,这是 Grails 或 Hibernate 中的一个已知变化。它是出于性能原因而制作的。我不是 100% 同意,因为它会影响您可以拥有 0 个相关项目的任何关系。 :-\

以上是关于Grails GORM“或”不使用关联的主要内容,如果未能解决你的问题,请参考以下文章

Grails 查询不使用 GORM

Grails GORM 查询以匹配多个关联对象

Grails GORM MySQL 生成 TEXT 或 LONGTEXT 列

在 Grails/GORM 中定义默认排序顺序

Grails gorm 查询问题

独立使用 Grails GORM