Hibernate annotato molti-a-uno non aggiungere figlio a genitore Collection
-
05-10-2019 - |
Domanda
Ho le seguenti classi di entità Hibernate annotate:
@Entity
public class Cat {
@Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) @Id
private Long id;
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Kitten> kittens = new HashSet<Kitten>();
public void setId(Long id) { this.id = id; }
public Long getId() { return id; }
public void setKittens(Set<Kitten> kittens) { this.kittens = kittens; }
public Set<Kitten> getKittens() { return kittens; }
}
@Entity
public class Kitten {
@Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) @Id
private Long id;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Cat cat;
public void setId(Long id) { this.id = id; }
public Long getId() { return id; }
public void setCat(Cat cat) { this.cat = cat; }
public Cat getCat() { return cat; }
}
La mia intenzione: ecco un bidirezionale uno-a-molti / molti-a-uno tra Gatto e gattino, con Kitten è il "lato possedere".
Quello che voglio che accada è quando creo un nuovo gatto, seguito da un nuovo gattino riferimento al gatto, Set di gattini sul mio gatto dovrebbe contenere il nuovo gattino . Tuttavia, questo non accade nella seguente test:
@Test
public void testAssociations()
{
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
Cat cat = new Cat();
session.save(cat);
Kitten kitten = new Kitten();
kitten.setCat(cat);
session.save(kitten);
tx.commit();
assertNotNull(kitten.getCat());
assertEquals(cat.getId(), kitten.getCat().getId());
assertTrue(cat.getKittens().size() == 1); // <-- ASSERTION FAILS
assertEquals(kitten, new ArrayList<Kitten>(cat.getKittens()).get(0));
}
Anche dopo ri-interrogare il Gatto, il set è ancora vuota:
// added before tx.commit() and assertions
cat = (Cat)session.get(Cat.class, cat.getId());
mi aspetto troppo da Hibernate qui? O è l'onere su di me per gestire la raccolta me stesso? Il (Annotazioni) Documentazione non fa alcuna indicazione che ho bisogno di creare metodi di convenienza addTo*
/ removeFrom*
sul mio oggetto padre.
Qualcuno può per favore mi illumini su ciò che le mie aspettative dovrebbero essere da Hibernate con questo rapporto? Oppure, se non altro, mi puntare alla corretta documentazione di Hibernate che mi dice cosa devo essere in attesa di accadere qui.
Che cosa devo fare per fare il genitore Collection contiene automaticamente il bambino Entity?
Soluzione
Non aggiungerà automaticamente. È necessario aggiungere voi stessi.
Non vorrei chiamare direttamente Kitten.setCat()
neanche. Il modello tipico per questo è di mettere un metodo in Cat
come:
public void addKitten(Kitten kitten) {
if (kittens == null) {
kittens = new HashSet<Kitten>();
}
kittens.add(kitten);
kitten.setCat(this);
}
e poi semplicemente chiamare:
cat.addKitten(kitten);
Altri suggerimenti
Quando si lavora con le associazioni bi-direzionale, si deve gestire entrambi i lati del "link" ed è molto comune l'uso di metodi di gestione collegamento difensive per che, come suggerito da @ Cletus. Dalla documentazione Hibernate Nucleo:
1.2.6 . rapporti di lavoro bidirezionali
In primo luogo, tenere presente che Hibernate non pregiudica il normale semantica di Java. Come abbiamo fatto a creare un collegamento tra un Persona e un evento nel esempio unidirezionale? Si aggiunge un istanza di eventi per la raccolta di riferimenti di eventi, di un'istanza di Persona. Se si vuole fare questo link bi-direzionale, si deve fare il stesso sull'altro lato aggiungendo un Persona di riferimento per la raccolta di un evento. Questo processo di impostazione" il link da entrambe le parti" è assolutamente necessario con collegamenti bidirezionali.
Molti sviluppatori di programmare in difesa e creare metodi di gestione puntano a impostate correttamente entrambi i lati (per esempio, in persona):
protected Set getEvents() { return events; } protected void setEvents(Set events) { this.events = events; } public void addToEvent(Event event) { this.getEvents().add(event); event.getParticipants().add(this); } public void removeFromEvent(Event event) { this.getEvents().remove(event); event.getParticipants().remove(this); }
I metodi get e set per la collezione sono ora protetti. Questo permette classi dello stesso pacchetto e sottoclassi di accedere ancora il metodi, ma evita tutti gli altri possano modificare le collezioni direttamente. Ripetere i passaggi per la raccolta sul lato opposto.