我有一个与实体Member
有如下@OneToOne
关系的实体:Address
在Member
实体中:
@OneToOne(cascade=CascadeType.ALL)
private Address address;
Address
实体:
@RooJpaEntity
public class Address {
private String formattedAddress;
private double latitude;
private double longitude;
}
我遇到的问题是每次我更新会员的地址如下:
public void modifyAddress(Member member, Address address){
member.setAddress(address);
memberRepository.save(member);
}
...而不是更新地址表中的行,而是在地址表中插入一个新行并更新成员表中的 FK,如下面的 sql 所示:
生成的 SQL:
Hibernate:
/* insert com.bignibou.domain.Address
*/ insert
into
address
(formatted_address, latitude, longitude, version)
values
(?, ?, ?, ?)
Hibernate:
/* update
com.bignibou.domain.Member */ update
member
set
address=?,
version=?
where
id=?
and version=?
我不知道如何解决这个问题(我现在不想在成员表中内联地址数据)。我希望我的应用程序更新地址表,而不是在该表中插入新行。
有人可以请教吗?
编辑1:
我修改了我的实体如下:
这是完整的Address
实体:
@RooJpaEntity
public class Address {
private String formattedAddress;
private double latitude;
private double longitude;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "address")
private Member member;
}
这是Member
实体中的相关属性:
@OneToOne
private Address address;
我的方法:
@Override
public void modifyAddress(Member member, Address address){
address.setMember(member);
updateAddress(address);
}
我的应用程序的行为没有改变......
编辑 2:如果我如下修改应用程序,我会收到 StaleObjectStateException。
@Override
public void modifyAddress(Member member, Address address){
long addressId = member.getAddress().getId();
address.setId(addressId);
address.setMember(member);
updateAddress(address);
}
地址:
@RooJpaEntity
public class Address {
private String formattedAddress;
private double latitude;
private double longitude;
@OneToOne
private Member member;
}
在会员中:
@OneToOne
private Address address;
陈旧对象状态异常:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.Address#5]
org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:303)
org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903)
org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887)
org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891)
org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:879)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
com.sun.proxy.$Proxy49.merge(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
com.sun.proxy.$Proxy48.merge(Unknown Source)
org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:353)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
com.sun.proxy.$Proxy65.save(Unknown Source)
com.bignibou.service.PreferencesServiceImpl_Roo_Service.ajc$interMethod$com_bignibou_service_PreferencesServiceImpl_Roo_Service$com_bignibou_service_PreferencesServiceImpl$updateAddress(PreferencesServiceImpl_Roo_Service.aj:53)
com.bignibou.service.PreferencesServiceImpl.updateAddress(PreferencesServiceImpl.java:1)
com.bignibou.service.PreferencesServiceImpl_Roo_Service.ajc$interMethodDispatch1$com_bignibou_service_PreferencesServiceImpl_Roo_Service$com_bignibou_service_PreferencesServiceImpl$updateAddress(PreferencesServiceImpl_Roo_Service.aj)
com.bignibou.service.PreferencesServiceImpl.modifyAddress_aroundBody12(PreferencesServiceImpl.java:100)
com.bignibou.service.PreferencesServiceImpl$AjcClosure13.run(PreferencesServiceImpl.java:1)
org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59)
org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63)
com.bignibou.service.PreferencesServiceImpl.modifyAddress(PreferencesServiceImpl.java:93)
com.bignibou.controller.PreferenceController.modifyAddress(PreferenceController.java:168)
编辑 3:
地址的哈希码:
public int hashCode() {
return new HashCodeBuilder().append(formattedAddress).append(getId()).append(latitude).append(longitude).toHashCode();
}
地址等于(来自 ITD):
public boolean Address.equals(Object obj) {
if (!(obj instanceof Address)) {
return false;
}
if (this == obj) {
return true;
}
Address rhs = (Address) obj;
return new EqualsBuilder().append(formattedAddress, rhs.formattedAddress).append(id, rhs.id).append(latitude, rhs.latitude).append(longitude, rhs.longitude).append(member, rhs.member).isEquals();
}
地址实体的 ITD:
privileged aspect Address_Roo_Jpa_Entity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long Address.id;
@Version
@Column(name = "version")
private Integer Address.version;
public Long Address.getId() {
return this.id;
}
public void Address.setId(Long id) {
this.id = id;
}
public Integer Address.getVersion() {
return this.version;
}
public void Address.setVersion(Integer version) {
this.version = version;
}
}
顺便说一句,ITD 只是方面。
编辑 4:我在这里为您设置了一个示例应用程序:https ://github.com/balteo/sample-app-gab