java - Spring Data JPA 多对多,带有额外的列

标签 java spring jpa orm

我正在尝试在两个表之间建立多对多关系。该关系包含额外信息(日期)。我正在尝试使用 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

最佳答案

我错过了集合中的级联类型:/。

添加后:

@OneToMany(mappedBy="a",cascade = CascadeType.ALL)
private Set<JoinEntity> bs;

现在工作正常。

关于java - Spring Data JPA 多对多,带有额外的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46789899/

相关文章:

spring - 如何在Spring EL中评估Spring EL

java - 如何使用 JSTL 根据 Map 中的键显示多个表?

java - JPA实体关系方向

java - 具有多个类别的箱线图的 JFreeChart 缩放

java - Jtable 不可见?

java - Groovy 依赖注入(inject)

java - 在 JavaEE Maven 项目中使用 Hibernate 时出现 "java.lang.NoClassDefFoundError: javax/persistence/criteria/Selection"错误

java - HASHMAP - 阈值和负载因子以及容量

java - 如何根据 URL 路径和嵌套级别配置 Jackson 和 Spring 以不同方式呈现对象

java - Oracle 将空字符串转换为 null 但 JPA 不会相应地更新实体缓存