Reputation: 1950
I have a basic SpringBoot 2.0.5.RELEASE app. Using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.
I have this class:
public class User implements Serializable {
@OneToMany( cascade = CascadeType.ALL,orphanRemoval = true,
fetch = FetchType.EAGER,mappedBy = "user")
@JsonIgnore
private List<Wallet> wallets = new ArrayList<Wallet>();
..
}
and this one:
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;
..
}
and this other one:
public class Purchase implements Serializable {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "wallet_id")
@JsonIgnore
Wallet wallet;
...
}
But I delete a wallet form the controller that have an invoice and purchases and belong to a user the wallet is not deleted from the DB
walletService.delete(walletService.findById(id).get());
this is the service method:
@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);
}
and
@Transactional
public void delete (Purchase purchase ) {
purchaseRepository.delete (purchase);
}
in the properties file:
spring.jpa.show-sql=true
and the last query I see in the console is this one:
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=?
and no delete and no Exceptions !!! !
Upvotes: 2
Views: 1219
Reputation: 2133
try this in the controller:
user.getWallets().remove(wallet);
walletService.delete(wallet);
userService.save(user);
Upvotes: 1
Reputation: 2230
The problem raise when you are trying to remove each children by itself while the parent (i.e. parent) still has a reference to it and since the reference has a cascade All set on it (including persist and merge), it causes child (i.e. purchase) to be revived in the context by undoing the remove.
source : JPA / Hibernate removing "child" entities
Get rid of removing children by making a stream on parent and change wallet class to have cascade remove type on purchases relationship :
@OneToMany(mappedBy = "wallet",
cascade = CascadeType.REMOVE, // <--- here should be changed
orphanRemoval = true, fetch = FetchType.LAZY)
@JsonIgnore
private Set<Purchase> purchases = new HashSet<>();
Then you just need to call walletRepository.delete(wallet);
to delete parent and children altogether.
Upvotes: 0
Reputation: 98
Could this be possible solution: Hibernate configuration -> orphanRemoval = true
will delete wallets only in case User entity is deleted?
Upvotes: 0
Reputation: 7622
I can think of 2 Cases here
You have added mappedBy
in Wallet
Class so Purchase
is owner entity and you need to delete from Purchases
try changing delete Wallet method like this
@Transactional
public void delete(Wallet wallet) {
if (LOG.isDebugEnabled()) {
LOG.debug("deleting Wallet [ " + wallet + " ]");
}
wallet.getPurchases().removeAll();
walletRepository.delete(wallet);
}
Ideally you have configured CascadeType.ALL
in Wallet
so doing
walletRepository.delete(wallet);
should remove Set<Purchase>
too.
Upvotes: 1