无法为双向 Spring Data JPA 和 Spring REST 正确设置@ManyToMany和@OneToOn



我正在使用带有Spring Data JPA和Spring Data REST的Spring Boot。

我有一个名为TestExection的类,它是一个具有多个TestResults的类设置。 创建测试执行时,不会为其创建要设置的结果。

稍后,当 TestExecution 运行时,将创建 TestResult 对象。

这些 TestResult 对象与 TestExecution 具有@OneToOne关系,在保存 TestResult 之前,在 TestResult 上设置 TestExecute 对象并调用 save(TestResult)。

  // Create RESULT object
  TestResult testResult = new TestResult(someTestExection......);
  save(testResult)

如果我通过 REST 调用以查看 testResults/1/testExecution,我可以看到与 testResult 关联的 testExecution。 如果我对testExecutions/1/testResults进行相同的调用,它会返回一个空的[]。

2个问题:

1) 我是否需要将新创建的 TestResult 对象显式设置为测试执行的 TestResult 集?

  testExecution.getTestResults().add(testResult);
  save(testExecution)
  • 当我尝试这样做时,它会导致附加的堆栈跟踪。

    Hibernate: update test_execution set description=?, owner=?, version=? where id=? and version=?
    [WARNING]
    java.lang.reflect.InvocationTargetException
        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:497)
        at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:478)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.StackOverflowError
        at com.miw.mcb.server.model.TestExecution.hashCode(TestExecution.java:32)
        at com.miw.mcb.server.model.TestResult.hashCode(TestResult.java:30)
        at java.util.AbstractSet.hashCode(AbstractSet.java:126)
        at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:448)
        at com.miw.mcb.server.model.TestExecution.hashCode(TestExecution.java:32)
        at com.miw.mcb.server.model.TestResult.hashCode(TestResult.java:30)
        at java.util.AbstractSet.hashCode(AbstractSet.java:126)
        at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:448)
    

2)有没有办法让它设置一个关系,以便在TestResult设置TestExecution时可以链接它并添加到其列表中?

测试执行

  @Data
  @Entity
  @Table(name = "test_execution")
  //@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
  public class TestExecution {
      private @Id @GeneratedValue Long id;
      // TODO set back to lazy
      @ManyToMany(fetch = FetchType.EAGER)
      //@JsonBackReference
      private Set<TestResult> testResults;
      // TODO set back to lazy
      @ManyToMany(fetch = FetchType.EAGER)
      private Set<TestSuite> testSuites;

测试结果

  @Data
  @Entity
  @Table(name = "test_result")
  //@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
  public class TestResult {
      private @Id @GeneratedValue Long id;
      // TODO switch back to lazy
      @OneToOne(fetch = FetchType.EAGER)
      //@JsonManagedReference
      private TestExecution testExecution;
      // TODO switch back to lazy
      @OneToOne(fetch = FetchType.EAGER)
      private TestSuite testSuite;

两个存储库的设置相同

TestExecutionRepository

@Repository
@Transactional
public interface TestExecutionRepository extends PagingAndSortingRepository<TestExecution, Long> {

测试结果存储库

@Repository
@Transactional
public interface TestResultRepository extends PagingAndSortingRepository<TestResult, Long> {

应用配置

@Configuration
@ComponentScan({ "com.miw.mcb.server.dao.repository", "com.miw.mcb.server.model" })
public class AppConfig {
}

SpringBootApp (ReactAndSpringDataRestApplication)

@SpringBootApplication
public class ReactAndSpringDataRestApplication {
public static void main(String[] args) {
    SpringApplication.run(ReactAndSpringDataRestApplication.class, args);
}
}

更新:我为 @ManyToOne 和 @OneToMany 进行了更新,但仍然存在如何将TestResults传播到TestExecution

的问题

感谢您对ManyToOne和OneToMany的解释。我以为我的映射不正确。

之后,我在运行时得到了以下堆栈跟踪:

 testExecution.getTestResults().add(testResult); 
 save(testExecution)

** 更新 result.setTestExecution(execution); execution.getResults().add(result); repo.save(execution); 不保存 result

java.lang.StackOverflowError: null
  at com.miw.mcb.server.model.TestExecution.hashCode(TestExecution.java:26)
  at com.miw.mcb.server.model.TestResult.hashCode(TestResult.java:35)
  at java.util.AbstractSet.hashCode(AbstractSet.java:126)
  at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:448)
  at com.miw.mcb.server.model.TestExecution.hashCode(TestExecution.java:26)
  at com.miw.mcb.server.model.TestResult.hashCode(TestResult.java:35)
  at java.util.AbstractSet.hashCode(AbstractSet.java:126)
  at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:448)
  at com.miw.mcb.server.model.TestExecution.hashCode(TestExecution.java:26)
  at com.miw.mcb.server.model.TestResult.hashCode(TestResult.java:35)
  at java.util.AbstractSet.hashCode(AbstractSet.java:126)...

** 为了解决这个问题,我必须用龙目岛实现测试结果的 hasCode() 函数 **

 @EqualsAndHashCode(exclude={"id", "testExecution", "device", "testCase"})

我认为您对 JPA 注释做出了错误的选择。此外,我不明白这是如何工作的。

事实上,@ManyToMany关系代表一种关系,其中实体的每个元素都可以与其他实体中的任何人相关联。为此,您需要一个中间表。这意味着单个TestResult可能与许多处决相关联。

另一方面,您提供@OneToOne映射,这是另一种方式,仅为此对象提供另一端的一个实体实例。

您管理它的方式看起来像您想要的是一个@OneToMany,这将允许TestExecution控制testResults集合,这意味着测试执行可以有多个结果,但每个结果只属于一个执行。

测试执行:

@OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="testExecution")
private Set<TestResult> testResults;

测试结果:

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="id_test_result")
private TestExecution testExecution;

这样,您可以让 TextExecution 管理其 TestResult 集合(使用 CascadeType.ALL 在保存 TestExecution 对象时将更改传播到集合中)。

另请参阅:

  • JPA 一对多和多对一关系

相关内容

  • 没有找到相关文章

最新更新