2015-02-25 44 views
12

Mam następujący układ zajęć:Kolejność zapisywania kaskadowego GORM w zależności od nazw pól? Naprawdę?

class A { 
    static belongsTo = [c: C] 
    B b 
} 

class B { 
    static belongsTo = [c: C] 
} 


class C { 
    static hasMany = [bbs: B, aas: A] 
} 

Gdybym teraz tworzyć instancje tych klas ...

B b = new B() 
A a = new A() 
a.b = b 

C c = new C() 
c.addToBbs(b) 
c.addToAas(a) 

... i spróbuj zapisać c ...

c.save() 

... Otrzymuję org.hibernate.TransientObjectException Message object references an unsaved transient instance - save the transient instance before flushing: B.

To, co myślę, że GORM robi, to najpierw kaskada zapisu do c.aas, a następnie potknie się o instancję a.b, która nie jest jeszcze zapisana. Dlatego wyjątek.

Teraz trick: Gdybym przemianowany na własność Caas do xxs, to działa:

class C { 
    static hasMany = [bbs: B, xxs: A] 
} 

b zostaje zapisany, potem a. GORM wydaje się kaskadować zapisy w porządku leksykograficznym pól (najpierw bbs, następnie xxs)!

Jak mogę kontrolować kolejność użycia GORM dla zapisu kaskadowego (z wyjątkiem zmiany nazwy pól, co wydaje mi się bardzo kruche)?

+1

To może nie odpowiedzieć na dokładną pytanie, ale były zapisuje zawinięte w transakcji? Spodziewałbym się twojej pierwszej próby pracy tak długo, jak wszystko było transakcyjne. –

+0

Tak. Podczas zapisywania była aktywna transakcja. –

+0

Przepraszam, naciśnij przycisk edycji zbyt wcześnie. Czy to działa, jeśli używasz "c.addToAas (a)" (bez c.addToBbs (b))? Nie jestem pewien, czy zapisy spadną do trzeciego poziomu, ale warte strzału (chciałbym też wiedzieć, czy sugestia Gaurava o "kaskadzie: oszczędzanie" działa, ale nie spodziewałbym się, że to coś zmieni, biorąc pod uwagę domyślne mapowanie dla hasMany to "cascade: all".) –

Odpowiedz

0

O ile mi wiadomo, GORM nie zapewnia sposobu kontrolowania sekwencji, w której kaskady zapisu są stosowane do właściwości.

Myślę, że powinieneś być w stanie rozwiązać ten problem przy użyciu jednej z następujących metod:

1] Jawnie zapisać B jest wystąpienie przed zapisaniem A 's (jak zawsze robi dla pojedynczego związku bez belongsTo)

B b = new B().save() 
A a = new A(b: b) // b should already be persisted as A doesn't `belongsTo` B 
C c = new C() 
c.addToBbs(b) 
c.addToAas(a) 
c.save() 

2] Definiowanie custom cascading behavior własności b klasy A

class A { 
    static belongsTo = [c: C] 
    B b 

    static mapping = { 
     b cascade: 'save' 
    } 
} 

Uwaga: ani podejście badano

0

W moich wielu-do-wielu tych, zapisać klasy C przed próbuję zrobić .addTo na

B b = new B() 
A a = new A() 
a.b = b 

C c = new C() 
c.save() 
c.addToBbs(b) 
c.addToAas(a) 

I musiał zdefiniować niestandardowy kaskadowe zachowanie w niektórych okolicznościach.

Artykuły te pomagają zrozumieć takie problemy.

https://spring.io/blog/2010/06/23/gorm-gotchas-part-1/

https://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

https://spring.io/blog/2010/07/28/gorm-gotchas-part-3/

+0

To nie działa dla mnie. C nie może być przechowywane bez A i B. Znam artykuły GORM Gotcha (masz rację, są naprawdę dobre). –

+0

Tak, pierwszeństwo ma kolejność zapisywania, a co się dzieje podczas kaskadowania. Zamiast zmieniać aa na xxs, aby zapisać je w kolejności alfabetycznej, lepszym rozwiązaniem jest ustalenie, co należy najpierw zapisać, i zapisanie ich w tej kolejności ... Nie jest to zbyt przyjazne dla użytkownika, prawda? –