Spring Data,REST和ManyToMany关系

时间:2017-05-17 12:19:21

标签: java spring rest spring-boot spring-data

我想知道创建,记录(swagger)和暴露涉及多对多关系的REST API的好习惯是什么。一个简单的例子 - Student,拥有'侧:

@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;
    }
    ...
}

Course(学生们甚至没有曝光):

@Entity
public class Course {

    private int id;
    private String name;
    ...
}

这导致3个DB表 - 学生,课程和关系表(H2 /休眠)。让我们找一个现有的学生:

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);
}

学生资料库是CrudRepository

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

  

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

原因:现有课程的ID-s(它们存在于DB中)使得他们&#34;分离&#34;。我该如何处理这些情况?

通过创建学生并稍后通过REST更新它? 有一个特殊的逻辑进入控制器? 通过更改CascadeType

谢谢!

更新:我已按照接受的答案建议将学生视为DTO,并且我还为课程介绍了PATCH / GET方法。

1 个答案:

答案 0 :(得分:2)

我相信您应该将<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <center> <p>REGISTRATION</p> <form method="post"> <h1>Add Student</h1> <table cellpadding="2"> <tr> <td align="right">Student Name</td> <td align="left"><input type="text" id="studentName" name="studentName" size="32" required></td> </tr> <tr> <td align="right">Contact No</td> <td align="left"><input type="number" name="contactNo" id="Contact" size="32" maxlength="10" required></td> </tr> <tr> <td align="right">Gender</td> <td align="left"> <input type="radio" name="gender" value="Male" checked>Male <input type="radio" name="gender" value="Female">Female </td> </tr> <tr> <td align="right">Email Id</td> <td align="left"> <input type="email" title="Enter valid acharya email" pattern="[a-zA-Z]+\. [a-zA-Z]+\.([0-9][1-9]|[1-9][0-9])@acharya\.ac\.in" id="email" size="32" required> </td> </tr> <tr> <td align="right">Address Line</td> <td align="left"><textarea placeholder="Your Address Here..." rows="5" cols="100"></textarea></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="Add" id="btn" onclick="validate()" /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="button" value="Reset" id="btn" /> </td> </tr> </table> </form> </center>视为dto(它实际上是)不直接保存它,更好地提取它,创建实体或从存储库中检索它们并构建最终的Student实体并保存它到数据库。