Relacje hibernate OneToMany

0

WItam tworzę sobie prosty system do pisania umów na na usługi telekomunikacyjne
chce zrobić tak. Stworzyć jakiś pakiet usług na początek chce powiązać dany pakiet z wieloma okresami długości umowy. Tak by na dany pakiet można było podpisać umowe tylko np na 12 miesięcy albo 15

tak wygląda mój produkt (pakiet)

@Entity
public class Product {

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

    private String name;

    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;

    @ManyToOne
    @JoinColumn(name = "peri_id")
    private Periods periods;

    private BigDecimal price;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Periods getPeriods() {
        return periods;
    }

    public void setPeriods(Periods periods) {
        this.periods = periods;
    }
}

tak wygląda klasa okres (admin może tworzyć nowe okresy)

@Entity
public class Periods {

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

    private String period;

    @ManyToOne
    private Product product;

    @ManyToOne
    private User userCreate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getPeriod() {
        return period;
    }

    public void setPeriod(String period) {
        this.period = period;
    }

    public User getUserCreate() {
        return userCreate;
    }

    public void setUserCreate(User userCreate) {
        this.userCreate = userCreate;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

a tu mam dodatkową klasę by zamknąć to w jednej tabeli

@Entity(name = "product_periods")
public class ProductsPeriods {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany
    private List<Periods> periodsList = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public List<Periods> getPeriodsList() {
        return periodsList;
    }

    public void setPeriodsList(List<Periods> periodsList) {
        this.periodsList = periodsList;
    }
}

muszę przyznać, że nie rozumiem tego za bardzo zapisać chce to w taki sposób

    @PostMapping("/new/product")
    public String saveProduct(Product product) {
        productRepository.save(product);
        periodsList.clear();
        return "redirect:/system/dashboard/new/product";
    }

jaki i też tak

    @PostMapping("/new/product")
    public String saveProduct(Product product) {
        ProductsPeriods productPeriods = new ProductsPeriods();
        productPeriods.setProduct(product);
        productPeriods.setPeriodsList(periodsList);
        productPeriodsRepository.save(productPeriods);
        productRepository.save(product);
        periodsList.clear();
        return "redirect:/system/dashboard/new/product";
    }

wszystkie okresy są zapisywane najpierw do do listy periodsList a następnie chce to wrzucić do bazy danych.
Jak to rozwiązać by było tak jak pisałem na początku ?

1

Witaj!

Najpierw o modelu danych. Opisaną przez Ciebie sytuację można zamodelować na kilka sposobów. Opiszę poniżej dwa z nich:

  1. Product [1] ---> [n] Period, Period [1] ---> [n] User

W tym modelu dla każdego produktu okresy definiujesz niezależnie. Użytkownik bezpośrednio powiązany jest z okresem, a poprzez niego pośrednio z produktem. Są to dwie proste relacje jeden-do-wielu. Zaleta to prostota, natomiast nie sprawdzi się to, jeśli będziesz chciał wyciągać informacje w stylu "lista klientów oraz ich umów o długości 12 miesięcy".

  1. Product [1] ---> [n] Offer [n] <--- [1] Period, ProductPeriod [n] <---> [n] User

Patrząc na kod wydaje mi się, że do czegoś podobnego dążyłeś. Masz produkty, masz okresy umów i z nich budujesz "oferty" dla użytkowników. Pojedyncza oferta to jakiś pakiet z określoną długością trwania umowy. Możesz tutaj też wstawić np. jakąś flagę informującą czy dana oferta jest wciąż w sprzedaży (musisz trzymać o niej informacje, ponieważ mogą istnieć klienci, którzy podpisali na nią umowę). W tym modelu użytkownicy nie są spięci z produktami czy okresami, ale z konkretnymi ofertami.

Tutaj masz dwie relacje jeden-do-wielu oraz jedną relację wiele-do-wielu.

Teraz o Twoim kodzie, czyli jak dojść do tej sytuacji. Widzę, że się trochę pogubiłeś, ponieważ zaplątały Ci się kierunki referencji. Popatrz: w klasie Product napisałeś, że produkt może być przypisany do jednego okresu, a okres może mieć wiele produktów. Jednocześnie w klasie Period napisałeś coś sprzecznego: okres może być przypisany do jednego produktu, a produkt może mieć wiele okresów.

W JPA (i innych ORM-ach również) relacje modeluje się według paru schematów. Na początek wystarczy, że się ich wyuczysz i będziesz je konsekwentnie stosował. Możesz sobie to zapamiętać w ten sposób.

  1. relacja jeden-do-wielu (jeden A, wiele B):```

w klasie A dajesz:

@OneToMany
private List<B> bs;

w klasie B dajesz:

@ManyToOne
private A a;
  1. relacja wiele-do-wielu:

w klasie A dajesz:

@ManyToMany
private List<B> bs;

w klasie B dajesz:

@ManyToOne
private A a;

To są dwa podstawowe schematy. Nie zajmuj się na razie relacjami jedno/dwukierunkowymi itd. lecz skup na ich dobrym opanowaniu. Wystarczą one do zamodelowania Twojego problemu. Dodatkowo, przećwicz wybieranie, która strona jest właścicielem danej relacji poprzez położenie tam adnotacji @JoinColumn (dla jeden-do-wielu) bądź @JoinTable dla wiele-do-wielu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1