Удаление объекта в приложении SpringBoot 2.0.5.RELEASE с использованием Spring Data JPA - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть базовое приложение SpringBoot 2.0.5.RELEASE.Используя Spring Initializer, JPA, встроенный Tomcat, шаблонизатор Thymeleaf и пакет в качестве исполняемого файла JAR.

У меня есть этот класс:

public class User implements Serializable {

    @OneToMany( cascade = CascadeType.ALL,orphanRemoval = true, 
                fetch = FetchType.EAGER,mappedBy = "user")
    @JsonIgnore
    private List<Wallet> wallets = new ArrayList<Wallet>();

..
}

и этот:

public class Wallet implements Serializable {

@ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "invoice_id")
    @JsonIgnore
    @NotNull
    private Invoice invoice;



    @OneToMany(mappedBy = "wallet", 
               cascade = CascadeType.ALL, 
               orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonIgnore
    private Set<Purchase> purchases = new HashSet<>();


    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id" , nullable=false)
    @JsonIgnore
    private User user;

..
}

и этот другой:

public class Purchase implements Serializable {

        @ManyToOne(fetch = FetchType.EAGER)
            @JoinColumn(name = "wallet_id")
            @JsonIgnore
            Wallet wallet;

        ...

    }

Но я удаляю кошелек из контроллера, который имеет счет-фактуру и покупки и принадлежит пользователю, кошелек не удаляется из БД

walletService.delete(walletService.findById(id).get());

это метод обслуживания:

@Transactional
    public void delete(Wallet wallet) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("deleting Wallet [ " + wallet + " ]");
        }


        wallet
            .getPurchases()
            .parallelStream()
            .forEach(p -> purchaseService.delete(p));

        walletRepository.delete(wallet);

    }

и

 @Transactional
     public void delete (Purchase purchase ) {
         purchaseRepository.delete (purchase);
     }

в файле свойств:

spring.jpa.show-sql=true

и последний запрос, который я вижу вконсоль вот такая:

select
    purchases0_.wallet_id as wallet_i8_13_0_,
    purchases0_.id as id1_13_0_,
    purchases0_.id as id1_13_1_,
    purchases0_.amount as amount2_13_1_,
    purchases0_.wallet_id as wallet_i8_13_1_ 
from
    t_purchase purchases0_ 
where
    purchases0_.wallet_id=?

и без удаления и без исключений !!!!

Ответы [ 4 ]

0 голосов
/ 24 сентября 2018

попробуйте это в контроллере:

    user.getWallets().remove(wallet);
    walletService.delete(wallet);       
    userService.save(user);
0 голосов
/ 24 сентября 2018

Может ли это быть возможным решением? Конфигурация Hibernate -> orphanRemoval = true будет удалять кошельки только в случае удаления объекта User?

0 голосов
/ 24 сентября 2018

Описание проблемы

Проблема возникает, когда вы пытаетесь удалить каждого потомка самостоятельно, в то время как родитель (то есть родитель) по-прежнему имеет ссылку на него, и так как ссылка имеет каскад Все установлено наон (в том числе, сохраняются и объединяются), он вызывает возрождение потомка (то есть покупки) в контексте, отменяя удаление.

  • Имейте в виду, что ссылки отражают то, что должно происходить в базе данныхпоэтому вы должны обнулять ссылки на объекты, которые вы удаляете, иначе вы не достигнете ожидаемого состояния желаемого

source: JPA / Hibernate, удаляющего "дочерние" сущности


Решение

Избавьтесь от удаления потомков, сделав поток для родителя, и измените класс кошелька так, чтобы каскадное удаление вводилось при покупках отношения:

@OneToMany(mappedBy = "wallet", 
           cascade = CascadeType.REMOVE,  // <--- here should be changed
           orphanRemoval = true, fetch = FetchType.LAZY)
@JsonIgnore
private Set<Purchase> purchases = new HashSet<>();

Тогда вам просто нужно позвонить walletRepository.delete(wallet);, чтобы полностью удалить родителей и детей.

0 голосов
/ 24 сентября 2018

Я могу вспомнить 2 случая здесь

  1. Вы добавили mappedBy в Wallet Класс, поэтому Purchase является владельцем объекта, и вам нужно удалить из Purchases

    попробуйте изменить метод удаления кошелька следующим образом

    @Transactional
    public void delete(Wallet wallet) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("deleting Wallet [ " + wallet + " ]");
        }
    
        wallet.getPurchases().removeAll();
    walletRepository.delete(wallet);
    
    }
    
  2. В идеале вы настроили CascadeType.ALL в Wallet, выполнив

    walletRepository.delete (кошелек);

    должен удалить Set<Purchase> тоже.

...