• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Problem z zaprojektowaniem encji

VPS Starter Arubacloud
0 głosów
347 wizyt
pytanie zadane 30 grudnia 2017 w Java przez przemko06 Początkujący (370 p.)

Ostatnio zacząłem sie uczyć Hibernate i mam problem z encjami, a dokladnie z relacjami.

Jeżeli chodzi o klase Order to przechowuje ona Client gdzie zachodzi relacja @ManyToOne czyli wiele zamowień dla jednego klienta. Dodatkowo w Order przechowuje liste produktów i tu pojawia sie problem. Jak mam to zmapować? Jaką adnotacje dać? Czy może klasa Order powinna przchowywać Liste idProduktów? Jakiej adnotacji użyć? Dodatkowo jeżeli chodzi o produkty to chce je przechowywać w bazie i na podstawie tych produktów co są bedzie tworzone zamowienie. Proszę o pomoc

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private List<Product> products;

    @ManyToOne(cascade =  CascadeType.ALL)
    @JoinColumn(name = "id_client")
    private Client client;

 


@Entity
public class Client {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String surname;
    @Column(name = "login")
    private String email;
    private String password;

    @Transient
    private int numberClient;

    @OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
    private List<Order> order;

 

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productName;
    private double price;

 

1 odpowiedź

+1 głos
odpowiedź 30 grudnia 2017 przez Tomasz90 Nałogowiec (25,140 p.)
wybrane 2 stycznia 2018 przez przemko06
 
Najlepsza
List<Product> w encji Order jest jak najbardziej ok tylko mapowania dodaj tak jak masz między Client a Order (czyli jeden do wielu)
komentarz 30 grudnia 2017 przez przemko06 Początkujący (370 p.)

Czyli coś takiego?

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<Product> products;

    @ManyToOne(cascade =  CascadeType.ALL)
    @JoinColumn(name = "id_client")
    private Client client;

 

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productName;
    private double price;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "id_order")
    private Order order;

 

Tylko że coś nie tak jest jak tak zrobiłem...  Do tabeli product została dodana kolumna id_order, która jest nullem. A dobrze by było zrobić żeby w tabeli order było id danego produktu.

 

Metoda testowa:

ProductService productService = new ProductService();

    Product p1 = new Product("Czekolada", 4);
    Product p2 = new Product("Mąka", 5);
    Product p3 = new Product("Kawa", 16);
    Product p4 = new Product("Cukier", 8);

    productService.save(p1);
    productService.save(p2);
    productService.save(p3);
    productService.save(p4);

    Client client1 = new Client("Przemek", "Szlachta", "test@gmail.com", "admin1234");

    ClientService clientService = new ClientService();

    clientService.save(client1);


    OrderService orderService = new OrderService();

    //Zamowienie nr 1
    Order order = new Order(client1);
    order.addProduct(productService.findById((long) 1));
    order.addProduct(productService.findById((long) 2));
    order.addProduct(productService.findById((long) 3));
    orderService.save(order);

    //Zamowienie nr 2
    Order order2 = new Order(client1);
    order2.addProduct(productService.findById((long) 1));
    order2.addProduct(productService.findById((long) 2));
    order2.addProduct(productService.findById((long) 4));
    orderService.save(order2);

 

komentarz 30 grudnia 2017 przez Tomasz90 Nałogowiec (25,140 p.)
Masz w tej chwili mapowanie obustronne, czyli musisz obie strony relacji zaktualizować tzn.

1) dodajesz do listy zamówień produkt

2) produktowi ustawiasz id zamówienia do którego on należy

A tak poza tym to te rzutowania wg mnie też nie mają sensu bo skoro wyciągasz po id to metoda powinna przyjmować Long, a jak chcesz go zapisać na sztywno tak jak to zrobiłeś to dodajesz "L" na końcu czyli 1L, 2L itp.
komentarz 31 grudnia 2017 przez przemko06 Początkujący (370 p.)

Chyba nie dokońca rozumiem, albo po prostu sam sobie komplikuje sprawe. Ja sobie to wyobrażam tak:

Tabela Client

Tabela Product

Tabela Order

Ja to tak rozumuje.

