CascadeType - merge vs persist - tworzy kopię

Odpowiedz Nowy wątek
2020-03-25 10:33

Rejestracja: 7 miesięcy temu

Ostatnio: 1 minuta temu

0

Cześć,
mam taki przypadek:

class Product {
    @OneToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, mappedBy = "product")
    private Set<Action> actions;

    public void addAction(Action action) {
        if (Objects.isNull(actions)) {
            actions = new HashSet<>();
        }
        actions.add(action);
        action.setProduct(this);
     }
}
class Action {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
}
Action action = new Action();
Product product = findProductById().orElseGet(() -> new Product()));
product.addAction(action);
saveAndFlush(product);
Long id = action.getId();

No i teraz w przypadku gdy findProductById() nie zwróci nic to tworzymy nowy Product, wsadzamy mu tam Action i zapisujemy, wtedy product.getActions().contains(action) == true i action ma założmy ID = 1, tak samo jak w utworzonym produkcie - zachodzi em.persist (saveAndFlush jest ze Spring Data JPA).
Natomiast w odwrotnym przypadku gdy findProductById() zwróci jakiś produkt i wsadzimy mu action to po zapisie product.getActions().contains(action) == false, bo
action ma ID = null natomiast akcja w produkcie ma normalnie nadany ID - np. 2 - zachodzi em.merge.

Problemu by nie było, gdyby nie to że potem potrzebne jest mi action.getId(). Nie mogę też zapisać najpierw action, a potem product, bo action ma na bazie not null na polu product. W dodatku to nie jest jedyna encja powiązana z Product, którą muszę tu zapisać. Teraz pytanie jak ładnie wyciągnąć ten id action z pojazdu, bo myślę że niemożliwym jest osiągnąć aby product.getActions().contains(action) w drugim przypadku (merge) było true - czyli żeby przy mergu nie tworzyło mi nowego obiektu action gdzieś w środku.

Pozostało 580 znaków

2020-03-25 11:41

Rejestracja: 12 lat temu

Ostatnio: 1 godzina temu

2

Jak masz napisany equals i hashcode? Zakładam, że używasz id wygenerowanego przez JPA - proponuję go nie używać, najlepiej generować swój UUID.


Ivory Tower Architect
edytowany 1x, ostatnio: Charles_Ray, 2020-03-25 11:43

Pozostało 580 znaków

2020-03-25 11:45

Rejestracja: 7 miesięcy temu

Ostatnio: 1 minuta temu

0

Jeśli chodzi o equals i hashcode próbowałem już na różne sposoby - na różnych polach (tych niezmiennych - nie dotykałem na pewno generownaych bazodanowo ID'kow). Co do id - tak, bazodanowe id to te generowane przez JPA. Niestety nie mam możliwości generowania swojego ID, choć wiem, że to wiele by ułatwiło - takie są zarządzenia z góry.

e; znam tą prelekcję Kuby, bardzo dużo dałoby tutaj generowanie takiego UUID - ale niestety nie możemy, wszystko generuje się przy zapisie.

edytowany 2x, ostatnio: lavoholic, 2020-03-25 11:50

Pozostało 580 znaków

2020-03-25 13:15

Rejestracja: 4 lata temu

Ostatnio: 10 minut temu

0

A nie możesz generować ID z bazy przez query, wrzucać go do encji, i zapisywać encji z już ustawionym id przez setter?

Edit:
Ewentualnie zapisać główną encje i dopiero po zapisie dopchać tę relację.

edytowany 1x, ostatnio: MrMadMatt, 2020-03-25 14:38

Pozostało 580 znaków

2020-03-25 15:18

Rejestracja: 7 miesięcy temu

Ostatnio: 1 minuta temu

0

Poszło to w inny sposób, dość prosty, banalny - czyli taki na który nigdy się nie wpadnie.
Po prostu swój em.persist - bez zabawy w JpaRepository i jego


if (entity.isNew()) {
   em.persist(entity);
   return entity;
}
else {
   return em.merge(entity);
}
edytowany 2x, ostatnio: lavoholic, 2020-03-25 15:19
czyli chyba dokladnie to o czym w 26:10 mowi Kubrynski w wyzej wrzuconym nagraniu ? - filemonczyk 2020-03-26 08:05
zgadza się - to była jedna z rzeczy, która mi o tym przypomniała - lavoholic 2020-03-26 08:28

Pozostało 580 znaków

Odpowiedz

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