JPA i Hibernate #11 - Relacja One-to-many

JPA #11 – Relacja One-to-many

Relacja One-to-many to powiązanie jednego wpisu w bazie danych do kilku innych, znajdujących się w innej tabeli. Przyjrzyjmy się temu na prostym przykładzie aplikacji rezerwującej pokoje dla kilku gości.

Zdarza się, że rezerwacja pokoju jest na więcej niż jednego gościa. W klasie Reservation przygotujmy się na taką ewentualność zmieniając jednego gościa na całą listę gości. Logika podpowiada, że relację @OneToOne zastępujemy @OneToMany.

Zatem poprawiony kod będzie wyglądał tak:

@Entity
public class Reservation {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToMany
    private List<Guest> guests;

    public Reservation(List<Guest> guest) {
        this.guests = guest;
    }
}

Poprawa kodu

Do celu pokazania jak działa relacja One-to-many stwórz drugiego gościa w klasie App.

W metodzie createReservation() zmień argument na Arrays.asList() z naszymi goścmi jako argumentami.

W createReservation() zmień argumenty na listę gości.

Usuń wypisywanie na ekran komunikatu o gościu i jego ID – nie potrzebujemy na tym się skupiać w tym ćwiczeniu.

Designed by pch.vector / Freepik

Wspólny kod będzie uproszczony. Za gości posłużą guest i guest2. Wygląda więc tak:

Uwaga: Pracując nad prawdziwą aplikacją nie nazywajmy w ten sposób zmiennych!

package pl.clockworkjava.hotelreservation.jpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.Arrays;

public class App {

    private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("thePersistenceUnit");
    private static EntityManager em  = factory.createEntityManager();

    public static void main(String[] args) {
        GuestRepository guestRepository = new GuestRepository(em);
        ReservationRepository reservationRepository = new ReservationRepository(em);
        guestRepository.createNewGuest("Paweł", 34);
        guestRepository.createNewGuest("Kinga", 37);
        Guest guest = guestRepository.findById(1l);
        Guest guest2 = guestRepository.findById(2l);

        reservationRepository.createReservation(Arrays.asList(guest, guest2));
    }
}
package pl.clockworkjava.hotelreservation.jpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import java.util.Arrays;
import java.util.List;

public class ReservationRepository {

    private EntityManager em;

    public ReservationRepository(EntityManager em) {
        this.em = em;
    }

    public void createReservation(List<Guest> guests) {

        Reservation r = new Reservation(guests);

        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        em.persist(r);
        transaction.commit();

    }
}

Jeśli wszystko napisaliśmy jak należy to po odpaleniu zobaczymy między innymi takie linijki w konsoli:

Konsola aplikacji – informacja o tabelach, które stworzył dla nas Hibernate

W obecnej sytuacji potrzebna jest tabela pośrednicząca Reservation_Guest – zgodnie z zasadami budowy baz danych. Hibernate “pomyślał” o tym za nas i stworzył nie dwie, a trzy tabele.

Zatem przyjrzyjmy się obecnej sytuacji na grafie.

Schemat relacji One-to-many

Tabela łączona Reservation_Guest przechowuje ID rezerwacji i łączy ją z ID gościa. Reservation_ID może się powtarzać, a Guest_ID musi być unikalne. Reservation_ID wskazuje na tabelę Reservation, która zostałą zredukowana do jednej kolumny. Guest_ID wskazuje na dane gościa w tabeli Guest.

Tabela, która łączy nasze tabele w relacji One-to-many jest naszą tabelą główną. To ona wskazuje nam odpowiednie pola w pozostałych dwóch tabelach.

Prześledzmy jeszcze raz działanie aplikacji i obecnego kodu.

Na początku tworzymy pierwszego i drugiego gościa oraz szukamy ich po ID. Następnie tworzymy rezerwację:

Tworzenie rezerwacji

W pierwszym insert dajemy ID do tabeli Reservation, a dwa kolejne insert dodają dane do tabeli Reservation_Guest.

Podsumowanie

Relacja One-to-many to powiązanie jednej tabeli z kilkoma. Taka tabela wiążąca pozostałe jest naszą tabelą główną. Hibernate tworzy ją sam, dzięki czemu na tym etapie nie musimy zagłębiać się w szczegóły. Dodatkowo, dzięki temu rozwiązaniu jesteśmy w stanie zbudować bazę danych zgodne z zasadami dla relacyjnych baz danych.

Kod aplikacji znajdziesz w publicznym repozytorium GitHub.

By być na bieżąco i mieć realny wpływ na tematykę tworzonych artykułów zapraszam do dołączenia do mojego newslettera.


Informacje oparte zostały o materiał darmowego kursu wprowadzającego w świat JPA i Hibernate “Fundamenty JPA i Hibernate” dostępnego w formie wideo na platformie ClockworkJava.

Pozostałe artykuły z cyklu:

  1. Czym jest persystencja?
  2. ORM, JPA i Hibernate
  3. Podstawowe elementy
  4. Konfiguracja projektu
  5. Pierwsza encja
  6. Create
  7. Read
  8. Update
  9. Delete
  10. Relacja One-to-One
  11. Relacja One-to-Many

2 myśli w temacie “JPA #11 – Relacja One-to-many”

  1. Fajny, krótki wpis do kawy. To lubię 🙂
    Można rozszerzyć wpis o to, że nie trzeba wcale wprowadzać kolejnej tabeli pośredniczącej, jeżeli nie ma takiej potrzeby. Można dodać adnotację @JoinColumn i oprzeć się na dwóch tabelach.

    1. Dzięki za cenną uwagę.
      Cykl jest dedykowany do omówienie podstaw i na prostych przypadkach lepiej się je przedstawia. To jeszcze nie koniec w tym temacie więc – zanotowałam.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *