【问题标题】:CascadeType.Persist not working with primary key generator type table in JPACascadeType.Persist 不使用 JPA 中的主键生成器类型表
【发布时间】:2011-11-21 09:44:27
【问题描述】:

在我的 JPA/独立项目中使用 CascadeType.Persist 时遇到问题。我有一个父实体,它有一个子实体列表,应该与父实体一起保留,父实体的主键是使用表(GeneratorType.TABLE)生成的,我使用一个表来生成主键。

在父母中我有:

    @OneToMany(mappedBy="parent",fetch=FetchType.EAGER,cascade= {CascadeType.PERSIST,CascadeType.DETACH})
    List<Child> children;
    //Getter and Setter

    @PostPersist
    public void setParentID(){
    System.out.println("Inside Postpersist");
    for(Child ch : this.children){
        ch.setParent(this);
                    System.out.println(ch.getParent().getParentId());
    }
}

在儿童中:

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "Parent_ID")
    private Parent parent;

在数据库中,我为 Parent 表的 Parent_ID 列设置了一个非空值。当我坚持一个父实体并且它已经设置了子实体列表时,它会抛出一个

    ConstraintViolationException: Cannot insert the value NULL into column 'Parent_ID', table 'jpaTest.Child', column does not allow nulls.

因为父实体对于所有子实体都是空的,尽管它会将 ParentId 设置为使用@PostPersist 注释的方法中的每个子实体

但是,当我将主键生成策略从 TABLE 类型更改为 AUTO 时,不会发生这种情况,并且会发生父母和孩子的持久性。这是如何以及为什么会发生的。

提供者是 Hibernate。我的数据库服务器是 mssql。

【问题讨论】:

    标签: jpa


    【解决方案1】:

    这种方法看起来有点弱,因为规范并没有为修改生命周期回调中的其他实体提供太多支持:

    一般来说,可移植应用程序的生命周期方法不应该 调用 EntityManager 或 Query 操作,访问其他实体 实例,或修改同一持久性内的关系 上下文。

    此外,您无法保证 children@PostPersist 在父级中的级联顺序:

    是否回调方法取决于实现 在生命周期事件级联之前或之后调用 相关实体。应用程序不应依赖此顺序。

    【讨论】:

    • 嘿,谢谢。在那种情况下,我不能依靠级联效应来坚持孩子。好吧,它会持久化,但 Child 表中的 Parent 的 ID 设置为 null,因为 ID 是在插入操作时生成的,而不是之前设置的。因此,我选择了事件侦听器回调方法,在级联效果发生之前将 ParentId 设置为子实体。无论如何,谢谢,我会将孩子坚持在业务代码中,而不是在父母的后坚持。
    【解决方案2】:

    是的,它在没有省略级联持久性的情况下工作。我所要做的就是将 Parent 对象设置为 Child,同时将 Child 实体添加到 Parent 中的子列表中,因为它是双向关系。

    在父级中:

        public void setParentToChild(Child ch){
        if(this.getChildren()==null){
            this.children = new ArrayList<Children>();
        }
                this.children.add(cb);
                //this is what worked. Also set the Parent to Child
        cb.setCustomer(this);
    }
    

    现在在创建新的 Parent 和 Child 时,我调用此方法将 child 添加到 parent。其余的 JPA 无需在业务代码中设置任何内容。谢谢你们。

    【讨论】:

    • 我遇到了同样的问题(子表中的 parentId 为空)。我现在用了@PostPersist,但是大家都说这不是个好主意。你能解释一下你是如何解决这个问题的吗?我好像没什么好主意,有点绝望。
    【解决方案3】:

    我的猜测是,在@PostPersist 方法中,子字段的父字段必须在持久化父字段之前初始化,而不是之后,该方法可能在级联完成后调用。

    【讨论】:

    • 感谢 JB 的回复。好吧,通过 Parent 实体类中 PostPersist 事件的结果,很明显,在持久化子实体之前,已为其设置了 ParentId。 It does not throw any Exception as such when the Primary Key generation strategy opted is AUTO.这就是我感到困惑的地方。请帮忙。
    • 正如我所说,尝试在您的业务代码中设置 child 的 parenbt 字段,在调用 persist 之前,而不是在 PostPersist 回调中。 @Mikko Maunu 说得对:您不能依赖排序,主键生成可能会对其产生影响。只需按照规范的要求进行操作:在持久化之前初始化关联的拥有方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多