JPA + Spring:在保留实体之前,根据接收到的值将外键列映射到ID

时间:2019-04-09 12:43:17

标签: java spring hibernate rest jpa

如果这是一个愚蠢的问题,请原谅,但是我对JPA和Spring非常陌生。 我想知道是否有人可以解决以下问题,因为我在StackOverflow和google上进行了大量搜索,但找不到用例的任何示例。可能是因为我不知道该关键字在JPA中被称为而缺少了关键字。

因此,基本上,我正在尝试开发REST API,以从数据库中检索记录或在数据库中插入记录,为此我有两个表,分别为CLIENT_MASTERTITLE

CLIENT_MASTER的架构如下所示,

CREATE TABLE CLIENT_MASTER (
   ID INT GENERATED BY DEFAULT AS IDENTITY(START WITH 1000),
   TITLE_ID INT,
   FIRST_NAME VARCHAR(255),
   MIDDLE_NAME VARCHAR(255),
   LAST_NAME VARCHAR(255),
   PRIMARY KEY (ID)
);

类似地,TITLE表的方案是

CREATE TABLE TITLE (
   ID INT GENERATED BY DEFAULT AS IDENTITY,
   TITLE VARCHAR(10),
   PRIMARY KEY (ID)
);

CLIENT_MASTER表具有以下外键约束

ALTER TABLE CLIENT_MASTER ADD CONSTRAINT TITLE_ID FOREIGN KEY (TITLE_ID) REFERENCES TITLE;

两个表的实体定义如下,

import java.io.Serializable;
...
import lombok.Setter;

@Entity
@Table(name = "CLIENT_MASTER")
@Getter
@Setter
public class ClientMaster implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", updatable = false, nullable = false)
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "TITLE_ID")
    private Title title;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "MIDDLE_NAME")
    private String middleName;

    @Column(name = "LAST_NAME")
    private String lastName;
}

import java.io.Serializable;
....
import lombok.Setter;

@Entity
@Table(name = "TITLE")
@Getter
@Setter
public class Title implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", updatable = false, nullable = false)
    private Integer id;

    @Column(name = "TITLE")
    private String title;
}

在我的rest控制器中,我要在下面插入新客户端

@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> create(@RequestBody ClientMaster cm) {
    cmrepository.create(cm);
    HttpHeaders headers = new HttpHeaders();
    ControllerLinkBuilder linkBuilder = linkTo(methodOn(CompanyController.class).get(cm.getId()));
    headers.setLocation(linkBuilder.toUri());
    return new ResponseEntity<>(headers, HttpStatus.CREATED);
}

其中cmrepository

的实例
@Repository
public class CMRepository {

@PersistenceContext
private EntityManager entityManager;

@Override
public void create(ClientMaster cm) {
    entityManager.persist(cm);

 }
}

我要在发布请求中发送以下json,我想要的是将标题值映射到TITLE表中的相应ID,并插入具有正确标题ID的记录。

{
    "title": {
        "title": "Mr"
    },
    "firstName": "XXX",
    "middleName": "YYY",
    "lastName": "ZZZ",
}

使用上述方法,当前行为是对于CLIENT_TABLE中的每个记录插入,在TITLE表中创建了一条我不想要的新记录。

任何人都可以为我指出正确的方向吗?

非常感谢。

3 个答案:

答案 0 :(得分:0)

持久性提供程序无法通过字段值本身自动假定id。

您必须:

  1. 首先通过Title获取title条目。
  2. 如果已提取title,请在ClientMaster上设置merge。否则将不进行任何操作,并允许级联保留该值。
  3. persist对象上使用ClientMaster代替cmrepository.merge(cm);

    .apply()

答案 1 :(得分:0)

我认为不插入它不是一个好主意,因为您已经定义了一个forgien键关系,对于标题表存储所有ID总是更好。

答案 2 :(得分:0)

谢谢你们

我遵循了Maciej的建议,现在我的控制器如下所示

@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> create(@RequestBody ClientMaster company) {
    //fetch and set title. 
    company.setTitle(titleService.get(company.getTitle().getTitle()));
    companyService.create(company);
    HttpHeaders headers = new HttpHeaders();
    ControllerLinkBuilder linkBuilder = linkTo(methodOn(CompanyController.class).get(company.getId()));
    headers.setLocation(linkBuilder.toUri());
    return new ResponseEntity<>(headers, HttpStatus.CREATED);
}