CascadeType.MERGE-避免IllegalStateException:合并同一实体的多个表示形式

时间:2018-06-22 09:06:39

标签: java hibernate jpa cascade illegalstateexception

说我有两个实体,BookPersonBook包含两个Person字段,一个字段用于“作者”,一个字段用于“编辑”。关系在@ManyToOne端是Book

@EqualsAndHashCode
@Entity
public class Book {
    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Person author;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Person editor;
    ...
}

@EqualsAndHashCode
@Entity
public class Person {
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Book authored;

    @OneToMany(mappedBy = "editor", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Book edited;
    ...
}

如果我收到一个分离的Book的XML表示形式,其中包含一个分离的Person作为子实体,那么我可以使用弹簧JpaRepository保留该书,并且该人也是坚持。

但是,如果一个Person既创作又编辑同一Book

Book: The Very Hungry Caterpillar
    Author: Eric Carle
    Editor: Eric Carle

我会得到例外:

java.lang.IllegalStateException: Multiple representations of the same entity [my.project.Person#1] are being merged. Detached: [my.project.Person@4729256a]; Detached: [my.project.Person@56ed25db]

我可以通过从关系中删除CascadeType.PERSIST来“解决”这一问题。但是,这将导致EntityNotFoundException

EntityNotFoundException: Unable to find my.project.Person with id 759.

这可以通过将JPA注释参数CascadeType.MERGE更改为Hibernate注释来进一步实现:

@OneToMany(fetch=FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE})
private Person author;
...

我相信这将使Hibernate基于其持久性状态有效地选择是合并还是持久化子实体。但是,这不会导致重复的Person对象被保留。然后,我将得到一个JpaObjectRetrievalFailureException:

JpaObjectRetrievalFailureException: Unable to find my.project.Person 759.

这可以通过添加另一个注释来解决:

@OneToMany(fetch=FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE})
@NotFound(action = NotFoundAction.IGNORE)
private Person author;
...

但这不能解决问题,因为Person对象仍需要手动保存。

是否可以使用JPA持久保存一个独立的子实体的两种表示形式?

编辑:已实现hashCode()和equals(),并且两个Person对象的值均相等。

0 个答案:

没有答案