删除oneToOne后,Spring Hibernate TransientPropertyValueException

时间:2018-05-25 14:21:44

标签: java spring hibernate spring-data-jpa

我需要一些帮助来解决Hibernate TransientPropertyValueException

我们有两个实体:

@Entity
@Table(name = "TABLE_A")
public class TableA {
    @Id
    @Column(name = "EXT_ID", nullable = false, unique = true, updatable = false)
    private String extId;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "EXT_ID", updatable = false, insertable = false)
    private TableB tableB;

   (...)
}

@Entity
@Table(name = "TABLE_B")
public class TableB  {
    @Id
    @Column(name = "EXT_ID", nullable = false)
    private String extId;

    @OneToOne
    @JoinColumn(name = "EXT_ID")
    private TableA tableA;
}

现在我们使用TableA删除CrudRepository

@Override
@Transactional
public boolean cancel(String extId) {
    Optional<TableA> maybeTableA = repository.findTableA(extId, DELETE_STATUS_SET);

    return maybeTableA.map(tableA -> {
        repository.delete(tableA);
        return true;
    }).orElse(false);
}

到目前为止一切正常。但是现在每当我想查询引用TableB TableA的{​​{1}}时,我都会TransientPropertyValueException 很明显,在提交交易之前,TableBTableA的引用尚未删除。

有没有一种很好的方法来解决这个问题? 我在删除后直接尝试了sessionFactory.getCurrentSession().flush(),但它也无法正常工作

唯一有效的选择是手动删除事务中的引用:

tableB.setTableA(null);
tableBRepository.save(tableB);

但这有点像hacky imo

3 个答案:

答案 0 :(得分:1)

当谈到JPA关系时,你有责任更新关系的双方。

此处,cancel方法应更新tableAtableB。否则,你得到的是tableB中的EXT_ ID值,它在tableA中没有对应关系。然后,在检索tableB实体时,Hibernate需要一个相应的tableA实体,它不再存在并抛出错误。

如果tableB实体在删除其对应的tableA实体时应保留,则表{B} extId需要可以为空。

还有一件事:与TableA一样,TableB必须将extIdtableA声明为updatable = false, insertable = false。 Hibernate不喜欢同一个数据库字段上的两个可写属性。

@Override
@Transactional
public boolean cancel(String extId) {
    Optional<TableA> maybeTableA = repository.findTableA(extId, DELETE_STATUS_SET);

    return maybeTableA.map(tableA -> {

        // update tableB
        TableB tableB = tableA.getTableB();
        tableB.setExtId(null);
        tableB.setTableA(null);
        tableBRepository.save(tableB);

        // and update tableA
        repository.delete(tableA);
        return true;
    }).orElse(false);
}

答案 1 :(得分:0)

答案 2 :(得分:0)

你看过级联吗?我自己会选择你的hacky方法,因为我发现它更容易阅读并遵循代码。

JPA @ManyToOne with CascadeType.ALL