JPA/Hibernate 同一实体的多个表示
JPA/Hibernate Multiple representations of the same entity
我的实体:
@Entity
public class Document {
@Id
protected String id; //It string in purpose
@OneToOne(cascade = ALL)
@JoinColumn(name = "DOCUMENT_DETAILS")
private DocumentDetails details;
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "documentDiscr")
@EqualsAndHashCode
public abstract class DocumentDetails {
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private Money total;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "SELLER_ID")
private Company seller;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "BUYER_ID")
private Company buyer;
}
@Entity
public class Company {
@Id
protected String id;
private String name;
private String phoneNumber;
private String email;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id")
private Address address;
}
@Entity
@EqualsAndHashCode
public class Address {
@Id
@GeneratedValue(strategy= GenerationType.SEQUENCE)
private Long id;
private String country;
private String city;
private String postalCode;
private String streetName;
private String streetNumber;
private String apartmentNumber;
}
@Path("path")
@Transactional
public class MyResource {
@Inject
MyRepo myRepo;
@PUT
public Document updateDoc(Document document){
myRepo.update(document);
}
}
public class Repo<T extends MyClass> implements MyRepo<T> {
@PersistenceContext
protected EntityManager entityManager;
public T create(T t) {
t.generateId();
this.entityManager.persist(t);
return t;
}
public T update(T entity) {
return entityManager.merge(entity);
}
}
当我调用 entityManage.update(documentEntity) 并将同一公司添加为供应商和买方时,我看到
'Multiple representations of the same entity'
。
我读了 this 但没有任何帮助。当我删除 CascadeType.All 我得到
'detached entity passed to persist: my.pckg.Address'
我也尝试删除 CascadeType.Merge 但错误是一样的。
我可以做什么?我的错误在哪里?
更新
首先我在DocumentDetails
中将@ManyToOne(Cascade.All)
更改为@ManyToOne()
其次,我在 DocumentDetails
中将 @ManyToOne(Cascade.All)
更改为 @ManyToOne(Cascade.Merge)
。
第三个我在DocumentDetails
中将@ManyToOne(Cascade.All)
更改为@ManyToOne(all types except all and merge)
。
我也试过 Address
class
好的 - 在 Piotr Gwiazda 的提示下我解决了它。
简单而天真的解决方案是添加:
if(seller != null && buyer != null){
if(seller.equals(buyer)){
document.getDetails.setSeller(document.getDetails().getBuyer());
}
}
(更好的答案是 SpringData)
在 update()
之前。这种情况之所以存在,是因为当两个不同的对象相等但它们引用不同时,hibernate 无法将它们作为同一对象处理。
This happens when you overwrite the object with same value but with
different hashcode, If i am having employee class and employee is
having the address
class and if I will save the same employee with same address value but with different hashcode then I will get this issue, If I will
clone address and set in employee then Hibernate will get confused and
not able to save data
@Entity
@Getter
@Setter
class Person implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique = true, nullable = false)
private Long id;
@OneToMany(cascade= CascadeType.ALL)
private Set<Address> Addresses = new HashSet<>();
protected Person(){}
}
@Entity
@Getter
@Setter
class Address implements Serializable {
@EmbeddedId
private AddressId addressId;
private State state;
protected Address(){}
}
@Embeddable
@Getter
@Setter
public class AddressId implements Serializable {
@Column(name = "person_id")
private Long personId;
@Column(name = "postcode")
private String postcode;
}
Solution For this
AddressId addressId = new AddressId();
addressId.setPersonId(personId);
addressId.setPostcode("4000"); //person already has an address with this postcode
Address address = null;
for (Address a : person.getAddresses()) {
if (a.getAddressId().equals(addressId)) {
address = a;
break;
}
}
if (address == null) {
address = new Address();
address.setAddressId(addressId);
address.setState(State.ABC); //but I want to change the state from QLD to TAS
person.getAddresses().add(address);
}
else {
address.setState(State.TAS);
}
person = personRepo.save(person);
我的实体:
@Entity
public class Document {
@Id
protected String id; //It string in purpose
@OneToOne(cascade = ALL)
@JoinColumn(name = "DOCUMENT_DETAILS")
private DocumentDetails details;
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "documentDiscr")
@EqualsAndHashCode
public abstract class DocumentDetails {
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private Money total;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "SELLER_ID")
private Company seller;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "BUYER_ID")
private Company buyer;
}
@Entity
public class Company {
@Id
protected String id;
private String name;
private String phoneNumber;
private String email;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id")
private Address address;
}
@Entity
@EqualsAndHashCode
public class Address {
@Id
@GeneratedValue(strategy= GenerationType.SEQUENCE)
private Long id;
private String country;
private String city;
private String postalCode;
private String streetName;
private String streetNumber;
private String apartmentNumber;
}
@Path("path")
@Transactional
public class MyResource {
@Inject
MyRepo myRepo;
@PUT
public Document updateDoc(Document document){
myRepo.update(document);
}
}
public class Repo<T extends MyClass> implements MyRepo<T> {
@PersistenceContext
protected EntityManager entityManager;
public T create(T t) {
t.generateId();
this.entityManager.persist(t);
return t;
}
public T update(T entity) {
return entityManager.merge(entity);
}
}
当我调用 entityManage.update(documentEntity) 并将同一公司添加为供应商和买方时,我看到
'Multiple representations of the same entity'
。
我读了 this 但没有任何帮助。当我删除 CascadeType.All 我得到
'detached entity passed to persist: my.pckg.Address'
我也尝试删除 CascadeType.Merge 但错误是一样的。 我可以做什么?我的错误在哪里?
更新
首先我在DocumentDetails
@ManyToOne(Cascade.All)
更改为@ManyToOne()
其次,我在 DocumentDetails
中将 @ManyToOne(Cascade.All)
更改为 @ManyToOne(Cascade.Merge)
。
第三个我在DocumentDetails
中将@ManyToOne(Cascade.All)
更改为@ManyToOne(all types except all and merge)
。
我也试过 Address
class
好的 - 在 Piotr Gwiazda 的提示下我解决了它。
简单而天真的解决方案是添加:
if(seller != null && buyer != null){
if(seller.equals(buyer)){
document.getDetails.setSeller(document.getDetails().getBuyer());
}
}
(更好的答案是 SpringData)
在 update()
之前。这种情况之所以存在,是因为当两个不同的对象相等但它们引用不同时,hibernate 无法将它们作为同一对象处理。
This happens when you overwrite the object with same value but with different hashcode, If i am having employee class and employee is having the address class and if I will save the same employee with same address value but with different hashcode then I will get this issue, If I will clone address and set in employee then Hibernate will get confused and not able to save data
@Entity
@Getter
@Setter
class Person implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique = true, nullable = false)
private Long id;
@OneToMany(cascade= CascadeType.ALL)
private Set<Address> Addresses = new HashSet<>();
protected Person(){}
}
@Entity
@Getter
@Setter
class Address implements Serializable {
@EmbeddedId
private AddressId addressId;
private State state;
protected Address(){}
}
@Embeddable
@Getter
@Setter
public class AddressId implements Serializable {
@Column(name = "person_id")
private Long personId;
@Column(name = "postcode")
private String postcode;
}
Solution For this
AddressId addressId = new AddressId();
addressId.setPersonId(personId);
addressId.setPostcode("4000"); //person already has an address with this postcode
Address address = null;
for (Address a : person.getAddresses()) {
if (a.getAddressId().equals(addressId)) {
address = a;
break;
}
}
if (address == null) {
address = new Address();
address.setAddressId(addressId);
address.setState(State.ABC); //but I want to change the state from QLD to TAS
person.getAddresses().add(address);
}
else {
address.setState(State.TAS);
}
person = personRepo.save(person);