4

次の例では、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 の問題ですか?

4

1 に答える 1

5

私の推測では、クエリをすばやく見ると、Grails/GORMがを実行していると思いますinner join。内部結合は、テーブル間に関係が存在する場合にのみ一致します。上記の例では、関連する追加機能がないため、そのクエリは一致しませんchocchoc

つまり、or失敗しているのではなく、実際のクエリです。localhost:8080 / {yourapp} / dbConsoleを起動し、同じクエリを実行しますが、whereステートメントはありません。1つまたは複数の添加剤を含む製品しか入手できないことがわかります。

私は(テストされていませんが)次のLEFT JOINような構文を使用するように強制できると信じています:

import org.hibernate.criterion.CriteriaSpecification
...

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

これにより、左(または外側)の結合が強制され、一致する添加剤がない製品が可能になります。注:外部結合を使用すると重複する結果が得られる可能性がありますが、これは特定の使用シナリオによって異なります。

于 2012-05-10T08:44:51.830 に答える