简体   繁体   English

传递给实体的独立实体:配置文件

[英]detached entity passed to persist: Profile

I've the following two entities: 我有以下两个实体:

@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;

    ...

and

@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;
    ...

I'm using "repositories" and hibernate to store entities to the database. 我正在使用“存储库”并休眠以将实体存储到数据库。 I would like that my entities are as much robust as possible by using annotations, but this is only causing me a lot of problems. 我希望通过使用注释使我的实体尽可能地强大,但这只会给我带来很多问题。

Currently, I've the following code: 目前,我有以下代码:

@Autowired
private RegisteredUserRepository rur;

@Autowired
private UserRepository ur;
...

// Creating a user
User root = new User("root", "1234", "root@root.com");
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!

The traceback of the problem is: 问题的回溯是:

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

What I was trying to accomplish is that when I try to save the second time the registered user, it would update the tables correctly. 我要完成的工作是,当我第二次尝试保存注册用户时,它将正确更新表。

How can I solve this problem? 我怎么解决这个问题? I've seen that it may be because of how I implemented the setters and getters, so there they are: 我已经看到,这可能是因为我实现了setter和getter的方式,所以它们是:

Getters and setters in the class RegisteredUser : RegisteredUser器和设置器:

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);
    }
}

Setters and getters in Profile : Profile

public RegisteredUser getRegisteredUser() {
    return user;
}

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

Id generator is not specified for the RegisteredUser entity, meaning that the generation strategy is assigned (you have to provide the id value before saving). 未为RegisteredUser实体指定ID生成器,这意味着已assigned生成策略(保存之前必须提供ID值)。

Because you don't specify id value, the registeredUser instance is considered transient in the second save call as well. 由于未指定id值,因此在第二个save调用中, registeredUser实例也被视为瞬态。 Persist operation is cascaded to the associated Profile which has already been saved in the first call with properly auto-generated id (it has @GeneratedValue annotation on its id field) and is thus considered detached in the new transaction. 持久化操作将级联到已关联的Profile ,该Profile已使用正确自动生成的ID(在其id字段上具有@GeneratedValue批注)保存在第一个调用中,因此被视为在新事务中已分离。

The easiest solution is to define id generator for RegisteredUser as well: 最简单的解决方案是同时为RegisteredUser定义ID生成器:

@Id
@GeneratedValue
private int id;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM