2014-09-03 691 views
0

我使用的是grails 2.4.2,但懷疑這與ORM(休眠)通常有關。grails/gorm:指定受'unique'約束的屬性

我想重新分配一個對象集合中的序數屬性。這個重新分配構成了對象的「重新洗牌」。

考慮:

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' 
    } 
} 

如何獲得上述洗牌試圖推過(即不翻倒的唯一約束)?

謝謝:)

回答

1

由於ORM將由一個更新Bar情況下,一個你只能做到這一點,如果你先刪除的Foo所有Bar情況下通過

foo.bars*.delete(flush: true) 

,然後執行其餘你的測試代碼。

這是爲什麼?

Hibernate將爲每個Bar實例創建一個Update語句,並且很可能會在第一次更新時失敗。這是一個例子。想象一下,你已經有Bar實例i = 4。由於i被聲明爲唯一的,所以更新將失敗。

UPDATE bar SET i = 4 WHERE id = ?; 

這就是爲什麼你需要刪除整個集合bars首先,你開始刷新你對數據庫的修改前的原因。希望這有助於解釋問題。

+0

刪除一組對象的添加只是這樣我就可以重新添加呢?我對此感覺不太舒服......是這種用例的最佳實踐嗎? – pointyhat 2014-09-03 11:26:44

+0

請在上面找到我的解釋 – saw303 2014-09-03 11:41:17

+0

我認爲這種用例是最壞的做法:) – injecteer 2014-09-03 11:43:04

0

我不認爲,你應該定義你的i是唯一的。您應該使用組合鍵代替foo.idi。否則,你會碰到不同的Foo實例之間的衝突。

順便說一句,如果你定義Foo.barsListix位置列由GORM自動

+0

謝謝@injecteer。具有明確的「i」屬性允許非連續序號(例如「1,3,4,5,...」),並且不一定是基於0的序號。通常,'i'屬性不僅用於排序,還用於爲對象分配實際的數字。 不確定我明白你的意思是跑'衝突'。之前沒有使用過複合鍵,但瀏覽文檔表明它可能會過度設計與「獨特」相同的解決方案。 使用列表時添加'ix':我不熟悉該功能。這是記錄的嗎?這是一個實際的域屬性? – pointyhat 2014-09-03 12:49:14

+0

我的意思是,如果您只使用'i'進行排序,並且如果它是基於0或1-或任何其他基礎且同時是唯一的,那麼它會導致衝突,如果您嘗試分配相同的'我'的價值不同'酒吧'實例。 – injecteer 2014-09-03 12:55:02

+0

''_idx'(對不起原文中的拼寫錯誤)列被添加到List中,用於List類型的集合,並且暴露給域類作爲List中的元素索引。 'Set'不需要這個。這就是ref-doc所說的:'這在數據庫級別工作的方式是Hibernate創建一個books_idx列,在那裏它保存了集合中元素的索引,以便在數據庫級別保留這個順序。 – injecteer 2014-09-03 12:58:17