说我有两个实体,Book
和Person
。 Book
包含两个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
对象的值均相等。