Spring Data REST - 检测到具有相同关系类型的多个关联链接 [英] Spring Data REST - Detected multiple association links with same relation type

查看:195
本文介绍了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)
私人长ID;

private String firstName;
private String lastName;

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

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

/// Getter和setter除了id之外的所有内容。



@Entity
public class PersonChildren {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
私人长ID;

private String childFirstName;
private String childLastName;

@OneToOne(mappedBy =personChildren,可选= false)
私人Person person;

/// Getter和setter除了id之外的所有内容。



@Entity
public class PersonDetails {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
私人长ID;

私人字符串电子邮件;
私人字符串phoneNumber;

@OneToOne(mappedBy =personDetails,可选= false)
私人Person person;

/// Getter和setter除了id之外的所有内容。


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

列表< Person> findByLastName(@Param(name)字符串名称);

$ b

build.gradle

  buildscript {
repositories {
maven {urlhttp:// repo。 spring.io/libs-release}
mavenLocal()
mavenCentral()
}
依赖项{
classpath(org.springframework.boot:spring-boot -gradle-plugin:1.1.1.RELEASE)
}
}

apply plugin:'java'
apply plugin:'eclipse'
应用插件:'idea'
apply插件:'spring-boot'

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

知识库{
mavenLocal()
mavenCentral()
maven {urlhttp://repo.spring.io / libs-release}
}

依赖关系{
compile(org.springframework.boot:spring-boot-starter-web)
compile( org.springframework.boot:spring-boot-starter-data-jpa)
compile(com.h2database:h2)
compi le(org.springframework.data:spring-data-rest-webmvc)
}

任务包装(类型:包装器){
gradleVersion ='1.11'

通话:

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

响应:
HTTP / 1.1 201创建
服务器:Apache-Coyote / 1.1
< code>
位置:http:// localhost:8080 / people / 1
< / code>
Content-Length:0
日期:2014年6月26日星期四05:42:45 GMT

$ curl http:// localhost:8080 / people

{
timestamp:1403761371011,
status:500,
error:内部服务器错误,
exception:org.springframework .http.converter.HttpMessageNotWritableException,
message:无法写入JSON:检测到具有相同关系类型的多个关联链接!消除关联@ javax.persistence.OneToOne(可选= false,targetEntity = void,cascade = [],fetch = EAGER,orphanRemoval = false,mappedBy = personChildren)private com.ds.dao.rest.Person com.ds.dao.rest.PersonChildren.person using @RestResource!(通过引用链:org.springframework.hateoas .PagedResources [\_embedded \] - > java.util.UnmodifiableMap [\people \] - > java.util.ArrayList [0]);嵌套的异常是com.fasterxml.jackson。 databind.JsonMappingException:检测到具有相同关系类型的多个关联链接!Disambiguate associati on @ javax.persistence.OneToOne(可选= false,targetEntity = void,cascade = [],fetch = EAGER,orphanRemoval = false,mappedBy = personChildren)private com.ds.dao.rest.Person com.ds.dao.rest .PersonChildren.person使用@RestResource! (通过参考链: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作为依赖关系,否则无法识别。



这与未回答的问题
春季数据休息不明确的关联例外



更新

它只与e OneToOne 映射到 Person 类中。如果我在 Person 中添加了两个类, personDetails personChildren OneToOne 映射。它不工作。



我也尝试添加 @JointColumn(name =person_details) @JointColumn(name =person_children) personDetails personChildren 。它也没有工作。

解决方案

原因很简单:关联实体的关系名是从属性派生的包含类的名称。因此 PersonDetails PersonChildren 都希望创建出站链接到 Person 名为 person 。如果我们提出这个问题,它会看起来像这样

  {_links:{
person:{href:...} ,< - 来自PersonDetails
person:{href:...}< - 来自PersonChildren的
}
的一个

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



所以这里有几个选项:


  1. 手动命名这些类型的关系。您可以使用 @RestResource注释 Person 并将注释的 rel 属性配置为不同于 person 的内容。

  2. 您希望两者中的任何一个都不能被导出。可以使用完全相同的注释来防止链接被渲染,只需设置<$ c $在 @RestResource false 中导出标志,链接将不会呈现。如果来自 PersonDetails 的指针在代码中恰好相关,但实际上不是JSON表示,则这可能很有用。


I am trying to doing a simple Spring app. It needs to expose REST endpoints and save it to a relational database.

I took your sample project, http://spring.io/guides/gs/accessing-data-rest/. I am able to do all the operations( POST, PATCH, PUT, GET) as mentioned in your guide.

However I tried creating adding relationships to Person Entity class and things start to fall apart.

@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'
}

Call:

$ 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"
}

Question 1: I am able to do a post but my GET keeps failing.

Question 2: Why am I getting this error when Post succeeds?

Question 3: Is there a good Spring Guide that will help with REST and JPA? If you are still working on these modules what examples can I look at?

Question 4: Is @RepositoryRestResource the problem? It is not recognized unless I add spring-data-rest-webmvc as dependency.

This is similar to the unanswered question Spring Data Rest Ambiguous Association Exception

Update:

It is working with only one OneToOne mapping in Person class. If I add both classes, personDetails and personChildren in Person with OneToOne mapping. It is NOT working.

I also tried adding @JointColumn(name="person_details") and @JointColumn(name="person_children") to personDetails and personChildren. It did NOT work either.

解决方案

The reason for that is pretty simple: the relation names for associated entities are derived from the property names of the containing class. So both PersonDetails and PersonChildren want to create an outbound link to a Person named person. If we rendered that, it would look something like this

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

This is of course invalid. Also, lining up the two links in an array would not allow you to distinguish between the two links anymore (which one is coming from PersonDetails and which one is coming from PersonChildren.

So there are a few options here:

  1. Manually name the relations of those types. You can annotate the Person properties with @RestResource and configure the rel attribute of the annotation to something different than person.
  2. You want any of the two not exported at all. The very same annotation can be used to prevent the link from being rendered at all. Simply set the exported flag in @RestResource to false and the link will not be rendered. This might be useful if the pointer e.g. from PersonDetails is just relevant within the code, but actually not in a JSON representation.

这篇关于Spring Data REST - 检测到具有相同关系类型的多个关联链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