问题描述
我正在尝试做一个简单的 Spring 应用程序.它需要公开 REST 端点并将其保存到关系数据库中.
I am trying to doing a simple Spring app. It needs to expose REST endpoints and save it to a relational database.
我拿了你的示例项目,http://spring.io/guides/gs/accessing-data-rest/.我能够执行您指南中提到的所有操作(POST、PATCH、PUT、GET).
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.
但是,我尝试为 Person Entity 类创建添加关系,但事情开始分崩离析.
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'
}
调用:
$ 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 一直失败.
Question 1: I am able to do a post but my GET keeps failing.
问题 2:为什么当 Post 成功时我会收到这个错误?
Question 2: Why am I getting this error when Post succeeds?
问题 3:有没有好的 Spring 指南可以帮助 REST 和 JPA?如果您仍在研究这些模块,我可以查看哪些示例?
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?
问题 4:@RepositoryRestResource 是问题吗?除非我将 spring-data-rest-webmvc 添加为依赖项,否则无法识别它.
Question 4: Is @RepositoryRestResource the problem? It is not recognized unless I add spring-data-rest-webmvc as dependency.
这类似于未回答的问题Spring Data Rest 模糊关联异常
更新:
它仅使用 Person
类中的一个 OneToOne
映射.如果我在 Person
和 OneToOne
映射中添加两个类,personDetails
和 personChildren
.它不起作用.
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.
我还尝试将 @JointColumn(name="person_details")
和 @JointColumn(name="person_children")
添加到 personDetails
和personChildren
.它也不起作用.
I also tried adding @JointColumn(name="person_details")
and @JointColumn(name="person_children")
to personDetails
and personChildren
. It did NOT work either.
推荐答案
原因很简单:关联实体的关系名称派生自包含类的属性名称.所以PersonDetails
和PersonChildren
都想创建一个到名为person
的Person
的出站链接.如果我们渲染它,它看起来像这样
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
}
这当然是无效的.此外,将两个链接排列在一个数组中将不再允许您区分这两个链接(哪个来自 PersonDetails
,哪个来自 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
.
这里有几个选项:
- 手动命名这些类型的关系.您可以使用
@RestResource
注释Person
属性并将注释的rel
属性配置为与person
不同的内容. - 您希望两者中的任何一个都不导出.可以使用完全相同的注释来防止链接被渲染.只需将
@RestResource
中的exported
标志设置为false
,链接将不会被呈现.如果指针例如fromPersonDetails
仅在代码中相关,但实际上不在 JSON 表示中.
- Manually name the relations of those types. You can annotate the
Person
properties with@RestResource
and configure therel
attribute of the annotation to something different thanperson
. - 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
tofalse
and the link will not be rendered. This might be useful if the pointer e.g. fromPersonDetails
is just relevant within the code, but actually not in a JSON representation.
这篇关于Spring Data REST - 检测到多个具有相同关系类型的关联链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!