【问题标题】:Annotation mapping vs. XML mapping and deleting an entity注释映射与 XML 映射和删除实体
【发布时间】:2015-08-16 21:41:51
【问题描述】:

我正在将项目从 XML 映射迁移到基于纯 JPA 注释的映射,并且在尝试删除(删除)实体及其子项时遇到问题。它适用于 XML 映射,不适用于注释映射。

XML 映射如下所示:

<set name="evaluations" order-by="evalDate desc" table="Evaluation" lazy="true" inverse="true" cascade="delete">
    <key column="requestId" />
    <one-to-many class="org.stuff.model.Evaluation" />
</set>

注解映射,据我所知是这样的:

@OneToMany(orphanRemoval=true)
@JoinColumn(name = "requestId")
@OrderBy("evalDate DESC")
private Set<Evaluation> evaluations = new TreeSet<>();

这是一种单向关系。

删除实体的JPA代码是:

ServiceRequest sr = em.getReference(ServiceRequest.class, id);
em.remove(sr);

上面的EvaluationServiceRequest 的子对象。 Hibernate 4.3.7 是我正在使用的 JPA Impl,在 WildFly 8.2 上运行。

Hibernate 设置为排除其 SQL,使用 annotation 映射执行删除 Hibernate 会生成一个查询来查找实体引用,然后当调用 remove 时,它会生成一个更新尝试将Evaluation FK 中的子记录更新回 ServiceRequest 为空:

Hibernate: update Evaluation set requestId=null where requestId=?

因为not nullrequestId 的约束,所以这会爆炸。

如果我使用 XML 映射(参见上面的 sn-p)执行相同的操作,它就可以正常工作。所有子实体与父实体一起被删除。如果从不尝试更新任何东西,Hibernate 只会产生selectsdeletes

这感觉就像我的注释映射错误,但我不知道哪里出错了。请帮忙。

【问题讨论】:

    标签: java hibernate jpa wildfly-8


    【解决方案1】:

    您的 xml 配置实际上说您的 ServiceRequest 和 Set 之间的关系是双向的,因为 inverse = "true"。

    但是您的 JPA 注释是单向的。所以这应该工作(在OP的评论后编辑)

    @OneToMany(orphanRemoval=true,mappedBy="requestId")
    @OrderBy("evalDate DESC")
    private Set<Evaluation> evaluations = new TreeSet<>();
    

    这里mappedBy="requestId"告诉 Hibernate 这是关系的所有者方。所以它会发布声明删除评估。

    【讨论】:

    • 谢谢,这是正确的方向,稍作修改。在 Hibernate 中进行此映射更改后,抱怨同时使用 mappedBy@JoinColumn,但以下情况除外:Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: hci.hrccadmin.model.ServiceRequest.evaluations。然后在删除@JoinColumn 之后,它不喜欢mappedBy="ServiceRequest",所以我将其更改为mappedBy="requestId",因为这是将ServiceRequest 链接到评估的FK,这似乎有效。看起来有点奇怪,但我想这是有道理的。
    • 感谢@sarahthebutterfly 的回答。它真的又动起来了。
    【解决方案2】:

    感谢@troy 的指导。单独添加级联不起作用,但添加insertable=flase, updateable=false 可以。所以注解映射现在看起来像这样:

    @OneToMany(cascade=CascadeType.REMOVE)
    @JoinColumn(name = "requestId", insertable=false, updatable=false)
    @OrderBy("evalDate DESC")
    private Set<Evaluation> evaluations = new TreeSet<>();
    

    我不确定为什么会这样,所以如果有人能解释一下,我将非常感激。

    我是间接到达这里的。首先,我在这个映射中添加了一个nullable-false,当我部署它时,Hibernate 抱怨它并告诉我需要在Evaluation 实体上将insert=false update=false 添加到requestId。那种工作。我可以随意删除,但无法保存或插入评价。我有点预料到会发生这种情况。所以我只是厌倦了这个解决方案,它奏效了。

    【讨论】:

    • 我认为您的 xml 配置实际上是双向关系,因为您设置了 inverse = "true"。使用 JPA 注释,现在您已经设置了“insertable=false, updatable=false”,它创建了一个虚拟逆 =“true”。这就是它起作用的原因。哦,我想如果你把@OneToMany(orphanRemoval=true) 放回去,它也会起作用。
    • JPA 有它自己的 inverse = true 注释,见这里stackoverflow.com/questions/4865285/…。 @OneToMany(mappedBy="ServiceRequest")
    • 是的,回复orphanlRemoval=true 也可以,但并不孤单。 insertable=false, updatable=false 仍然需要在那里。谢谢。
    • 在这个过程中,我也了解到orphanRemoval=true包含一个隐含的CascadeType.REMOVE,所以在指定orphanRemoval=true的时候不需要指定cascade=CascadeType/REMOVE
    【解决方案3】:

    我认为您需要指定级联注释。当心this issue though

    【讨论】:

      猜你喜欢
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-24
      • 2011-07-13
      • 2010-10-06
      • 2016-02-14
      相关资源
      最近更新 更多