2013-04-08 28 views
2

我有Address一個新鮮/非託管實例和管理作爲參數傳入以下方法的Member例如使用彈簧數據JPA:爲了更新實體(而不復制字段逐個)

@Override 
public void modifyAddress(Member member, Address address){ 
    long addressId = member.getAddress().getId();//retrieving id of managed address instance 
    address.setId(addressId);//setting id on unmanaged instance 
    updateAddress(address);//updating unmanaged instance 
} 

updateAddress方法的實現:

public Address PreferencesServiceImpl.updateAddress(Address address) { 
     return addressRepository.save(address); 
} 

正如你所看到的,我想更新地址和JPA b但下列情況除外ALKS:

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.$Proxy122.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.$Proxy121.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.$Proxy137.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:81) 
    com.bignibou.service.PreferencesServiceImpl.updateAddress(PreferencesServiceImpl.java:1) 

我不知道如何從非託管實例(address參數)的管理實例不厭其煩地複製領域得到這個權利除了(member.getAddress())逐一和更新管理實例

任何人都可以請指教?

編輯1

我已經設置了能重現問題示例應用程序。任何希望使用樣本GitHub的應用需求來重現問題:

  • Maven的
  • 的Git
  • JDK 6
  • MySQL的

他們可以按照以下步驟重現該問題:

  • git clone [email protected]:balteo/StaleObjectStateException.git
  • 在MySQL中創建一個名爲數據庫架構SOSE create database sose;
  • mvn test
  • ,瞧:BOOM

任何人都可以請向我解釋爲什麼這個異常發生在我的情況,以及如何更新地址實例沒有得到這個異常?

回答

2

long addressId = member.getAddress()。getId();

已經有保存在數據庫中會員的實例 - 它已經保存在數據庫中的地址實例的外鍵關係。 FK關係在對象模型中通過member.getAddress()導航。 Address實例的主鍵是member.getAddress()。getId()

address.setId

您已經創建地址另一新實例的對象模型,並手動設置爲相同主鍵爲預先存在的(addressId)實例保存在數據庫中,然後嘗試保存新的實體。

這是違法的。如果您希望更新預先存在的實體,您必須加載它,啓動事務,修改屬性並提交事務。如果你想添加一個新實體,你必須開始一個事務,創建一個新實例,填充它的屬性(包括一個新的唯一主鍵),保存它並提交事務。

您可以通過使用JPA @Id註釋和PK屬性上的@GeneratedValue註釋來自動填充新的唯一PK值(另外還可以在代碼中的其他位置添加@ SequenceGenerator/@ TableGenerator註釋中的任意一個註釋 - 通常位於類中) 。這裏有兩個教程:http://www.oracle.com/technetwork/middleware/ias/id-generation-083058.htmlhttp://www.objectdb.com/java/jpa/entity/generated

希望這有助於! :^)

相關問題