JpaRepository:在@PostPersist中使用存储库

时间:2015-02-13 10:43:28

标签: spring hibernate jpa spring-data h2

我有两个实体

class A {
    ...
    Integer totalSum;
    Set<B> b;
}

class B {
    ...
    Integer value;
    A container;
}

我希望a.totalSum是每个a.b.value的总和;

也许最好的解决方案是在db中查看,但我想在BRepository中监听更改并更新A记录。

我做:

@PostPersist
@PostUpdate
@PostRemove
private void recalculateSums(B b) {
    AutowireHelper.autowire(this, this.aRepository);
    AutowireHelper.autowire(this, this.bRepository);
    A a =   b.getContainer();
    a.setTotalSum(bRepository.sumByA(s));
    aRepository.save(s);
}

在BRepository:

@Query("select sum(b.value) from B b where b.container = :a")
Long sumByA(@Param("a") A a);

我有错误:org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.B(ID)"; SQL statement: insert into b (VALUE, CONTAINER_ID, ID) values (?, ?, ?)

我做错了什么?

如果我这样做

    a.setTotalSum(a.getTotalSum()+1);
    aRepository.save(s);

一切正常,但如果我这样做

    a.setTotalSum(a.getTotalSum()+1);
    aRepository.saveAndFlush(s);

我有同样的错误。

1 个答案:

答案 0 :(得分:2)

我可以看到为什么你可能想要这样做,但我认为这会产生大量关于数据完整性的潜在问题。

如果您希望A的总和不必加载并迭代所有B,那么您可以实现其他三个选项,所有这些选项都比您的提议更强大。

  1. 如您所述,创建一个视图。然后,您可以将实体说明,SummaryData映射到此视图,并将A从一对一映射到SummaryData,以便您可以执行a.getSummaryData()。getTotalSum();

  2. 或者,您可以使用Hibernate特定的@Formula注释,它将在加载实体时发出内联选择。

    @Formula(&#34;(从B b内部连接A a中选择sum(value),其中b.a_id = a.id和a.id = id private int totalSum;

  3. 最后,根据数据库的功能,您可以像创建任何其他字段一样创建虚拟列并映射属性。

  4. 1和3显然需要架构更改,但您的应用仍将符合JPA标准。 2不需要任何架构更改,但如果这很重要,则会违反严格的JPA规范。