Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring数据、REST和多个关系_Java_Spring_Rest_Spring Boot_Spring Data - Fatal编程技术网

Java Spring数据、REST和多个关系

Java Spring数据、REST和多个关系,java,spring,rest,spring-boot,spring-data,Java,Spring,Rest,Spring Boot,Spring Data,我想知道创建、记录(炫耀)和公开涉及多对多关系的RESTAPI的良好实践是什么。一个简单的例子-学生,“拥有”一方: @Entity public class Student { private int id; private String name; private Set<Course> courses; ... @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)

我想知道创建、记录(炫耀)和公开涉及多对多关系的RESTAPI的良好实践是什么。一个简单的例子-
学生
,“拥有”一方:

@Entity
public class Student {

    private int id;
    private String name;
    private Set<Course> courses;

    ...
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    public Set<Course> getCourses() {
        return courses;
    }

    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }
    ...
}
这将产生3个DB表-学生、课程和关系表(H2/hibernate)。让我们找一个现有的学生:

GET /api/students/1 HTTP/1.1
...

{
  "id": 1,
  "name": "John Smith",
  "courses": [
    {
      "id": 2,
      "name": "Maths"
    },
    {
      "id": 1,
      "name": "Java Programming"
    }
  ]
}
好的。现在,我想创建一个具有POST请求的新学生,该学生已注册两个现有课程:

curl -X POST \
  http://localhost:8080/api/students \
  -H 'postman-token: 706c8d0e-eca5-7bff-c557-3e199e8a0c17' \
  -d '{
  "name": "Peter Brown",
  "courses": [
    {
      "id": 1,
      "name": "Maths"
    },
    {
      "id": 2,
      "name": "Java Programming"
    }
  ]
}'
在服务器端,这可能会触发映射方法,例如:

@ApiOperation("Creates a new student.")
@RequestMapping(method = RequestMethod.POST, 
    value = "/api/students",
    consumes = MediaType.APPLICATION_JSON_VALUE,
    produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Student> createStudent(@RequestBody Student student) {

    Student newStudent = studentRepository.save(student);

    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/api/students/{id}").buildAndExpand(newStudent.getId())
            .toUri();

    return ResponseEntity.created(location).body(newStudent);
}
@ApiOperation(“创建新学生”)
@RequestMapping(method=RequestMethod.POST,
value=“/api/students”,
consumes=MediaType.APPLICATION\u JSON\u值,
products=MediaType.APPLICATION\u JSON\u值)
公共响应创建学生(@RequestBody-Student){
学生新闻学生=studentRepository.save(学生);
URI位置=ServletUriComponentsBuilder.fromCurrentRequest()
.path(“/api/students/{id}”).buildAndExpand(newStudent.getId())
.toUri();
返回ResponseEntity.created(location).body(newStudent);
}
学生存储库是一个
crudepository

问题:这将触发以下错误:

传递给persist的分离实体:xxx.domain.Course;嵌套异常 是否将org.hibernate.PersistentObjectException:分离的实体传递给 持续:xxx.domain.Course

原因:现有球场上的ID-s(存在于DB中)使其“分离”。我应该如何处理这些情况

创建一个学生,然后通过REST更新? 用特殊的逻辑进入控制器? 通过更改级联类型

谢谢


更新:我已经按照公认答案中的建议将学生视为DTO,并且我还为课程介绍了一种补丁/获取方法。

我认为您应该将
@RequestBody学生
视为DTO(实际上是),不要直接保存,最好将其提取,创建实体或从存储库中检索实体,并构建最终的学生实体并将其保存到数据库。

我的猜测是,您必须在之前将学生实体保持为“空”,然后再进行更新。您的意思是我应该使用控制器(或服务)实现所有这些特殊处理?首先创建一个学生,然后创建或分配课程,然后在响应正文中返回最终对象?确切地说,但在只接受dto对象并返回您的学生对象的服务中,不要污染控制器。我将四处玩,看看这是否看起来很好(包括最后生成的招摇过市文档)。我添加了一些框架来实现这个逻辑,希望能有所帮助!代码不是很好,因为如果新学生注册到现有课程中,repo将抛出我在问题中引用的异常。相反,它应该首先创建一个空学生,然后用现有(或新)课程更新它。
@ApiOperation("Creates a new student.")
@RequestMapping(method = RequestMethod.POST, 
    value = "/api/students",
    consumes = MediaType.APPLICATION_JSON_VALUE,
    produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Student> createStudent(@RequestBody Student student) {

    Student newStudent = studentRepository.save(student);

    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/api/students/{id}").buildAndExpand(newStudent.getId())
            .toUri();

    return ResponseEntity.created(location).body(newStudent);
}