W sensie że administrator dodaje produkty do bazy. A potem kilka klientów robi zamowienie i korzysta z tych produktów. Wiec w tabeli product nie powino byc id zamowienia, bo wtedy musial bym dublowac produkty no nie? Mam totalna zaćme jak to zrobić i stoje juz od paru dni z tym problemem :/ Już teraz wogole nie wiem jakich adnoatcji mam uzyc xD

1
komentarz 31 grudnia 2017 przez Tomasz90 Nałogowiec (25,140 p.)
w Twojej sytuacji to najlepiej jakbyś miał dodatkową tabelę np OrderProduct, która połączy Ci produkt z zamówieniem. O ile w tabeli Order może być client_id bo każdy klient może mieć swoje zamówienie, to o tyle w order_id w tabeli product nie będzie miało większego sensu bo doprowadzi do powielenia danych. Aby zrobić tą tabelę wiążącą potrzebujesz adnotacji @JoinTable zamiast @JoinColumn

jak to zmapować masz tutaj pokazane:

http://www.java2s.com/Tutorials/Java/JPA/0810__JPA_OneToMany_Mapping_Table.htm
komentarz 1 stycznia 2018 przez przemko06 Początkujący (370 p.)

Tak to zrobilem:

@Entity
@Table(name = "orders")
public class Order {

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

    @OneToMany
    @JoinTable(name = "order_product", joinColumns = @JoinColumn(name = "order_id"), inverseJoinColumns = @JoinColumn(name = "product_id"))
    private List<Product> products;

    @ManyToOne(cascade =  CascadeType.ALL)
    @JoinColumn(name = "id_client")
    private Client client;

Niby wszytko ładnie jak dodaje jedno zamowienie. 

Ale jak dodaje dwa zamowienia gdzie produkty sie powtarzaja to mam error. Czyli jak np do pierwszego zamowienia dam powiedzmy, mąke, kawe, a do drugiego czekolade, make to mam taki błąd.

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_3yjm7j95wlk9mrexq0gih8xr7"

 

komentarz 1 stycznia 2018 przez przemko06 Początkujący (370 p.)

Update:

Zrobiłem to tak i teraz wszytko działa. Tylko nie wiem czy to dobre rozwiązanie.

@Entity
@Table(name = "orders")
public class Order {

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

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "order_product", joinColumns = @JoinColumn(name = "order_id"), inverseJoinColumns = @JoinColumn(name = "product_id"))
    private List<Product> products;

    @ManyToOne(cascade =  CascadeType.ALL)
    @JoinColumn(name = "id_client")
    private Client client;

 

1
komentarz 1 stycznia 2018 przez Tomasz90 Nałogowiec (25,140 p.)
Wcześniej Ci musiało jakiegoś constrainta nałożyć na tabeli order_product i przez to błąd leciał. Takie rzeczy musisz diagnozować analizując logi Hibernate'a, żeby widzieć jakie zapytania wykonuje, a także sprawdzać co się na bazie dzieje. Też tworzenie całego schematu bazy przez Hibernate nie jest jedynym rozwiązaniem. Zawsze można mieć skrypt w SQL do tego.

Co do tej relacji to zależy od tego, czy potrzebujesz wiele do wielu. Bo nie wiem jakie masz założenia w swoim projekcie.

Ten FetchType.EAGER na kolekcjach nie jest wydajnościowo dobrym rozwiązaniem bo załóżmy będziesz chciał wyświetlić listę 1000 zamówień bez wchodzenia w szczególy konkretnego zamówienia. No to przy wyświetlaniu zamówień w tej chwili pobierze Ci od razu wszystkie produkty jakie zawierają te zamówienia (czego najprawdopodobniej nie będziessz chciał)
komentarz 2 stycznia 2018 przez przemko06 Początkujący (370 p.)
hmm no racja. Ale narazie chyba to mi starczy. Bede myślał później jak to pozmieniać. Narazie ten wynik mnie zadowala. Dzięki za pomoc :)

Podobne pytania

0 głosów
1 odpowiedź 1,855 wizyt
pytanie zadane 10 grudnia 2022 w Java przez letmestay Użytkownik (520 p.)
0 głosów
1 odpowiedź 1,149 wizyt
+1 głos
1 odpowiedź 376 wizyt
pytanie zadane 7 listopada 2022 w Java przez Lulex Użytkownik (820 p.)

92,452 zapytań

141,262 odpowiedzi

319,079 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...