【问题标题】:JPA and Hibernate Cascade DELETE OneToMany does not workJPA 和 Hibernate Cascade DELETE OneToMany 不起作用
【发布时间】:2017-03-10 06:33:48
【问题描述】:

我一直在阅读一篇又一篇文章,一篇又一篇文章试图在最新的 Spring Boot 版本中使用 JPA/Hibernate 进行级联删除。我读过你必须使用 Hibernate 特定的级联,我读过你不需要。我已经读到它们只是不起作用,但它似乎是一个混合包。我尝试过的一切都不起作用。这种关系是双向的。

不起作用:

@Entity
public class Brand {

    @OneToMany(mappedBy = "brand", orphanRemoval = true, fetch = FetchType.LAZY)
    @Cascade({CascadeType.DELETE})
    @JsonManagedReference("brand-tax-rate")
    private List<TaxRate> taxRates;

}

不起作用:

@Entity
public class Brand {

    @OneToMany(mappedBy = "brand", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonManagedReference("brand-tax-rate")
    private List<TaxRate> taxRates;

}

除了在删除Brand 之前删除TaxRates 之外,还有什么工作吗?

我的测试是这样的:

@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);
    }
}

参考错误:

原因:org.h2.jdbc.JdbcSQLException:参照完整性 违反约束:“FKC4BCIKI2WSPO6WVGPO3XLA2Y9:PUBLIC.TAX_RATE FOREIGN KEY(BRAND_ID) REFERENCES PUBLIC.BRAND(ID) (1)"; SQL 语句: 从 id=? 的品牌中删除[23503-192]

更新:修改了我的 brandService.deleteAll() 方法以执行以下操作:

@Override
public void deleteAll() {
    Iterable<Brand> iter = this.brandRepository.findAll();
    iter.forEach(brand -> this.brandRepository.delete(brand) );
}

还是不行。

更新 2:它似乎只是通过测试出现的问题。 Cascade 似乎可以在应用运行时正常工作。

【问题讨论】:

  • brandService.deleteAll() 是什么样的?可以加代码吗?
  • brandRepository.deleteAll() 就是它所做的一切。我的存储库都是 CrudRepository 接口。
  • 结果如何。例外?如果是这样,请打开 SQL 日志记录以查看发生了什么。
  • JPA 没有 cascade = CascadeType.DELETE。我认为这是一个错字?标准 JPA 注释应该可以工作,因此您需要发布异常(如果有)。
  • 修改错字并添加堆栈跟踪。我知道它应该有效,我是说它没有。

标签: spring hibernate jpa spring-boot cascade


【解决方案1】:

我想你想看看@OnDelete 注释,它会生成一个 DDL 级级联删除。

如果您使用自动模式生成(例如 hbm2ddl),这会将 ON DELETE CASCADE 添加到 FOREIGN KEY 定义中。但是,使用Flyway is almost always a better choice 比使用hbm2ddl。

您的映射变为:

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

【讨论】:

  • 只是给读者的一个提示。如果我理解这一点,如果您使用 Hibernate 生成架构,这将在 SQL 表中的外键中添加 ON DELETE CASCADE。
  • 没错。 OP 想要清除测试之间的数据库模式。看看这个blog post。
  • 但答案不仅适用于提问的人。我们应该尝试为任何到达这里的人解释答案。
  • 谢谢。一有机会,我会试一试。
  • 这适用于 Hibernate,但可以为一般 JPA 做吗?
猜你喜欢
  • 2016-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多