2010-01-15 4 views
11

To pytanie składa się z dwóch części, pierwsza część dotyczy czyszczenia listy, a druga dotyczy przypisania właściciela do obiektu.Jak wyczyścić i zastąpić kolekcję w relacji jeden do wielu w Grails/Groovy

Mam relacji jeden do wielu między obiektami domeny w moim modelu w Grails. Relacja wygląda tak ...

class Person { 

    static hasMany = [authorities: Role, locations: Location] 
} 

class Location { 

    static belongsTo = Person 

} 

W moim app lista locations na Person ją całkowicie odświeżony i zastąpiona nową listę na działania użytkownika. Co więcej dostaję listę obiektów Location niezależnie od powiązanego Person. Postanawiam, do której osoby je zastosować, pobierając aktualnie zalogowanego użytkownika, który nazywam activePerson i jest w porządku dla moich celów.

Co chcę zrobić, to usunąć wszystkie istniejące lokalizacje na activePerson i wstawić wszystkie nowe, wiążąc je z activePerson. Mam kilka właściwości na Person, których nie chcę trwać w tym momencie, więc chcę uniknąć zapisywania całego obiektu nadrzędnego tylko dlatego, że zmieniły się lokalizacje dzieci.

Pomyślałem o powtórzeniu listy activePerson.locations i usunięciu ich pojedynczo i poleganiu na GORM/Hibernate w celu grupowania zapytań i wypróżniania na końcu. To wydaje się brutalną siłą, chociaż może się udać. Spodziewałem się, że będzie metoda clearLocations lub coś podobnego, ale nie mogę jej znaleźć.

Jeśli po prostu zastąpię activePerson.locations nową listą i zadzwonię pod numer activePerson.save(flush:true), czy GORM obsłuży usunięcie istniejących wierszy?

Po drugie chcę umieścić nowe obiekty Location na activePerson. Ponownie mogę zapełnić activePerson.locations i uratować całość, ale chciałbym tego uniknąć, jeśli mogę. Mogę je zapisać pojedynczo, ale jak ustawić belongsTo na każdym obiekcie ?

Przypomnę więc:

  1. Jak wyczyścić listę w wielu końcu kolekcji jeden-do-wielu?
  2. Jak powiązać niezależne obiekty z obiektem nadrzędnym i utrzymywać je pojedynczo?

Dzięki

Odpowiedz

8

Dla # 1 można wyczyścić zbiór (to jest ustawiona domyślnie):

activePerson.locations.clear() 

dla # 2 Użyj addToLocations:

activePerson.addToLocations(location) 

i kiedy zapisz osobę w lokalizacji < -> relacje między osobami zostaną zaktualizowane.

+0

@Burt, dzięki (znowu) za odpowiedź, jestem ci winien piwo. To jednak sugeruje, że muszę utrzymywać obiekt Person, którego starałem się uniknąć. Czy istnieje sensowna alternatywa, czy powinienem po prostu żyć z aktualizowaniem rekordu, który tak naprawdę się nie zmienił? – Simon

+0

Oprócz odpowiedzi Burta, konieczne może być zaimplementowanie equals i hashcode w obiekcie kolekcji oraz określenie kaskady: "all-delete-orphan" w odwzorowaniu kolekcji. –

+2

'activePerson.locations.clear()' na kolekcji nie działa. Spróbuj: 'activePerson.locations.collect(). Each {item.removeFromLocations (it)}' – Athlan

8

Usuwanie Collection podejście nie pracował dla mnie:

activePerson.locations.clear() 

Spróbuj iteracyjne nad kolekcji z unikania ConcurrentModificationException wywołując collect():

activePerson.locations.collect().each { 
    item.removeFromLocations(it) 
} 

A potem zapisać podmiotu do wykonania instrukcji SQL :

activePerson.save flush:true 

link do artykułu, aby dowiedzieć się więcej: http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

+0

, to nie działało dla mnie, dopóki nie określiłem orphanRemoval = true na Entity @OneToMany (..., orphanRemoval = true) – Mahakala

+2

Czy "element" nie powinien być "activePerson"? W ten sposób możemy wywołać removeFromLocations (it)? –

6

Chociaż jest to starszy pytanie, wpadłem w bardzo podobnej sytuacji, w której chciałem zaktualizować zestaw rekordów podrzędnych. Oto sposób, w jaki zdecydowałem się go rozwiązać. Dla uproszczenia użyję tych samych nazw obiektów/relacji, co osoba pytająca.

  1. W bloku mapping domeny nadrzędnej, dodać:

    static mapping = { 
        locations(cascade: "all-delete-orphan") 
    } 
    
  2. W domenie podrzędnej, dodaj @EqualsAndHashCode adnotacji (na wszelki wypadek nie ma innego jeden czai się, mam na myśli groovy.transform.EqualsAndHashCode).

  3. Dodaj wszystkie elementy podrzędne do domeny nadrzędnej, używając metod Grails addTo (np. addToLocations), a następnie zapisz domenę nadrzędną.

Takie podejście wymaga zapisywania domenę nadrzędną (co pytający nie chce robić), wydaje się, że jest to najbardziej odpowiednie podejście biorąc pod uwagę wyraźne belongsTo definicja w modelu. Chciałbym zatem odpowiedzieć ponumerowanych pytań Pytający jest tak:

  1. Zamiast robić to ręcznie, niech Grails/Hibernacja usunąć rekordy określając zachowanie all-delete-oprhan Kaskada na relacji.

  2. Nie próbuj bezpośrednio zapisywać rekordów podrzędnych, ale zamiast tego zapisz obiekt nadrzędny, aby dopasować to, czego oczekuje Grails.

Powiązane problemy