2013-05-04 15 views
6

mam kolejne dwa podmioty z relacji między nimi OneToOne:Utrzymują OneToOne relację z SpringData WZP

@Entity 
@Table(name = "tasks") 
public class Task { 
    @OneToOne(mappedBy = "task", cascade = CascadeType.PERSIST) 
    private Tracker tracker; 

    /* More code */ 
} 

@Entity 
@Table(name = "trackers") 
public class Tracker { 
    @OneToOne 
    @JoinColumn(name = "trk_task", unique = true) 
    private Task task; 

    /* More code */ 
} 

próbuję uruchomić ten kod:

Task task = taskService.findDispatchableTask(); 
if (task != null) { 
    Tracker tracker = trackerService.findIdleTracker(); 
    if (tracker != null) { 
     task.setTracker(tracker); 
     task.setStatus(TaskStatus.DISPATCHED); 
     taskService.save(task); 
    } 
} 

Ale ten błąd :

ERROR org.hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) 
org.hibernate.AssertionFailure: non-transient entity has a null id 

mogę "rozwiązać" to zmienia mojego kodu:

Task task = taskService.findDispatchableTask(); 
if (task != null) { 
    Tracker tracker = trackerService.findIdleTracker(); 
    if (tracker != null) { 
     tracker.setTask(task); 
     trackerService.save(tracker); 
     task.setTracker(tracker); 
     task.setStatus(TaskStatus.DISPATCHED); 
     taskService.save(task); 
    } 
} 

Moje pytanie brzmi: Jaki jest właściwy sposób na utrzymanie relacji OneToOne? W moim kodzie, dlaczego mam zapisać obie części relacji, aby działało?

Odpowiedz

15

Znów jedziemy.

Każde powiązanie dwukierunkowe ma dwie strony: stronę właściciela i stronę odwrotną. Strona odwrotna to ta, która ma atrybut mappedBy. Strona właściciela jest druga. JPA/Hibernate dba tylko o stronę właściciela. Jeśli więc zainicjujesz odwrotną stronę, powiązanie nie będzie trwało.

Zazwyczaj dobrą praktyką jest inicjowanie obu stron stowarzyszenia. Po pierwsze dlatego, że upewnia się, że strona właściciela jest zainicjalizowana, a po drugie dlatego, że tworzy wykres jednostek spójny dla twojego własnego dobra.

Należy również zauważyć, że jeśli pracujesz wewnątrz transakcji (i powinieneś), wszystkie elementy zwrócone przez twoje zapytania są dołączonymi jednostkami. Zmiany zastosowane do jednostek są automatycznie utrwalane w momencie zatwierdzenia transakcji (lub wcześniej). Nie ma potrzeby, aby uratować te istoty, które tak zdecydowanie robią.

+0

Dzięki za wspaniałą odpowiedź. Rozumiem to teraz, ale nie rozumiem, dlaczego nie muszę koniecznie ocalić moje istoty. Metoda save() polega na wywołaniu metody składowania save(), która jest transakcyjna. Co powinienem zrobić? –

+2

Punktem transakcji jest możliwość zmiany wielu elementów, wielu rodzajów, atomowo. Albo wszystko jest zapisane, albo nic nie jest. To gwarantuje spójność danych. I dlatego usługi powinny być transakcyjne, a nie tylko repozytoria. Po załadowaniu elementów transakcji i zmodyfikowaniu ich w tej samej transakcji, Hibernate automatycznie kontynuuje zmiany bez konieczności ich wyraźnego zapisywania. Krótko mówiąc, cały kod w twoim pytaniu powinien być metodą transakcyjną i nie powinieneś wywoływać 'save()'. –

Powiązane problemy