Relazioni uno-a-molti e molti-a-molti
Mappi @OneToMany, @ManyToMany e @JoinTable con i tipi di propagazione e le strategie di caricamento.
Relazioni uno-a-molti e molti-a-molti è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.
Tipi di relazioni in JPA
JPA supporta quattro tipi di relazione: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. Ognuno associa vincoli di chiave esterna o di tabella di join.
@ManyToOne: lato proprietario
Una relazione molti-a-uno (ad esempio, molti Orders appartengono a un User) viene mappata con @ManyToOne e una @JoinColumn per la chiave esterna.
@Entity
public class Order {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}@OneToMany: lato inverso
Il lato inverso (un User ha molti Orders) utilizza @OneToMany(mappedBy = "user"). L'attributo mappedBy indica il campo sul lato proprietario che contiene la FK.
@Entity
public class User {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
}Metodo di supporto per la coerenza bidirezionale
Con le associazioni bidirezionali, mantenga entrambi i lati della relazione in un metodo di supporto per mantenere coerente il grafo degli oggetti prima del flush.
public void addOrder(Order order) {
orders.add(order);
order.setUser(this); // keep both sides in sync
}
public void removeOrder(Order order) {
orders.remove(order);
order.setUser(null);
}Tipi di cascade
CascadeType.ALL propaga tutte le operazioni (persist, merge, remove, refresh, detach) dal genitore al figlio. PERSIST e MERGE sono scelte comuni e sicure. REMOVE elimina i figli quando viene eliminato il genitore.
@OneToMany(mappedBy = "user",
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
orphanRemoval = true)
private List<Order> orders;orphanRemoval: eliminazione automatica dei figli
orphanRemoval = true elimina un'entità figlia quando viene rimossa dalla raccolta del genitore, anche senza una chiamata esplicita a entityManager.remove().
user.getOrders().remove(order); // triggers DELETE for the orphaned order on flush@ManyToMany con @JoinTable
Una relazione molti-a-molti (ad esempio, Student e Course) utilizza una tabella di join. La definisca sul lato proprietario con @JoinTable; il lato inverso utilizza mappedBy.
@Entity
public class Student {
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set<Course> courses = new HashSet<>();
}Colonne aggiuntive nella tabella di join
Quando la tabella di join richiede colonne aggiuntive (ad esempio, la data di iscrizione), trasformi @ManyToMany in due relazioni @OneToMany / @ManyToOne con una nuova entità che rappresenta la tabella di join.
@Entity
public class Enrollment {
@ManyToOne Student student;
@ManyToOne Course course;
private LocalDate enrolledAt;
}FetchType: LAZY vs EAGER
Caricamento predefinito: @ManyToOne e @OneToOne sono EAGER (vengono caricati immediatamente). @OneToMany e @ManyToMany sono LAZY (vengono caricati al momento dell'accesso). Utilizzi sempre LAZY per le raccolte, per evitare query N+1.
// Always override to LAZY:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private Category category;Problema delle query N+1
L'accesso a una raccolta lazy all'interno di un ciclo esegue una query per ogni entità (N+1). Risolva il problema con JOIN FETCH in JPQL o con @EntityGraph per caricare la raccolta con una sola query.
// N+1 problem:
List<User> users = repo.findAll();
users.forEach(u -> u.getOrders().size()); // 1 + N queries!
// Fix:
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders")
List<User> findAllWithOrders();Set vs List per le raccolte
Utilizzi Set per @ManyToMany (evita righe duplicate nella tabella di join). Utilizzi List per @OneToMany quando l'ordine è importante. Non utilizzi mai List con @ManyToMany: Hibernate eliminerà e reinserirà tutte le righe.
Verifica rapida
Che cosa indica mappedBy in un'annotazione @OneToMany?
Riepilogo
Utilizzi @ManyToOne+@JoinColumn sul lato proprietario (FK). Utilizzi @OneToMany(mappedBy=...) sul lato inverso. Utilizzi sempre LAZY per le raccolte. Risolva il problema N+1 con JOIN FETCH. Utilizzi un'entità di join per le relazioni molti-a-molti con colonne aggiuntive.
Domande Frequenti
La lezione «Relazioni uno-a-molti e molti-a-molti» è gratuita?
Sì — il testo completo di «Relazioni uno-a-molti e molti-a-molti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.
Cosa imparerò in «Relazioni uno-a-molti e molti-a-molti»?
Mappi @OneToMany, @ManyToMany e @JoinTable con i tipi di propagazione e le strategie di caricamento. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Java Academy?
Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Relazioni uno-a-molti e molti-a-molti»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Java Academy?
Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Mappatura delle entità con le annotazioni JPA
- Repository Spring Data e metodi di query
- Relazioni uno-a-molti e molti-a-molti
- Paginazione, ordinamento e proiezioni