【发布时间】:2017-02-26 00:17:11
【问题描述】:
架构定义
CREATE TABLE person (
id bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
) ENGINE=InnoDB
CREATE TABLE address (
person_id bigint(20) not null,
postcode varchar(255) not null,
state int(11),
constraint `PRIMARY` primary key (address_id, postcode),
constraint FK_dq8j32idfdnwny42fiovenqwo foreign key (person_id) references person (id)
) ENGINE=InnoDB
即一个人应该能够拥有多个地址,只要邮政编码不同。
类
@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;
}
从某种意义上说,只要这两个地址具有不同的邮政编码,它就允许向同一个人添加多个地址。
Person person = personRepo.findOne(personId);
AddressId addressId = new AddressId();
addressId.setPersonId(personId);
addressId.setPostcode("4000");
Address address = new Address();
address.setAddressId(addressId);
address.setState(State.QLD);
person.getAddresses().add(address);
AddressId addressId2 = new AddressId();
addressId2.setPersonId(personId);
addressId2.setPostcode("4001");
Address address2 = new Address();
address2.setAddressId(addressId2);
address.setState(State.VIC);
person.getAddresses().add(address2);
person = personRepo.save(person);
但是当尝试更新其中一个时(例如更改状态)
Person person = personRepo.findOne(personId);
AddressId addressId = new AddressId();
addressId.setPersonId(personId);
addressId.setPostcode("4000"); //person already has an address with this postcode
Address address = new Address();
address.setAddressId(addressId);
address.setState(State.TAS); //but I want to change the state from QLD to TAS
person.getAddresses().add(address);
person = personRepo.save(person);
生成以下内容。我认为下面的基本意思是“嘿,你正在尝试添加一个带有 person_id 和已经存在的邮政编码的地址,我不在乎状态是否不同,你不能这样做”。如何让它发挥作用?
引起:java.lang.IllegalStateException:多种表示 正在合并同一实体 [Address#AddressId@5047ce78]。 托管:[地址@5c220478];分离:[地址@79804699]在 org.hibernate.event.internal.EntityCopyNotAllowedObserver.entityCopyDetected(EntityCopyNotAllowedObserver.java:51) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.MergeContext.put(MergeContext.java:262) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:216) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:192) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:886) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.internal.SessionImpl.merge(SessionImpl.java:868) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:277) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:319) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:296) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:474) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:218) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:192) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:876) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.internal.SessionImpl.merge(SessionImpl.java:858) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.internal.SessionImpl.merge(SessionImpl.java:863) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 在 org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1196) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final] 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) ~[na:1.8.0_102] 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102] 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102] 在 java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
但是,如果我这样做了
Person person = personRepo.findOne(personId);
new ArrayList<>(person.getAddresses()).get(0).setState(State.QLD); //change state of existing address row
person = personRepo.save(person);
我没有得到例外。我认为 Hibernate 检测到在这种情况下,正在更新现有行,而如果尝试添加另一个具有相同 personId 和邮政编码的地址,它会尝试执行 INSERT 并失败。有没有办法让 Hibernate 在日期情况下也进行更新?
【问题讨论】:
-
将地址添加到集合中的代码在哪里?你是否正确实现了equals和hashCode?span>
-
@aviad 添加了生成异常的代码。至于equals和hashcode,它们没有被任何类覆盖,我不确定什么是“正确”,因为对此有很多不同的意见。