2016-04-24 89 views
1

我有以下兩個實體:脫離實體:簡介

@Entity 
public class Profile implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private int id; 

    @OneToOne 
    @JoinColumn(nullable = false, name = "USERNAME_FK") 
    private RegisteredUser user; 

    ... 

@Entity 
public class RegisteredUser implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    private int id; 

    @OneToOne 
    @JoinColumn(nullable = false, name = "USERNAME_FK") 
    private User user; 

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "user") 
    private Profile profile; 
    ... 

我使用的「資源庫」和休眠的實體存儲到數據庫中。我希望我的實體通過使用註釋儘可能健壯,但這隻會給我帶來很多問題。

目前,我有以下代碼:

@Autowired 
private RegisteredUserRepository rur; 

@Autowired 
private UserRepository ur; 
... 

// Creating a user 
User root = new User("root", "1234", "[email protected]"); 
root.setFirstName("root"); 
root.setLastName("root"); 
root = ur.save(root); 

Profile profile = new Profile(String.format("%s", root.getFullName())); 

RegisteredUser registeredUser = new RegisteredUser(profile); 
root.setRegisteredUser(registeredUser); 
registeredUser = rur.save(registeredUser); 
registeredUser = rur.save(registeredUser); // PROBLEM HERE! 

問題的回溯是:

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mycompany.app.models.Profile 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:470) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:295) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:195) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:138) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40] 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:294) ~[spring-orm-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at com.sun.proxy.$Proxy88.persist(Unknown Source) ~[na:na] 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:439) ~[spring-data-jpa-1.9.4.RELEASE.jar:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:483) ~[spring-data-commons-1.11.4.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:468) ~[spring-data-commons-1.11.4.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440) ~[spring-data-commons-1.11.4.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.11.4.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) ~[spring-tx-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.2.5.RELEASE.jar:4.2.5.RELEASE] 
    ... 21 common frames omitted 

我試圖做到的是,當我嘗試保存第二次註冊用戶,它會正確更新表。

我該如何解決這個問題?我已經看到了,這可能是因爲我是如何實現的getter和setter方法,所以它們是:

public Profile getProfile() { 
    return profile; 
} 

public void setProfile(Profile profile) { 
    if (sameAsFormer(profile)) { 
     return; 
    } 

    Profile oldProfile = this.profile; 
    this.profile = profile; 

    if (oldProfile != null) { 
     oldProfile.setRegisteredUser(null); 
    } 

    if (this.profile != null) { 
     this.profile.setRegisteredUser(this); 
    } 
} 

getter和setter方法在Profile

getter和在類RegisteredUser制定者

RegisteredUser實體沒有指定
public RegisteredUser getRegisteredUser() { 
    return user; 
} 

public void setRegisteredUser(RegisteredUser u) { 
    user = u; 
} 

回答

2

ID生成的,這意味着生成策略是assigned(你必須保存之前提供的id值)。

因爲您沒有指定id值,所以在第二個save調用中也將registeredUser實例視爲暫時。持續操作級聯到關聯的Profile,該關聯已在第一次調用中保存在正確自動生成的ID(其id字段中有@GeneratedValue註釋),因此在新事務中被視爲分離。

最簡單的解決方案是定義ID發生器RegisteredUser還有:

@Id 
@GeneratedValue 
private int id; 
+0

謝謝,這似乎解決了問題。我不知道那個... – nbro

+0

對不起,男士,如果你能幫到,我還有其他問題。在上述相同的情況下,我試圖刪除'RegisteredUser',但它不會刪除任何東西......可能是什麼問題? – nbro

+0

[This answer](http://stackoverflow.com/a/34843369/4754790)可能會有所幫助。 –