问题 Spring Data REST - 检测到具有相同关系类型的多个关联链接


我正在尝试做一个简单的Spring应用程序。它需要公开REST端点并将其保存到关系数据库。

我拿了你的示例项目, http://spring.io/guides/gs/accessing-data-rest/。我可以按照指南中的说明进行所有操作(POST,PATCH,PUT,GET)。

但是我尝试创建添加到Person Entity类的关系,事情开始分崩离析。

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String firstName;
    private String lastName;

    @OneToOne(cascade = {CascadeType.ALL})
    private PersonDetails personDetails;

    @OneToOne(cascade = {CascadeType.ALL})
    private PersonChildren personChildren;

     ///Getter and setters for everything except id.
}


@Entity
public class PersonChildren {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String childFirstName;
    private String childLastName;

    @OneToOne(mappedBy="personChildren", optional=false)
    private Person person;

///Getter and setters for everything except id.
}


@Entity
public class PersonDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String email;
    private String phoneNumber;

    @OneToOne(mappedBy="personDetails",optional=false)
    private Person person;

///Getter and setters for everything except id.
}


@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {

    List<Person> findByLastName(@Param("name") String name);

}

build.gradle

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-release" }
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.1.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'gs-accessing-data-rest'
    version = '0.1.0'
}

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "http://repo.spring.io/libs-release" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("com.h2database:h2")
    compile("org.springframework.data:spring-data-rest-webmvc")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}

呼叫:

$ curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName":"John", "lastName": "Doe", "personDetails": { "email": "john@gmail.com", "phoneNumber": "001-002-0003" }, "personChildren": {"childFirstName": "Mary", "childLastName": "Martin" } }' <code> http://localhost:8080/people </code>

Response: 
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
<code>
Location: http://localhost:8080/people/1
</code>
Content-Length: 0
Date: Thu, 26 Jun 2014 05:42:45 GMT

$ curl  http://localhost:8080/people

{
  "timestamp" : 1403761371011,
  "status" : 500,
  "error" : "Internal Server Error",
  "exception" : "org.springframework.http.converter.HttpMessageNotWritableException",
  "message" : "Could not write JSON: Detected multiple association links with same relation type! Disambiguate association @javax.persistence.OneToOne(optional=false, targetEntity=void, cascade=[], fetch=EAGER, orphanRemoval=false, mappedBy=personChildren) private com.ds.dao.rest.Person com.ds.dao.rest.PersonChildren.person using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"people\"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Detected multiple association links with same relation type! Disambiguate association @javax.persistence.OneToOne(optional=false, targetEntity=void, cascade=[], fetch=EAGER, orphanRemoval=false, mappedBy=personChildren) private com.ds.dao.rest.Person com.ds.dao.rest.PersonChildren.person using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"people\"]->java.util.ArrayList[0])",
  "path" : "/people"
}

问题1:我能够发帖但我的GET一直都失败了。

问题2:发布成功后,为什么会出现此错误?

问题3:是否有一个好的Spring指南可以帮助REST和JPA?如果您仍在使用这些模块,我可以查看哪些示例?

问题4:@RepositoryRestResource是否存在问题?除非我将spring-data-rest-webmvc添加为依赖项,否则无法识别。

这类似于未回答的问题 Spring Data Rest Ambiguous Association Exception

更新

它只与一个人合作 OneToOne 映射 Person 类。如果我添加两个类, personDetails 和 personChildren 在 Person 同 OneToOne 映射。它不起作用。

我也尝试过添加 @JointColumn(name="person_details") 和 @JointColumn(name="person_children") 至 personDetails 和 personChildren。它也没用。


9449
2018-06-26 09:13


起源



答案:


原因很简单:关联实体的关系名称是从包含类的属性名称派生的。所以两者 PersonDetails 和 PersonChildren 想要创建一个出站链接 Person 命名 person。如果我们渲染它,它看起来就像这样

{ _links : { 
   person : { href : … }, <- the one from PersonDetails
   person : { href : … }  <- the one from PersonChildren
}

这当然是无效的。此外,排列数组中的两个链接将不允许您区分两个链接(哪一个来自 PersonDetails 哪一个来自 PersonChildren

所以这里有几个选项:

  1. 手动命名这些类型的关系。你可以注释 Person 属性 @RestResource 并配置 rel 注释的属性与不同的东西 person
  2. 您希望两者中的任何一个都不会导出。可以使用完全相同的注释来防止链接被渲染。只需设置 exported 国旗 @RestResource 至 false 并且不会呈现链接。如果指针例如这可能是有用的。从 PersonDetails 在代码中只是相关的,但实际上不是在JSON表示中。

14
2018-06-27 08:01



奥利弗,这就像一个魅力。我用了选项1.感谢您的帮助。 - user827096
我尝试了两种选择,其中没有一种可以帮助我。 - Vijay Muvva


答案:


原因很简单:关联实体的关系名称是从包含类的属性名称派生的。所以两者 PersonDetails 和 PersonChildren 想要创建一个出站链接 Person 命名 person。如果我们渲染它,它看起来就像这样

{ _links : { 
   person : { href : … }, <- the one from PersonDetails
   person : { href : … }  <- the one from PersonChildren
}

这当然是无效的。此外,排列数组中的两个链接将不允许您区分两个链接(哪一个来自 PersonDetails 哪一个来自 PersonChildren

所以这里有几个选项:

  1. 手动命名这些类型的关系。你可以注释 Person 属性 @RestResource 并配置 rel 注释的属性与不同的东西 person
  2. 您希望两者中的任何一个都不会导出。可以使用完全相同的注释来防止链接被渲染。只需设置 exported 国旗 @RestResource 至 false 并且不会呈现链接。如果指针例如这可能是有用的。从 PersonDetails 在代码中只是相关的,但实际上不是在JSON表示中。

14
2018-06-27 08:01



奥利弗,这就像一个魅力。我用了选项1.感谢您的帮助。 - user827096
我尝试了两种选择,其中没有一种可以帮助我。 - Vijay Muvva