如何使用@ResponseBody创建jpa实体加入关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用@ResponseBody创建jpa实体加入关系相关的知识,希望对你有一定的参考价值。

我有两个实体成员,部门。会员必须在一个部门。

public class Member {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private String number;

  @NonNull
  @Column(nullable=false)
  private String name;

  @ManyToOne
  @JoinColumn(name="department_number")
  @NonNull
  @JsonIdentityReference
  private Department department;
}

public class Department {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int department_number;

  @NonNull
  @Column(nullable=false, unique=true)
  private String name;


  @OneToMany(mappedBy="department")
  @JsonBackReference
  private List<Member> members;
}

而我在控制器中的方法是这样的

@RequestMapping(method=RequestMethod.POST, path="/member/")
public ResponseEntity<Member> 
        createMember(@RequestBody Member member) {

  return new ResponseEntity<Member>(
              memberRepository.save(member)
              , HttpStatus.OK);
}

当我试试这个

POST localhost:8080/member/
{
    "name": "test",
    "department": {
        "name": "human resource"
    }
}

我收到这个错误

"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.dao.InvalidDataAccessApiUsageException",
"message": "org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : rura6502.tistory.com.domain.Member.department -> rura6502.tistory.com.domain.Department; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : rura6502.tistory.com.domain.Member.department -> rura6502.tistory.com.domain.Department",
"path": "/member/"

因为部门参数我知道这个错误。没有department_number(@Id),实体无法识别“人力资源”。我必须要求这个结构

{
  "name": "test",
  "department": {
    "name": "human resource",
    "department_number": 1
  }
}

有没有办法用我的结构创建成员?(没有department_number结构.department.name也是唯一的)

答案

您必须在父集合中使用cascade=CascadeType.ALL来指示hibernate也保存您的孩子。

@ManyToOne
@JoinColumn(cascade=CascadeType.ALL, name="department_number")
@NonNull
@JsonIdentityReference
private Department department;

如果您将使用双向关系,则还必须在子集合中指定级联类型。

您可能还需要修复IdMember

另一答案

成员对象之前需要部门对象。所以可以试试这个:

@RequestMapping(method= RequestMethod.POST, path="/member")
public ResponseEntity<Member> createMember(@RequestBody Member member) {

    // Get department name from json
    String deptName = member.getDepartment().getName();

    Department department = null;

    //check if dept already exists
    Department alreadyExistsDepartment = departmentRepository.findByName(deptName);

    if(alreadyExistsDepartment == null){
        Department department1 = new Department();
        department1.setName(deptName);
        department = departmentRepository.save(department1);
    } else{
        department = alreadyExistsDepartment;
    }

    member.setDepartment(department);
    memberRepository.save (member);

   //other code here
}

这是为实体类建模的正确方法:

member.Java

@Entity
public class Member {

  @Id
  @GeneratedValue(strategy= GenerationType.AUTO)
  private Long memberId;

  @NonNull
  @Column(nullable=false)
  private String name;

  @ManyToOne
  @JoinColumn(name="department_id")
  private Department department;

  // getters and setters
}

department.Java

@Entity
public class Department {

  @Id
  @GeneratedValue(strategy= GenerationType.AUTO)
  private Long departmentId;

  @NonNull
  @Column(nullable=false, unique=true)
  private String name;


  @OneToMany(mappedBy="department")
  @JsonBackReference
  private List<Member> members;
  // getters and setters
}

department repository.Java

@Repository
public interface DepartmentRepository extends JpaRepository<Department, Long> {

   Department findByName(String name);

}

以上是关于如何使用@ResponseBody创建jpa实体加入关系的主要内容,如果未能解决你的问题,请参考以下文章

jpa 实体bean中如何定义非映射字段

如何阻止 eclipse 从表中自动创建 JPA 实体?

netbeans如何通过数据库创建实体类

JPA,如何使用同一个类(实体)来映射不同的表?

如何克隆 JPA 实体

如何使用 JPA Criteria API 连接不相关的实体