JPA and Hibernate Cascade DELETE OneToMany does not work

cascade, hibernate, jpa, spring, spring-boot

Solution

I think you want to take a look at `@OnDelete` annotation which generates a DDL-level cascade delete.

This will add an `ON DELETE CASCADE` to the `FOREIGN KEY` definition if you're using the automatic schema generation (e.g. hbm2ddl). However, using Flyway is almost always a better choice than hbm2ddl.

Your mapping becomes:

@OneToMany(mappedBy = "brand", orphanRemoval = true, fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonManagedReference("brand-tax-rate")
private List<TaxRate> taxRates;

Problem

I've been reading post after post and article after article trying to get cascade deletes to work with JPA/Hibernate in the latest Spring Boot version. I've read that You have to use Hibernate specific cascades and I've read that you don't. I've read that they just don't work but it seems to be a mixed bag. Everything I've tried doesn't work. The relationship is bi-directional. Doesn't Work: ``` @Entity public class Brand { @OneToMany(mappedBy = "brand", orphanRemoval = true, fetch = FetchType.LAZY) @Cascade({CascadeType.DELETE}) @JsonManagedReference("brand-tax-rate") private List<TaxRate> taxRates; } ``` Doesn't Work: ``` @Entity public class Brand { @OneToMany(mappedBy = "brand", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY) @JsonManagedReference("brand-tax-rate") private List<TaxRate> taxRates; } ``` Does anything work other than deleting the `TaxRates` prior to deleting the `Brand` ? My test looks like this: ``` @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = {Application.class, SpringSecurityConfig.class}) @ActiveProfiles("test") @Transactional public class CascadeTests { @Autowired private BrandService brandService; @Autowired private TaxRateLoaderService taxRateLoaderService; @Autowired private TaxRateService taxRateService; @Autowired private TaxRateRepository taxRateRepository; @Autowired private BrandRepository brandRepository; @Test public void testCascadeWorks() throws Exception { taxRateLoaderService.loadData(null, 10); // if I uncomment this then I'm good // but shouldn't have to if cascade works //taxRateService.deleteAll(); brandService.deleteAll(); List<TaxRate> rates = Lists.newArrayList(taxRateRepository.findAll()); List<Brand> brands = Lists.newArrayList(brandRepository.findAll()); Assert.assertEquals(rates.size(), 0); Assert.assertEquals(brands.size(), 0); } } ``` Error for reference: Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FKC4BCIKI2WSPO6WVGPO3XLA2Y9: PUBLIC.TAX_RATE FOREIGN KEY(BRAND_ID) REFERENCES PUBLIC.BRAND(ID) (1)"; SQL statement: delete from brand where id=? [23503-192] UPDATE: modified my `brandService.deleteAll()` method to do the following: ``` @Override public void deleteAll() { Iterable<Brand> iter = this.brandRepository.findAll(); iter.forEach(brand -> this.brandRepository.delete(brand) ); } ``` Still does not work. UPDATE 2: It only appears to be a problem via tests. Cascade seems to work okay with the app running.

Original source