grails / gorm:指定一个受“唯一”限制的财产。

时间:2014-09-03 03:49:32

标签: hibernate grails gorm

我正在使用grails 2.4.2,但怀疑这通常与ORM(休眠)有关。

我正在尝试在对象集合中重新分配序数属性。这种重新分配构成了对象的“重新洗牌”。

假设:

class Bar {
    int i
    static belongsTo = [foo:Foo]
    static constraints = { i unique: 'foo' }
}

class Foo {
    static hasMany = [bars:Bar]
    static mapping = { bars sort: 'i' }
}

import grails.test.spock.IntegrationSpec
import grails.validation.ValidationException

class FooServiceIntegrationSpec extends IntegrationSpec {
    public static final IntRange BAR_RANGE = 0..9
    Foo foo

    def setup() {
        foo = Foo.build()
        (BAR_RANGE).each {
            Bar bar = Bar.build(i: it, foo: foo)
            foo.addToBars(bar)
        }
        foo.save(flush:true).refresh()
    }

    void "reshuffling i-s doesn't work"() {
        when:
        List l = (BAR_RANGE).collect()
        use(Collections) {l.shuffle()}
        foo.bars.eachWithIndex{b,int index -> b.i=l[index]}
        foo.save()

        then:
        ValidationException ex = thrown()
        ex.message =~ 'must be unique'
    }
}

如何实现上述改组尝试(I.E.不会超越唯一约束)?

谢谢:)

2 个答案:

答案 0 :(得分:1)

由于ORM将逐个更新Bar个实例,因此如果您首先删除Bar的所有Foo实例,则只能实现此目的

foo.bars*.delete(flush: true)

然后执行其余的测试代码。

为什么?

Hibernate将为每个Bar实例创建一个Update语句,并且很可能在第一次更新时失败。这是一个例子。想象一下,您已经拥有Bari = 4个实例。由于i被声明为唯一,因此更新将失败。

UPDATE bar SET i = 4 WHERE id = ?;

这就是为什么在开始刷新对数据库的更改之前,首先需要删除整个集合bars的原因。希望这有助于解释问题。

答案 1 :(得分:0)

我不认为您应该将i定义为唯一。您应该使用复合键,以合并foo.idi。否则,您将遇到不同Foo实例之间的冲突。

顺便说一句,如果您将Foo.bars定义为List,则GORM会自动添加ix位置列