Java 使用Spring REST更新OneToMany关系

Java 使用Spring REST更新OneToMany关系,java,hibernate,rest,spring-mvc,jpa,Java,Hibernate,Rest,Spring Mvc,Jpa,我的问题是,我在实体任务和实体用户(作者)之间有一种双向的一对一关系。这是在使用SpringREST和SpringDataJPA的SpringBoot项目中实现的。如果我通过POST请求创建一个用户,它可以正常工作。如果我创建一个没有作者(用户)实例的任务,情况也是如此。我可以毫不费力地创造它。之后,我尝试通过执行PUT来使用用户实例更新任务的作者。网络服务的答案是200行。我在数据库中还有一个条目,用户id位于任务表的author列中。但是当我执行一个GET请求来获取所有用户或任务时,什么都不

我的问题是,我在实体任务和实体用户(作者)之间有一种双向的一对一关系。这是在使用SpringREST和SpringDataJPA的SpringBoot项目中实现的。如果我通过POST请求创建一个用户,它可以正常工作。如果我创建一个没有作者(用户)实例的任务,情况也是如此。我可以毫不费力地创造它。之后,我尝试通过执行PUT来使用用户实例更新任务的作者。网络服务的答案是200行。我在数据库中还有一个条目,用户id位于任务表的author列中。但是当我执行一个GET请求来获取所有用户或任务时,什么都不起作用了。邮递员只显示坏数组之类的东西。我不知道为什么。如果我删除数据库中的任务,一切都会恢复正常。有人知道为什么吗? 以下是课程:

