在Hibernate / JPA中检查多个子约束违规

时间:2015-06-17 15:32:28

标签: spring hibernate jpa

TL; DR:是否可以在Hibernate中执行使用SavePoints回滚到特定状态的嵌套事务?

所以我试图将具有OneToMany映射的父实体持久化到子实体。这很好。

在此持久性期间,我想捕获并记录发生的所有约束违规。目前,具有约束违规的FIRST实体(子或父)抛出ConstraintViolationException并回滚事务。我希望仍然可以回滚事务,但不知何故会收集所有可能发生的约束违规。

以下是我的实体的简要概述:

ParentEntity.java

@Entity
@Table(name = "PARENT", schema = "SOMESCHEMA")
public class ParentEntity {

    private static final ID_COLUMN = "ID_COLUMN";

    @Id
    @Column(name = ID_COLUMN)
    private Long id;    

    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, orphanRemoval = true)
    @JoinColumn(name = ID_COLUMN, referencedColumnName = ID_COLUMN)
    private List<childEntity> children;
}

ChildEntity.java

@Entity
@Table(name = "CHILD", schema = "SOMESCHEMA")
public class ChildEntity {

    public ChildEntity(String input) {
        this.validationString = input;
    } 

    @Id
    @Column(name = ParentEntity.ID_COLUMN)
    private Long id;    

    @ManyToOne
    @JoinColumn(name = ParentEntity.ID_COLUMN, insertable = false, updatable = false)
    private ParentEntity parent;

    // The field under validation (should be less than 25 char's long)
    @Column(name = "VALIDATE_ME")
    private String validationString;
}

示例运行:

public void someMethod() {
    ParentEntity parent = new ParentEntity();

    parent.addChild(new Child("good input 1"));
    parent.addChild(new Child("bad input 1             break here"));
    parent.addChild(new Child("bad input 2             break here"));
    parent.addChild(new Child("good input 2"));

    dataAccessObject.persist(parent);
}

结果:

我看到事务已回滚,ConstraintViolationException仅包含第一个坏孩子的信息。

期望的结果:

我看到交易回滚,ConstraintViolationException显示所有坏孩子的信息,无论有多少孩子不好。 (另外,如果父母有违反约束,我仍然想检查子约束)

这可能吗?

2 个答案:

答案 0 :(得分:0)

ConstraintViolationException是一个HibernateException,并且所有Hibernate异常都不可恢复。因此,如果抛出一个异常,则不能依赖现有的会话状态来继续可靠地处理。

所以这是不可能或不推荐的。

答案 1 :(得分:0)

我找到了一种方法来完成我的最终结果,虽然这是通过我没想到的方式。

为了实现我的目标,我需要使用嵌套事务和SavePoints。在一天结束时,该实现仍然会在我的数据库中产生无效数据,因为在查找子项中的错误所需的时间内,其他一些子项可能已经被持久化并且我的数据库的使用者将是不知道由于一个或多个不良实体(父母或孩子),父母及其所有孩子即将被删除。

我的解决方案:

我实施了一个验证器来验证所有父母和孩子,然后再坚持下去。这种方法的缺点是我必须在我的实体字段上注释约束,但双重验证从来都不是坏事。

我原来问题的答案:

除非我实现自定义SavePoint功能以支持嵌套事务,否则我的Hibernate版本是不可能的。