JPA and Hibernate Cascade DELETE OneToMany does not work

吃可爱长大的小学妹 提交于 2019-12-11 00:16:06

问题


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.


回答1:


I think you want to take a look on @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;


来源:https://stackoverflow.com/questions/40286906/jpa-and-hibernate-cascade-delete-onetomany-does-not-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!