2013-05-04 8 views
6

Ho i prossimi due entità con una relazione OnetoOne tra di loro:Persist OnetoOne relazione con SpringData APP

@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 */ 
} 

Sto cercando di eseguire questo codice:

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

Ma ottengo questo errore :

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 

posso "risolvere" è cambiare il mio codice per:

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); 
    } 
} 

La mia domanda è: quale è il modo corretto per mantenere una relazione OneToOne? Nel mio codice, perché ho salvato entrambe le parti della relazione per farlo funzionare?

risposta

15

Eccoci di nuovo.

Ogni associazione bidirezionale ha due lati: il lato proprietario e il lato inverso. La parte inversa è quella che ha l'attributo mappedBy. Il lato proprietario è l'altro. JPA/Hibernate interessa solo il lato proprietario. Quindi, se si inizializza semplicemente il lato inverso, l'associazione non verrà mantenuta.

È buona norma, in genere, inizializzare entrambi i lati dell'associazione. Innanzitutto perché si assicura che il lato proprietario sia inizializzato e in secondo luogo perché rende coerente il grafico delle entità, per il tuo bene.

Si noti inoltre che se si sta lavorando all'interno di una transazione (e si dovrebbe), tutte le entità restituite dalle query sono entità associate. Le modifiche applicate alle entità vengono automaticamente rese persistenti al momento del commit della transazione (o prima). Non è necessario salvare le entità in modo esplicito come si sta facendo.

+0

Grazie per la tua ottima risposta. Lo capisco adesso ma non capisco perché non devo salvare le mie entità in modo esplicito. Ciò che save() fa è chiamare il metodo save() del repository che è transazionale. Cosa dovrei fare? –

+2

Il punto di una transazione deve essere in grado di cambiare più entità, di più tipi, atomicamente. O tutto è salvato, o niente è. Questo è ciò che garantisce la coerenza dei dati. Ed è per questo che i servizi dovrebbero essere transazionali e non solo i repository. Una volta caricate le entità in una transazione e modificate nella stessa transazione, Hibernate persiste automaticamente le modifiche, senza la necessità di salvarle esplicitamente. In breve, tutto il codice nella tua domanda dovrebbe essere in un metodo di servizio transazionale e non dovresti chiamare 'save()'. –

Problemi correlati