Post-升级,@MapsId 在保存现有实体时抛出错误,但在其他方面工作正常
Post-upgrade, @MapsId is throwing an error when saving an existing entity, but otherwise works fine
我正在努力将 Spring Boot 1.5.21 项目 (Java 8u221) 升级到 Spring 启动 2.1.9(Java 11.0.2-打开)。在这两种情况下,我们都使用带有 spring 启动器和依赖解析器的 gradle 构建,因此底层 Spring、JPA 和 Hibernate 库的版本是 spring 管理的.
该项目有一个可选的一对一映射,其中子实体从父实体生成的 ID 中获取其 ID。在项目SpringBoot 1版本中,关系是这样配置的:
@Entity
@Table(name = "PARENT_OBJECT", schema = "MYSCHEMA")
public class ParentObject implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PARENT_OBJECT_ID_SEQ")
@SequenceGenerator(name = "PARENT_OBJECT_ID_SEQ", sequenceName = "MYSCHEMA.PARENT_OBJECT_ID_SEQ")
protected Long id;
@OneToOne(optional = true, mappedBy = "parentObject", cascade = CascadeType.ALL, orphanRemoval = true)
@Valid
protected ChildObject childObject;
// Other fields and methods
}
@Entity
@Table(name = "CHILD_OBJECT", schema = "MYSCHEMA")
public class ChildObject implements Serializable {
@Id
@Column(name = "parent_object_id", unique = true, nullable = false, insertable = true, updatable = false)
private Long parentObjectId;
@OneToOne
@MapsId
@PrimaryKeyJoinColumn
@JsonIgnore
private ParentObject parentObject;
// Other fields and methods
}
当我更新到 Spring Boot 2 时,我不得不更新很多 JPA 设置,特别是被抱怨的一件事是生成的查询正在寻找 'PARENTOBJECT_ID' 而不是 'PARENT_OBJECT_ID',所以我仔细研究了一下,发现一篇文章解释了如何使用 @JoinColumn
修复一对一映射的列名,并更新了子对象对 parentObject 字段的注释如下:
@OneToOne
@MapsId
@JoinColumn(name = "parent_object_id")
@JsonIgnore
private ParentObject parentObject;
我完全删除了 @PrimaryKeyJoinColumn
,因为文档似乎建议如果您希望 Hibernate 处理 ID 的分配,并且您打算自己管理它们,则应该使用 @MapsId
, 那就是你使用 @PrimaryKeyJoinColumn
.
的时候
此配置适用于我的所有测试,除了 2:控制器的 UPDATE 集成测试(POST 测试工作得很好,当第一次创建 ParentObject 及其相关联时子对象)。 这两个测试的错误是:
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]
奇怪的是,这些实体及其关联的所有存储库集成测试以及所有其他控制器集成测试都通过了,包括新 ParentObject
是 POST 的测试ed 及其新的 ChildObject
。我四处寻找可能的解决方案,但我阅读的每篇文章似乎都表明我使用的配置应该有效。我还尝试了建议的替代配置,例如使用 @PrimaryKeyJoinColumn
和自己设置 ID 字段,在 ChildObject
s ID 上使用 ID 生成器(即使 @MapsId
的目的是告诉系统使用 ParentObject
) 的 ID,通常我最终会遇到更多失败的测试,并出现以下错误:
org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): org.mycompany.myproject.mymodule.mysubmodule.ChildObject; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): org.mycompany.myproject.mymodule.mysubmodule.ChildObject
虽然有时我会得到无法 'assign id from null' 的原始错误。在这一点上,我不知道这是如何配置不正确的,或者还有什么其他因素在搞砸事情。此时我愿意尝试所有建议。
为了完整起见,以下是应用程序中的一堆代码片段。 堆栈跟踪中的相关行号用注释注明。我省略了控制器代码,因为它没有什么特别之处; POST 和 PUT 方法都调用相同的服务方法;它们只是位于不同的端点,PUT 在调用服务保存方法之前首先检查对象是否存在于数据库中。这是为 ParentObject
:
调用 JPA 存储库的服务方法
@Service
@Transactional(readOnly = true)
public class ParentObjectServiceImpl implements ParentObjectService {
// other fields and other methods
@Autowired
private ParentObjectRepository parentObjectRepository;
@Transactional(readOnly = false)
@Override
public ParentObject saveParentObject(final ParentObject parentObject) {
parentObject.prepForPersistence();
return parentObjectRepository.save(parentObject); //Line 93
}
}
这是我的 JPA 存储库:
public interface ParentObjectRepository extends CrudRepository<ParentObject, Long> {
// custom methods, no override for save though
}
这里是 ParentObject
的 prepForPersistence()
方法:
public void prepForPersistence() {
if(childObject != null) {
childObject.setParentObject(this);
// In some iterations of the code in trying to solve this, I also had the following line
//childObject.setParentObjectId(this.id);
}
}
这里有两项测试(一项通过,一项未通过):
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApplication.class)
@WebAppConfiguration
// This profile disabled csrf for testing, and sets some env variables
@ActiveProfiles("integration-test")
@Transactional
public class ParentObjectControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
// This test PASSES
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPostParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final ParentObject parentObject = new ParentObject();
// set some properties on parentObject that don't relate to ChildObject
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().post("/parent-objects")
.then().log().all().statusCode(201).contentType(ContentType.JSON)
.and().body(matchesJsonSchemaInClasspath("json-schemas/parent-object.json"))
.and().body("username", equalTo(TEST_USER))
.extract().as(ParentObject.class);
assertThat(result.getId(), is(notNullValue()));
assertThat(result.getChildObject().getParentObjectId(), is(result.getId()));
}
// This test FAILS with the 'attempted to assign id from null one-to-one property' error
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
// Inserts a ParentObject record with ID -1
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPutParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final Long EXISTING_ID = -1L;
final ParentObject parentObject = new ParentObject();
parentObject.setId(EXISTING_ID);
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().put("/parent-objects/{parentObjectId}", parentObject.getId()) //line 260
.then().log().all().statusCode(200)
.extract().as(ParentObject.class);
assertThat(result.getId(), is(EXISTING_ID));
assertThat(result.getChildObject().getParentObjectId(), is(EXISTING_ID));
}
这是完整的堆栈跟踪:
Responding with HTTPStatus=INTERNAL_SERVER_ERROR due to the following error:
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:352)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:254)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy249.save(Unknown Source)
at org.mycompany.myproject.mymodule.ParentObjectServiceImpl.saveParentObject(ParentObjectServiceImpl.java:93)
at org.mycompany.myproject.mymodule.ParentObjectServiceImpl$$FastClassBySpringCGLIB$531367.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:750)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at org.mycompany.myproject.mymodule.ParentObjectServiceImpl$$EnhancerBySpringCGLIB$$d3a0c3ee.saveChecklistItem()
at org.mycompany.myproject.mymodule.ParentObjectController.putParentObject(ParentObjectController.java:78)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:920)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:97)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:183)
at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.performRequest(MockMvcRequestSenderImpl.java:218)
at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.sendRequest(MockMvcRequestSenderImpl.java:447)
at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.put(MockMvcRequestSenderImpl.java:504)
at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.put(MockMvcRequestSenderImpl.java:100)
at org.mycompany.myproject.mymodule.ParentObjectControllerTest.testPutParentObjectWithChildObject(ParentObjectControllerTest.java:260)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod.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.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=32=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:90)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:119)
at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:287)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:259)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:191)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:927)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:897)
at org.hibernate.engine.spi.CascadingActions.cascade(CascadingActions.java:261)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:490)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:415)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:149)
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:532)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:361)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:188)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:72)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:905)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:310)
at com.sun.proxy.$Proxy214.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:538)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 140 more
在此先感谢您的建议和帮助!
我认为这是一个错误,但如果有人有变通方法,我仍然对变通方法感兴趣。我最初在 hibernate 上发现了一个似乎与问题匹配的错误,但它被注册为仅影响 5.2 系列并标记为 'fixed',由于我们的项目使用的是 5.3 系列,我继续前进。不过,从 spring 方面深入研究提交的错误,面包屑引导我找到了这个 5.3 系列错误:https://hibernate.atlassian.net/browse/HHH-13413 which linked back to the 5.2 series bug I originally found, which, contrary to the 5.3 write-up, seemed to suggest that this has always been a problem since the 5.2 series and should have never worked in the 5.3 series, because, not only was the 5.3 series bug marked as a duplicate of the 5.2 series bug, when I looked closer at the 5.2 bug, it stated that it's fix version wasn't until 5.4: https://hibernate.atlassian.net/browse/HHH-12436
所以我将尝试降级到最后一个可用的 5.2 系列,然后升级到 5.4 系列...我只是不确定这两个系列将如何与其他 spring 数据 jpa 功能,这本身可能是一个大问题。
更新:除了 运行 之外还有一个问题,因为我们使用的是 java 11(https://hibernate.atlassian.net/browse/HHH-12924 -> 我不得不使用 javassist:3.23.0-GA 来让 hibernate-core:5.2.13.Final 工作),降级成功,使一对一映射再次工作。所有其他测试也都通过了。但是我还没有对这个解决方案进行广泛的测试,因为我更喜欢基于升级的解决方案。
更新 2:能够升级到 Spring Boot 2.2.0(使用 Hibernate 5.4,修复了一对一映射的这个特定错误)!它需要对我的序列进行一些更改,但升级并不太痛苦;甚至不需要使用降级标志!如果碰巧您的映射问题未得到解决,则有一个 'use the 5.2 behavior' 标志,因为他们仍在解决各种映射方案的问题。有关其 5.4 迁移说明的更多详细信息,请参见此处:https://github.com/hibernate/hibernate-orm/blob/61cddad76d5bba951805fa7ed90cc149d404841c/migration-guide.adoc
我正在努力将 Spring Boot 1.5.21 项目 (Java 8u221) 升级到 Spring 启动 2.1.9(Java 11.0.2-打开)。在这两种情况下,我们都使用带有 spring 启动器和依赖解析器的 gradle 构建,因此底层 Spring、JPA 和 Hibernate 库的版本是 spring 管理的.
该项目有一个可选的一对一映射,其中子实体从父实体生成的 ID 中获取其 ID。在项目SpringBoot 1版本中,关系是这样配置的:
@Entity
@Table(name = "PARENT_OBJECT", schema = "MYSCHEMA")
public class ParentObject implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PARENT_OBJECT_ID_SEQ")
@SequenceGenerator(name = "PARENT_OBJECT_ID_SEQ", sequenceName = "MYSCHEMA.PARENT_OBJECT_ID_SEQ")
protected Long id;
@OneToOne(optional = true, mappedBy = "parentObject", cascade = CascadeType.ALL, orphanRemoval = true)
@Valid
protected ChildObject childObject;
// Other fields and methods
}
@Entity
@Table(name = "CHILD_OBJECT", schema = "MYSCHEMA")
public class ChildObject implements Serializable {
@Id
@Column(name = "parent_object_id", unique = true, nullable = false, insertable = true, updatable = false)
private Long parentObjectId;
@OneToOne
@MapsId
@PrimaryKeyJoinColumn
@JsonIgnore
private ParentObject parentObject;
// Other fields and methods
}
当我更新到 Spring Boot 2 时,我不得不更新很多 JPA 设置,特别是被抱怨的一件事是生成的查询正在寻找 'PARENTOBJECT_ID' 而不是 'PARENT_OBJECT_ID',所以我仔细研究了一下,发现一篇文章解释了如何使用 @JoinColumn
修复一对一映射的列名,并更新了子对象对 parentObject 字段的注释如下:
@OneToOne
@MapsId
@JoinColumn(name = "parent_object_id")
@JsonIgnore
private ParentObject parentObject;
我完全删除了 @PrimaryKeyJoinColumn
,因为文档似乎建议如果您希望 Hibernate 处理 ID 的分配,并且您打算自己管理它们,则应该使用 @MapsId
, 那就是你使用 @PrimaryKeyJoinColumn
.
此配置适用于我的所有测试,除了 2:控制器的 UPDATE 集成测试(POST 测试工作得很好,当第一次创建 ParentObject 及其相关联时子对象)。 这两个测试的错误是:
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]
奇怪的是,这些实体及其关联的所有存储库集成测试以及所有其他控制器集成测试都通过了,包括新 ParentObject
是 POST 的测试ed 及其新的 ChildObject
。我四处寻找可能的解决方案,但我阅读的每篇文章似乎都表明我使用的配置应该有效。我还尝试了建议的替代配置,例如使用 @PrimaryKeyJoinColumn
和自己设置 ID 字段,在 ChildObject
s ID 上使用 ID 生成器(即使 @MapsId
的目的是告诉系统使用 ParentObject
) 的 ID,通常我最终会遇到更多失败的测试,并出现以下错误:
org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): org.mycompany.myproject.mymodule.mysubmodule.ChildObject; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): org.mycompany.myproject.mymodule.mysubmodule.ChildObject
虽然有时我会得到无法 'assign id from null' 的原始错误。在这一点上,我不知道这是如何配置不正确的,或者还有什么其他因素在搞砸事情。此时我愿意尝试所有建议。
为了完整起见,以下是应用程序中的一堆代码片段。 堆栈跟踪中的相关行号用注释注明。我省略了控制器代码,因为它没有什么特别之处; POST 和 PUT 方法都调用相同的服务方法;它们只是位于不同的端点,PUT 在调用服务保存方法之前首先检查对象是否存在于数据库中。这是为 ParentObject
:
@Service
@Transactional(readOnly = true)
public class ParentObjectServiceImpl implements ParentObjectService {
// other fields and other methods
@Autowired
private ParentObjectRepository parentObjectRepository;
@Transactional(readOnly = false)
@Override
public ParentObject saveParentObject(final ParentObject parentObject) {
parentObject.prepForPersistence();
return parentObjectRepository.save(parentObject); //Line 93
}
}
这是我的 JPA 存储库:
public interface ParentObjectRepository extends CrudRepository<ParentObject, Long> {
// custom methods, no override for save though
}
这里是 ParentObject
的 prepForPersistence()
方法:
public void prepForPersistence() {
if(childObject != null) {
childObject.setParentObject(this);
// In some iterations of the code in trying to solve this, I also had the following line
//childObject.setParentObjectId(this.id);
}
}
这里有两项测试(一项通过,一项未通过):
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApplication.class)
@WebAppConfiguration
// This profile disabled csrf for testing, and sets some env variables
@ActiveProfiles("integration-test")
@Transactional
public class ParentObjectControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
// This test PASSES
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPostParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final ParentObject parentObject = new ParentObject();
// set some properties on parentObject that don't relate to ChildObject
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().post("/parent-objects")
.then().log().all().statusCode(201).contentType(ContentType.JSON)
.and().body(matchesJsonSchemaInClasspath("json-schemas/parent-object.json"))
.and().body("username", equalTo(TEST_USER))
.extract().as(ParentObject.class);
assertThat(result.getId(), is(notNullValue()));
assertThat(result.getChildObject().getParentObjectId(), is(result.getId()));
}
// This test FAILS with the 'attempted to assign id from null one-to-one property' error
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
// Inserts a ParentObject record with ID -1
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPutParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final Long EXISTING_ID = -1L;
final ParentObject parentObject = new ParentObject();
parentObject.setId(EXISTING_ID);
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().put("/parent-objects/{parentObjectId}", parentObject.getId()) //line 260
.then().log().all().statusCode(200)
.extract().as(ParentObject.class);
assertThat(result.getId(), is(EXISTING_ID));
assertThat(result.getChildObject().getParentObjectId(), is(EXISTING_ID));
}
这是完整的堆栈跟踪:
Responding with HTTPStatus=INTERNAL_SERVER_ERROR due to the following error: org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:352) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:254) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy249.save(Unknown Source) at org.mycompany.myproject.mymodule.ParentObjectServiceImpl.saveParentObject(ParentObjectServiceImpl.java:93) at org.mycompany.myproject.mymodule.ParentObjectServiceImpl$$FastClassBySpringCGLIB$531367.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:750) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) at org.mycompany.myproject.mymodule.ParentObjectServiceImpl$$EnhancerBySpringCGLIB$$d3a0c3ee.saveChecklistItem() at org.mycompany.myproject.mymodule.ParentObjectController.putParentObject(ParentObjectController.java:78) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:920) at javax.servlet.http.HttpServlet.service(HttpServlet.java:668) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:97) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:183) at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.performRequest(MockMvcRequestSenderImpl.java:218) at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.sendRequest(MockMvcRequestSenderImpl.java:447) at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.put(MockMvcRequestSenderImpl.java:504) at io.restassured.module.mockmvc.internal.MockMvcRequestSenderImpl.put(MockMvcRequestSenderImpl.java:100) at org.mycompany.myproject.mymodule.ParentObjectControllerTest.testPutParentObjectWithChildObject(ParentObjectControllerTest.java:260) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.runners.model.FrameworkMethod.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.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=32=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.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:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38) at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) at com.sun.proxy.$Proxy5.processTestClass(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [org.mycompany.myproject.mymodule.mysubmodule.ChildObject.parentObject] at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:90) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:119) at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:287) at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:259) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:191) at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:927) at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:897) at org.hibernate.engine.spi.CascadingActions.cascade(CascadingActions.java:261) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:490) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:415) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:149) at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:532) at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:361) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:188) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:72) at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:905) at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:310) at com.sun.proxy.$Proxy214.merge(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:538) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke(RepositoryFactorySupport.java:595) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ... 140 more
在此先感谢您的建议和帮助!
我认为这是一个错误,但如果有人有变通方法,我仍然对变通方法感兴趣。我最初在 hibernate 上发现了一个似乎与问题匹配的错误,但它被注册为仅影响 5.2 系列并标记为 'fixed',由于我们的项目使用的是 5.3 系列,我继续前进。不过,从 spring 方面深入研究提交的错误,面包屑引导我找到了这个 5.3 系列错误:https://hibernate.atlassian.net/browse/HHH-13413 which linked back to the 5.2 series bug I originally found, which, contrary to the 5.3 write-up, seemed to suggest that this has always been a problem since the 5.2 series and should have never worked in the 5.3 series, because, not only was the 5.3 series bug marked as a duplicate of the 5.2 series bug, when I looked closer at the 5.2 bug, it stated that it's fix version wasn't until 5.4: https://hibernate.atlassian.net/browse/HHH-12436
所以我将尝试降级到最后一个可用的 5.2 系列,然后升级到 5.4 系列...我只是不确定这两个系列将如何与其他 spring 数据 jpa 功能,这本身可能是一个大问题。
更新:除了 运行 之外还有一个问题,因为我们使用的是 java 11(https://hibernate.atlassian.net/browse/HHH-12924 -> 我不得不使用 javassist:3.23.0-GA 来让 hibernate-core:5.2.13.Final 工作),降级成功,使一对一映射再次工作。所有其他测试也都通过了。但是我还没有对这个解决方案进行广泛的测试,因为我更喜欢基于升级的解决方案。
更新 2:能够升级到 Spring Boot 2.2.0(使用 Hibernate 5.4,修复了一对一映射的这个特定错误)!它需要对我的序列进行一些更改,但升级并不太痛苦;甚至不需要使用降级标志!如果碰巧您的映射问题未得到解决,则有一个 'use the 5.2 behavior' 标志,因为他们仍在解决各种映射方案的问题。有关其 5.4 迁移说明的更多详细信息,请参见此处:https://github.com/hibernate/hibernate-orm/blob/61cddad76d5bba951805fa7ed90cc149d404841c/migration-guide.adoc