简体   繁体   English

org.hibernate.AssertionFailure: null 标识符@OneToOne 关系

[英]org.hibernate.AssertionFailure: null identifier @OneToOne relationship

I keep getting org.hibernate.AssertionFailure: null identifier when trying to create an object. My classes are as follows:尝试创建 object 时,我不断收到org.hibernate.AssertionFailure: null identifier 。我的课程如下:

public class User {

    @Id
    @Column(name = "user_id", nullable = false)
    private String userId;

    @OneToOne(cascade = CascadeType.ALL, optional = true, mappedBy = "user")
    private UserDetail userDetail;
}

public class UserDetail {

    @Id
    @Column(name = "user_id", nullable = false)
    private String userId;

    @OneToOne(optional = false)
    @PrimaryKeyJoinColumn
    private User user;
}

@Service
public class UserDetailService {

   @Autowired
   private UserDetailRepository userDetailRepository;

   public void create(UserDetail userDetail) {
      userDetailRepository.saveAndFlush(userDetail);
   }
}

And when I try to create a UserDetail :当我尝试创建一个UserDetail时:

String userId = "user";
User user = userService.findByUserId(userId);
UserDetail userDetail = new UserDetail();
userDetail.setUserId(userId);
userDetail.setUser(user);
user.setUserDetail(userDetail);
userDetailService.create(userDetail);

I get the exception我得到例外

Stack trace of the exception:异常堆栈跟踪:

org.hibernate.AssertionFailure: null identifier
at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:68)
at org.hibernate.internal.AbstractSessionImpl.generateEntityKey(AbstractSessionImpl.java:327)
at org.hibernate.type.OneToOneType.isNull(OneToOneType.java:110)
at org.hibernate.type.EntityType.resolve(EntityType.java:500)
at org.hibernate.type.EntityType.replace(EntityType.java:366)
at org.hibernate.type.AbstractType.replace(AbstractType.java:178)
at org.hibernate.type.TypeHelper.replace(TypeHelper.java:211)
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:444)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:249)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:317)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:186)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:876)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:858)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:863)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1196)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:291)
at com.sun.proxy.$Proxy45.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:410)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush(SimpleJpaRepository.java:421)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:416)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:401)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:373)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy49.saveAndFlush(Unknown Source)
at com.my.services.RepositoryUserDetailService.create(RepositoryUserDetailService.java:17)
at com.my.services.RepositoryUserDetailServiceTest.testCreate(RepositoryUserDetailServiceTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:217)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

I was stuck with a very similar problem.我遇到了一个非常相似的问题。 It seems that saving the UserDetails first, while there are also changes to the User ( user.setUserDetail(userDetail) ), requires an explicitly set cascade mode.似乎首先保存UserDetails ,同时对 User ( user.setUserDetail(userDetail) ) 也有更改,需要明确设置级联模式。

Adding the CascadeType.ALL to the UserDetails @OneToOne definition fixed it for me.CascadeType.ALL添加到UserDetails @OneToOne定义为我修复了它。

In my case it works by setting the relationship to null.在我的情况下,它通过将关系设置为空来工作。 Looks like it loads it anyway using the @Id.看起来它无论如何都使用@Id 加载它。

UserDetail userDetail = new UserDetail();
userDetail.setUserId(userId);
userDetailService.create(userDetail);

Hi I think that is a solution for your problem. 嗨,我认为这是解决您的问题的方法。 http://blog.scriptico.com/02/hibernate-one-to-one-bi-directional-mapping/ http://blog.scriptico.com/02/hibernate-one-to-one-bi-directional-mapping/

For me it helped to upgrade from 4.2.x version of Hibernate to 4.3.11.对我来说,它帮助从 Hibernate 的 4.2.x 版本升级到 4.3.11。 The exception does not show up anymore, looks like a bug that has been fixed.异常不再出现,看起来像是已修复的错误。

In my case, save parent before, add parent to relationship field of child (child haven't id), after save child (id get from Parent Entity) references: https://www.baeldung.com/hibernate-identifiers在我的情况下,先保存父母,将父母添加到孩子的关系字段(孩子没有id),在保存孩子之后(从父实体获取id)参考: https://www.baeldung.com/hibernate-identifiers

@Entity
public class UserProfile {

    @Id
    private long profileId;
    
    @OneToOne
    @MapsId
    private User user;

    // ...
}



@Test
public void whenSaveDerivedIdEntity_thenOk() {        
    User user = new User();
    session.save(user);
       
    UserProfile profile = new UserProfile();
    profile.setUser(user);
    session.save(profile);

    assertThat(profile.getProfileId()).isEqualTo(user.getUserId());
}

I had a similar issue and I've managed to solve it.我有一个类似的问题,我已经设法解决了。 Try this:尝试这个:

@OneToOne(cascade = CascadeType.MERGE, optional = false)
@PrimaryKeyJoinColumn(name = "user_id")
private User user;

From what I've been able to find out, when persisting UserDetail , Hibernate takes a different code path and an underlying merge() call is being made instead of persist() , as you have stated in your issue.据我所知,当坚持UserDetail时, Hibernate 采用不同的代码路径,并且正在进行底层merge()调用而不是persist() ,正如您在问题中所述。 One fix could be adding CascadeType.MERGE .一种解决方法是添加CascadeType.MERGE

Please have in mind that this fix does have the effect that the underlying User could be updated.请记住,此修复确实具有可以更新基础User的效果。

Another possible fix could be to use Spring Data Persistable interface , that gives you control of determining if an object is a new object or not, making the repository save method take the correct path (merge or persist).另一种可能的修复方法是使用Spring Data Persistable interface ,它可以让您控制确定 object 是否是新的 object ,从而使存储库保存方法采用正确的路径(合并或持久化)。

Sources:资料来源:

Also answered here: https://stackoverflow.com/a/74500104/11667138也在这里回答: https://stackoverflow.com/a/74500104/11667138

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

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