我正在尝试在两个表之间做多对多的关系。该关系包含额外信息(日期)。我正在尝试使用Spring Data JPA实现这一点,而我正在使用单元测试进行测试。测试失败并给出错误:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find ....JoinEntity with id ....JoinEntity@5934ca1e; nested exception is javax.persistence.EntityNotFoundException: Unable to find ....JoinEntity with id ....JoinEntity@5934ca1e
这是我的代码:
实体A:
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name= "tableA")
public class EntityA
{
/** The primary key. */
@Id
private Integer id;
private String name;
@OneToMany(mappedBy="a")
private Set<JoinEntity> bs;
//... getters and setters
}
实体B:
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name= "tableB")
public class EntityB
{
/** The primary key. */
@Id
private Integer id;
private String name;
//... getters and setters
}
加入实体:
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="joinTableAB")
@IdClass(ABId.class)
public class JoinEntity implements Serializable
{
@Column(name = "join_date")
private Date date;
@Id
@ManyToOne
@JoinColumn(name = "a_id")
private EntityA a;
@Id
@ManyToOne
@JoinColumn(name = "b_id")
private EntityB b;
//... getters and setters
}
A的存储库:
import org.springframework.data.repository.CrudRepository;
public interface ARepository extends CrudRepository<EntityA,Integer>
{
}
B的存储库:
import org.springframework.data.repository.CrudRepository;
public interface BRepository extends CrudRepository<EntityB,Integer>
{
}
简单的测试类:
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Testing for AtmosphericConditionsRepository.
*/
@DataJpaTest
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ARepositoryTest.class})
public class ARepositoryTest
{
@Autowired
ARepository aRepository;
@Autowired
BRepository bRepository;
@Test
public void test()
{
EntityA a0 = new EntityA();
a0.setId(0);
a0.setName("a0");
EntityA a1 = new EntityA();
a1.setId(1);
a1.setName("a1");
a0 = aRepository.save(a0);
a1 = aRepository.save(a1);
EntityB b0 = new EntityB();
b0.setId(0);
b0.setName("b0");
EntityB b1 = new EntityB();
b1.setId(1);
b1.setName("b1");
b0 = bRepository.save(b0);
b1 = bRepository.save(b1);
Set<JoinEntity> joinEntities = new HashSet<>();
JoinEntity je = new JoinEntity();
je.setDate(new Date());
je.setA(a0);
je.setB(b0);
joinEntities.add(je);
a0.setBs(joinEntities);
aRepository.save(a0);
}
}
@IdClass中指定的类:
import java.io.Serializable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
public class ABId implements Serializable
{
private EntityA a;
private EntityB b;
public ABId()
{
}
public ABId(EntityA pA, EntityB pB)
{
a = pA;
b = pB;
}
public EntityA getA()
{
return a;
}
public EntityB getB()
{
return b;
}
@Override
public boolean equals(Object pO)
{
if (this == pO)
{
return true;
}
if (pO == null || getClass() != pO.getClass())
{
return false;
}
ABId abId = (ABId) pO;
if (a != null ? !a.equals(abId.a) : abId.a != null)
{
return false;
}
return b != null ? b.equals(abId.b) : abId.b == null;
}
@Override
public int hashCode()
{
int result = a != null ? a.hashCode() : 0;
result = 31 * result + (b != null ? b.hashCode() : 0);
return result;
}
}
扩展堆栈跟踪:
2017-10-18 08:30:48.696 INFO 6460 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@de3a06f testClass = ARepositoryTest, testInstance = ....ARepositoryTest@58a90037, testMethod = test@ARepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@76b10754 testClass = ARepositoryTest, locations = '{}', classes = '{interface ....ARepository, interface ....BRepository, class ....JoinEntity, class ....ABId, interface ....ARepository, interface ....BRepository, class ....JoinEntity, class ....ABId}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4493d195, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@4e1d422d, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@5c8ff52f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3cb1ffe6, org.springframework.boot.test.context.ImportsContextCustomizer@274bc460, org.springframework.boot.test.context.SpringBootTestContextCustomizer@2c039ac6, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6b57696f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@5e13f156]; rollback [true]
Hibernate: select entitya0_.id as id1_6_0_, entitya0_.name as name2_6_0_ from tablea entitya0_ where entitya0_.id=?
Hibernate: select entitya0_.id as id1_6_0_, entitya0_.name as name2_6_0_ from tablea entitya0_ where entitya0_.id=?
Hibernate: select entityb0_.id as id1_7_0_, entityb0_.name as name2_7_0_ from tableb entityb0_ where entityb0_.id=?
Hibernate: select entityb0_.id as id1_7_0_, entityb0_.name as name2_7_0_ from tableb entityb0_ where entityb0_.id=?
Hibernate: select joinentity0_.a_id as a_id2_2_0_, joinentity0_.b_id as b_id3_2_0_, joinentity0_.join_date as join_dat1_2_0_, entitya1_.id as id1_6_1_, entitya1_.name as name2_6_1_, entityb2_.id as id1_7_2_, entityb2_.name as name2_7_2_ from join_tableab joinentity0_ inner join tablea entitya1_ on joinentity0_.a_id=entitya1_.id inner join tableb entityb2_ on joinentity0_.b_id=entityb2_.id where joinentity0_.a_id=? and joinentity0_.b_id=?
2017-10-18 08:30:49.035 INFO 6460 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test context [DefaultTestContext@de3a06f testClass = ARepositoryTest, testInstance = ....ARepositoryTest@58a90037, testMethod = test@ARepositoryTest, testException = org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find ....JoinEntity with id ....ABId@5a9ba131; nested exception is javax.persistence.EntityNotFoundException: Unable to find ....JoinEntity with id ....ABId@5a9ba131, mergedContextConfiguration = [MergedContextConfiguration@76b10754 testClass = ARepositoryTest, locations = '{}', classes = '{interface ....ARepository, interface ....BRepository, class ....JoinEntity, class ....ABId, interface ....ARepository, interface ....BRepository, class ....JoinEntity, class ....ABId}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4493d195, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@4e1d422d, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@5c8ff52f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3cb1ffe6, org.springframework.boot.test.context.ImportsContextCustomizer@274bc460, org.springframework.boot.test.context.SpringBootTestContextCustomizer@2c039ac6, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6b57696f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]].
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find ....JoinEntity with id ....ABId@d3513f0a; nested exception is javax.persistence.EntityNotFoundException: Unable to find ....JoinEntity with id ....ABId@d3513f0a
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:389)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
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:213)
at com.sun.proxy.$Proxy93.save(Unknown Source)
at ....ARepositoryTest.test(ARepositoryTest.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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: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:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
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:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: javax.persistence.EntityNotFoundException: Unable to find ....JoinEntity with id ....ABId@d3513f0a
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:144)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1022)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:639)
at org.hibernate.type.EntityType.resolve(EntityType.java:431)
at org.hibernate.type.EntityType.replace(EntityType.java:330)
at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:518)
at org.hibernate.type.CollectionType.replace(CollectionType.java:663)
at org.hibernate.type.TypeHelper.replace(TypeHelper.java:177)
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:401)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:203)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:840)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:822)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:827)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1161)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy85.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:509)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
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:282)
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)
... 41 more
答案 0 :(得分:0)
我错过了该系列的Cascade类型:/。
添加后:
@OneToMany(mappedBy="a",cascade = CascadeType.ALL)
private Set<JoinEntity> bs;
现在工作正常。