JPA + Spring:根据持久化实体之前收到的值将外键列映射到 ID



如果这是一个愚蠢的问题,请原谅我,但我对JPA和Spring非常陌生。 我想知道是否有人可以帮助解决以下问题,因为我在 StackOverflow 和谷歌上进行了大量搜索,但找不到我的用例的任何示例。可能是我错过了关键字,因为我不知道这种映射在 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);
}
}

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

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

如上所述,当前的行为是,对于CLIENT_TABLE中的每个记录插入,TITLE表中都会创建一个新记录,这不是我想要的。

谁能指出我正确的方向,如何实现这一目标?

非常感谢。

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

您必须:

  1. 首先通过title获取Title条目。
  2. 如果ClientMaster读取了title,则将其设置为"..."不执行任何其他操作,并允许级联保留该值。
  3. ClientMaster对象使用merge而不是persist

    cmrepository.merge(cm);

谢谢你们

我遵循了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);
}

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

最新更新