@Entity
@Table(name="User")
public class User {
@Id
@GeneratedValue
@Column(name="USER_ID")
private Long id;

@Column(name="CONFIRMATION")
private boolean confirmed;

@Column(name = "EMAIL",nullable = false)
private String email;

@Column(name = "USERNAME",nullable = false)
@NotNull
private String userName;

@Column(name="PASSWORD",nullable = false)
@NotNull
private String password;

@Column(name="TIMESTAMP")
private Long creationTime;

@OneToMany(cascade=CascadeType.ALL, mappedBy="author",fetch=FetchType.EAGER)
private Set<Task>assignedTasks;

@OneToMany(cascade=CascadeType.ALL, mappedBy="assignee",fetch=FetchType.EAGER) 
private Set<Task>createdTasks;


public User() {
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}



public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public Long getCreationTime() {
    return creationTime;
}

public void setCreationTime(Long creationTime) {
    this.creationTime = creationTime;
}

public boolean isConfirmed() {
    return confirmed;
}

public void setConfirmed(boolean confirmed) {
    this.confirmed = confirmed;
}

public Set<Task> getAssignedTasks() {
    return assignedTasks;
}

public void setAssignedTasks(Set<Task> assignedTasks) {
    this.assignedTasks = assignedTasks;
}

public void addAssignedTasks(Task task){
    addAssignedTasks(task,true);
}

void addAssignedTasks(Task task, boolean set){
    if(task != null){
        getAssignedTasks().add(task);
        if(set){
            task.setAssignee(this);
        }
    }
}

public Set<Task> getCreatedTasks() {
    return createdTasks;
}

public void setCreatedTasks(Set<Task> createdTasks) {
    this.createdTasks = createdTasks;
}

public void addCreatedTask(Task task){
    addCreatedTask(task,true);
}

void addCreatedTask(Task task, boolean set){
    if(task != null){
        getCreatedTasks().add(task);
        if(set){
            task.setAuthor(this);
        }
    }
}

public void removeCreatedTask(Task task) {
    getCreatedTasks().remove(task);
    task.setAuthor(null);
}  
@实体
@表(name=“User”)
公共类用户{
@身份证
@生成值
@列(name=“USER\u ID”)
私人长id;
@列(name=“确认”)
私有布尔确认;
@列(name=“EMAIL”,nullable=false)
私人字符串电子邮件;
@列(name=“USERNAME”,null=false)
@NotNull
私有字符串用户名;
@列(name=“PASSWORD”,null=false)
@NotNull
私有字符串密码;
@列(name=“TIMESTAMP”)
私人创作时间长;
@OneToMany(cascade=CascadeType.ALL,mappedBy=“author”,fetch=FetchType.EAGER)
私有设置任务;
@OneToMany(cascade=CascadeType.ALL,mappedBy=“受让人”,fetch=FetchType.EAGER)
私有SetcreatedTasks;
公共用户(){
}
公共长getId(){
返回id;
}
公共无效集合id(长id){
this.id=id;
}
公共字符串getEmail(){
回复邮件;
}
公用电子邮件(字符串电子邮件){
this.email=电子邮件;
}
公共字符串getUserName(){
返回用户名;
}
public void setUserName(字符串用户名){
this.userName=用户名;
}
公共字符串getPassword(){
返回密码;
}
public void setPassword(字符串密码){
this.password=密码;
}
公共长getCreationTime(){
返回creationTime;
}
public void setCreationTime(长creationTime){
this.creationTime=creationTime;
}
公共布尔值已确认(){
返回确认;
}
公共无效设置已确认(布尔值已确认){
这个.已确认的=已确认的;
}
公共集getAssignedTasks(){
返回分配的任务;
}
公共无效setAssignedTasks(设置assignedTasks){
this.assignedTasks=assignedTasks;
}
public void addassignedtask(任务任务){
addAssignedTasks(任务,true);
}
void addassignedtask(任务任务,布尔集合){
如果(任务!=null){
getAssignedTasks().add(任务);
如果(设置){
任务.setAssignee(本);
}
}
}
公共集getCreatedTasks(){
返回createdTasks;
}
公共void setCreatedTasks(Set createdTasks){
this.createdTasks=createdTasks;
}
公共void addCreatedTask(任务){
addCreatedTask(任务,true);
}
void addCreatedTask(任务任务,布尔集合){
如果(任务!=null){
getCreatedTasks().add(任务);
如果(设置){
task.setAuthor(this);
}
}
}
public void removeCreatedTask(任务任务){
getCreatedTasks().remove(任务);
task.setAuthor(null);
}  
}

然后,任务实体:

@Entity
@Table(name="Task")
public class Task {


@Id
@GeneratedValue
@Column(name="TASK_ID")
private Long id;

@Transient
private List<String> possibleTaskTypes = TaskType.getTaskTypesAsString();

@Transient 
private List<String>possibleTaskContainer = TaskContainer.getTaskContainerAsString();

@Column(name="TASK_Container")
private String taskContainer;

@Column(name="TASK_TYPE")
private String taskType;

@Column(name="HEAD_LINE")
private String headLine;

@Column(name="TASK_TEXT")
private String taskText;

@Transient
private List<String> possibleworkFlowStati = WorkFlowStatus.getWorkFlowsStatiAsString();

@Column(name="WORKFLOW_STATUS")
private String status;

@ManyToOne(cascade=CascadeType.ALL)
private User author;

@ManyToOne(cascade=CascadeType.ALL)
private User assignee;

@Column(name="COMMENTS")
@ElementCollection(targetClass=String.class)
private List<String>comments;

@ManyToOne(cascade=CascadeType.ALL)
private Sprint sprint;

@Column(name="TIMESTAMP")
private Long creationTime;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getHeadLine() {
    return headLine;
}

public void setHeadLine(String headLine) {
    this.headLine = headLine;
}

public String getTaskText() {
    return taskText;
}

public void setTaskText(String taskText) {
    this.taskText = taskText;
}

public User getAuthor() {
    return author;
}

public void setAuthor(User author) {
    setAuthor(author, true);
}

void setAuthor(User author, boolean add){
    this.author = author;
    if(author !=null&&add){
        author.addCreatedTask(this, false);
    }
}

public User getAssignee() {
    return assignee;
}

public void setAssignee(User assignee) {
    setAssignee(assignee,true);
}

void setAssignee(User assignee, boolean add){
    this.assignee = assignee;
    if(assignee != null && add){
        assignee.addAssignedTasks(this,false);
    }
}

public List<String> getComments() {
    return comments;
}

public void setComments(List<String> comments) {
    this.comments = comments;
}

public Sprint getSprint() {
    return sprint;
}

public void setSprint(Sprint sprint) {
    this.sprint = sprint;
}

public Long getCreationTime() {
    return creationTime;
}

public void setCreationTime(Long creationTime) {
    this.creationTime = creationTime;
}

public String getTaskType() {
    return taskType;
}

public void setTaskType(String taskType) {
    this.taskType = taskType;
}

public List<String> getPossibleTaskTypes() {
    return possibleTaskTypes;
}

public void setPossibleTaskTypes(List<String> possibleTaskTypes) {
    this.possibleTaskTypes = possibleTaskTypes;
}

public List<String> getPossibleworkFlowStati() {
    return possibleworkFlowStati;
}

public void setPossibleworkFlowStati(List<String> possibleworkFlowStati) {
    this.possibleworkFlowStati = possibleworkFlowStati;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

public List<String> getPossibleTaskContainer() {
    return possibleTaskContainer;
}

public void setPossibleTaskContainer(List<String> possibleTaskContainer) {
    this.possibleTaskContainer = possibleTaskContainer;
}

public String getTaskContainer() {
    return taskContainer;
}

public void setTaskContainer(String taskContainer) {
    this.taskContainer = taskContainer;
}




}
@实体
@表(name=“Task”)
公开课任务{
@身份证
@生成值
@列(name=“TASK\u ID”)
私人长id;
@短暂的
私有列表possibleTaskTypes=TaskType.gettaskTypesString();
@短暂的
private ListpossibleTaskContainer=TaskContainer.getTaskContainerAsString();
@列(name=“TASK\u Container”)
私有字符串容器;
@列(name=“任务类型”)
私有字符串任务类型;
@列(name=“HEAD\u LINE”)
私有字符串标题;
@列(name=“TASK\u TEXT”)
私有字符串文本;
@短暂的
private List possibleworkFlowStati=WorkFlowStatus.GetWorkflowStatiaString();
@列(name=“工作流状态”)
私有字符串状态;
@多通(级联=级联类型.ALL)
私人用户作者;
@多通(级联=级联类型.ALL)
私人用户受让人;
@列(name=“COMMENTS”)
@ElementCollection(targetClass=String.class)
私人意见;
@多通(级联=级联类型.ALL)
私人短跑;
@列(name=“TIMESTAMP”)
私人创作时间长;
公共长getId(){
返回id;
}
公共无效集合id(长id){
this.id=id;
}
公共字符串getHeadLine(){
返回标题;
}
公共无效设置标题(字符串标题){
this.headLine=标题;
}
公共字符串getTaskText(){
返回任务文本;
}
public void setTaskText(字符串taskText){
this.taskText=taskText;
}
公共用户getAuthor(){
返回作者;
}
public void setAuthor(用户作者){
setAuthor(author,true);
}
void setAuthor(用户作者,布尔添加){
this.author=作者;
if(author!=null&&add){
author.addCreatedTask(此项为false);
}
}
公共用户getAssignment(){
返还受让人;
}
公共受让人(用户受让人){
设定受让人(受让人,真实);
}
void setassignment(用户受让人,布尔添加){
该受让人=受让人;
if(受让人!=null&&add){
受让人。addAssignedTasks(此项为假);
}
}
公共列表getComments(){
返回评论;
}
公共注释(列出注释){
this.comments=注释;
}
公共Sprint getSprint(){
返回短跑;
}
公共空白设置打印(Sprint-Sprint){
this.sprint=sprint;
}
公共长getCreationTime(){
返回creationTime;
}
public void setCreationTime(长creationTime){
this.creationTime=creationTime;
}
公共字符串getTaskType(){
返回任务类型;
}
公共void setTaskType(字符串taskType){
this.taskType=taskType;
}
公共列表getPossibleTaskTypes(){
返回可能的任务类型;
}
公共void setPossibleTaskTypes(列出possibleTaskTypes){
this.possibleTaskTypes=possibleTaskTypes;
}
公共列表getPossibleworkFlowStati(){
返回可能的Workflowstati;
}
public void setPossibleworkFlowStati(列表possibleworkFlowStati){
this.possibleworkFlowStati=possibleworkFlow
@RestController
@RequestMapping("/v1/")
@Api(value = "tasks", description = "V1 - Tasks API")
public class TaskController {

private final Logger logger = LoggerFactory.getLogger(TaskController.class);
private TaskRepository taskRepository;
private UserRepository userRepository;

@Autowired
public TaskController(TaskRepository taskRepository, UserRepository userRepository){
    this.taskRepository = taskRepository;
    this.userRepository = userRepository;

}

protected void verifyTaskById(Long id) throws ResourceNotFoundException{
    Task task = taskRepository.findOne(id);
    if(task == null){
        throw new ResourceNotFoundException("Task with ID:"+id+" not found."); 
    }
}
/**
 * <b>POST</b> v1/tasks/
 * @param task
 * @return
 */
@RequestMapping(value="tasks", method=RequestMethod.POST)
@ApiOperation(value = "Creates a new Task", notes="The newly created Task Id will be sent in the location response header", 
response = Void.class)
@ApiResponses(value = {@ApiResponse(code=201, message="Task Created Successfully", response=Void.class), @ApiResponse(code=500, message="Error creating Task", response=ErrorDetail.class) } )
public ResponseEntity<?> createTask(@Valid @RequestBody Task task){
    logger.info(task.toString());
    task.setCreationTime(new Date().getTime());

    task = taskRepository.save(task);
    HttpHeaders responseHeaders = new HttpHeaders();

    URI newTaskUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(task.getId()).toUri();
    responseHeaders.setLocation(newTaskUri);

    return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
}

/**
 * <b>GET</b> v1/tasks/
 * @return
 */
@RequestMapping(value = "tasks", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves all the tasks", response=Task.class, responseContainer="List")
public ResponseEntity<Page<Task>> listAllTasks(Pageable pageable){
    logger.info("Receiving get-Tasks Request..");
    Page<Task> allTasks = taskRepository.findAll(pageable);
    return new ResponseEntity<>(allTasks,HttpStatus.OK);
}

/**
 * <b>GET</b> v1/tasks/{id}
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves given Task", response=Task.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Task.class),  @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> getSingleTask(@PathVariable(value="id") Long id){
    logger.info("Receiving get Task-Request for ID: "+ id);
    verifyTaskById(id);
    Task task = taskRepository.findOne(id);
    return new ResponseEntity<>(task,HttpStatus.OK);
}

/**
 * <b>PUT</b> v1/tasks/{id}
 * @param task
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "Updates given Task", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> updateTask(@RequestBody Task task, @PathVariable(value="id") Long id) {
    logger.info("Receiving put Task Request for "+id);
    verifyTaskById(id);
    if(!isIdInBodyCorrect(task, id)){
        task.setId(id);
    }

    if(task.getAuthor() != null)userRepository.save(task.getAuthor());
    if(task.getAssignee()!=null)userRepository.save(task.getAssignee());
    Task t = taskRepository.save(task);

    return new ResponseEntity<>(HttpStatus.OK);
}

/**
 * <b>DELETE</b> v1/tasks/{id}
 * 
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.DELETE)
@ApiOperation(value = "Deletes given Task", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> deleteTask(@PathVariable (value="id") Long id) {
    verifyTaskById(id);
    taskRepository.delete(id);
    return new ResponseEntity<>(HttpStatus.OK);
}

protected boolean isIdInBodyCorrect(Task task, Long id){
    if(task.getId() != id){
        logger.warn("Id in Body wasn't defined or wrong. ");  //TODO Exception werfen. 
        return false;
    }else{
        return true;
    }
}

}
@RestController
@RequestMapping("/v1/")
@Api(value = "users", description = "V1 - Users API")
public class UserController {

private final Logger logger = LoggerFactory.getLogger(UserController.class);

private UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository ){
    this.userRepository = userRepository;
}
/**
 * Checks wether the user exists. If not it throws a {@link ResourceNotFoundException}.
 * @param id
 * @throws ResourceNotFoundException
 */
protected void verifyUserById(Long id) throws ResourceNotFoundException{
    User user = userRepository.findOne(id);
    if(user==null){
        throw new ResourceNotFoundException("User with ID:"+id+" not found.");
    }
}
/**
 * <b>POST</b> v1/users/
 * @param user
 * @return
 */
@RequestMapping(value="users", method=RequestMethod.POST)
@ApiOperation(value = "Creates a new User", notes="The newly created user Id will be sent in the location response header", 
response = Void.class)
@ApiResponses(value = {@ApiResponse(code=201, message="User Created Successfully", response=Void.class), @ApiResponse(code=500, message="Error creating User", response=ErrorDetail.class) } )
public ResponseEntity<?> createUser(@Valid @RequestBody User user) {
    user.setCreationTime(new Date().getTime());
    user = userRepository.save(user);

    // Set the location header for the newly created resource
    HttpHeaders responseHeaders = new HttpHeaders();
    URI newUserUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(user.getId()).toUri();
    responseHeaders.setLocation(newUserUri);

    return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
}
/**
 * <b>GET</b> v1/users/
 * @return
 */
@RequestMapping(value = "users", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves all the users", response=User.class, responseContainer="List")
public ResponseEntity<Page<User>> listAllUsers(Pageable pageable){
    Page<User> allUsers = userRepository.findAll(pageable);
    return new ResponseEntity<>(allUsers,HttpStatus.OK);
}

/**
 * <b>GET</b> v1/users/{id}
 * @param id
 * @return
 */
@RequestMapping(value = "users/{id}", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves given User", response=User.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=User.class),  @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> getSingleUser(@PathVariable(value="id") Long id){
    verifyUserById(id);
    User user = userRepository.findOne(id);
    return new ResponseEntity<>(user,HttpStatus.OK);
}
/**
 * <b>PUT</b> v1/users/{id}
 * @param user
 * @param id
 * @return
 */
@RequestMapping(value = "users/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "Updates given User", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> updateUser(@RequestBody User user, @PathVariable (value="id") Long id) {
    verifyUserById(id);
    // Save the entity
    if(!isIdInBodyCorrect(user,id)){
        user.setId(id);
    }
    User u = userRepository.findOne(id);
    userRepository.save(user);
    return new ResponseEntity<>(HttpStatus.OK);
}

/**
 * <b>DELETE</b> v1/users/{id}
 * @param id
 * @return
 */
@RequestMapping(value="users/{id}", method=RequestMethod.DELETE)
@ApiOperation(value = "Deletes given User", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> deleteUser(@PathVariable (value="id") Long id) {
    verifyUserById(id);
    userRepository.delete(id);
    return new ResponseEntity<>(HttpStatus.OK);
}

protected boolean isIdInBodyCorrect(User user, Long id){
    if(user.getId() != id){
        logger.warn("Id in Body wasn't defined or wrong. ");  //TODO Exception werfen. 
        return false;
    }else{
        return true;
    }
}



}
@Entity
@Table(name = "TABLENAME")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class ... {