Java JPA&x2B;Spring:根据在持久化实体之前接收到的值将外键列映射到ID
请原谅,如果这是一个愚蠢的问题,但我是非常新的JPA和春天。 我想知道是否有人可以帮助解决以下问题,因为我在StackOverflow和google上做了很多搜索,但找不到我的用例的任何示例。这可能是因为我缺少关键字,因为我不知道这种映射在JPA中被称为什么 因此,基本上,我正在尝试开发一个RESTAPI来从数据库中检索和插入一条记录,我有两个表,即Java JPA&x2B;Spring:根据在持久化实体之前接收到的值将外键列映射到ID,java,spring,hibernate,rest,jpa,Java,Spring,Hibernate,Rest,Jpa,请原谅,如果这是一个愚蠢的问题,但我是非常新的JPA和春天。 我想知道是否有人可以帮助解决以下问题,因为我在StackOverflow和google上做了很多搜索,但找不到我的用例的任何示例。这可能是因为我缺少关键字,因为我不知道这种映射在JPA中被称为什么 因此,基本上,我正在尝试开发一个RESTAPI来从数据库中检索和插入一条记录,我有两个表,即CLIENT\u MASTER和TITLE CLIENT\u MASTER的架构如下所示 CREATE TABLE CLIENT_MASTER (
CLIENT\u MASTER
和TITLE
CLIENT\u 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)
);
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;
}
类似地,标题
表的方案为
CREATE TABLE TITLE (
ID INT GENERATED BY DEFAULT AS IDENTITY,
TITLE VARCHAR(10),
PRIMARY KEY (ID)
);
CLIENT\u MASTER
表具有以下外键约束
ALTER TABLE CLIENT_MASTER ADD CONSTRAINT TITLE_ID FOREIGN KEY (TITLE_ID) REFERENCES TITLE;
两个表的实体定义如下:
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)
);
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);
}
我在post请求中发送了下面的json,我想要的是将标题值映射到title
表中相应的id,并插入具有正确标题id的记录
{
"title": {
"title": "Mr"
},
"firstName": "XXX",
"middleName": "YYY",
"lastName": "ZZZ",
}
如上所述,当前的行为是,对于在CLIENT_表
中插入的每个记录,在TITLE
表中创建一个新记录,这不是我想要的
有谁能为我指出正确的方向,如何实现这一目标
非常感谢。持久性提供程序无法通过字段值本身自动假定id 你必须:
标题
获取标题
项ClientMaster
,则在ClientMaster
上设置title
。。不执行其他操作,并允许级联保持该值ClientMaster
对象上使用merge
而不是persist
:
cmrepository.merge(cm)代码>
我不认为不插入它是个好主意,因为您已经定义了forgien键关系,所以标题表最好存储所有ID。谢谢大家 我听从了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);
}
@RequestMapping(method=RequestMethod.POST,products=MediaType.APPLICATION\u JSON\u值)
@ResponseStatus(值=HttpStatus.OK)
公共响应创建(@RequestBody ClientMaster company){
//获取并设置标题。
company.setTitle(titleService.get(company.getTitle().getTitle());
创建(公司);
HttpHeaders=新的HttpHeaders();
ControllerLinkBuilder linkBuilder=linkTo(methodOn(CompanyController.class).get(company.getId());
headers.setLocation(linkBuilder.toUri());
返回新的ResponseEntity(标题,HttpStatus.CREATED);
}
而不是CascadeType。请尝试将其仅设置为MERGE@vc73不幸的是,将CascadeType
更改为MERGE
无效。为什么MERGE
apersist
即使使用现有的引用对象也可以正常工作。如果获取标题实体。。在持久化之前,它将处于分离状态。如果您试图持久化一个分离的实体(通过这里的级联),您将得到一个异常,除非在控制器级别设置了事务。但是我们不知道,谢谢大家,我已经在下面发布了我的答案。很抱歉,我无法将此答案标记为有用,因为我还没有足够的声誉。不,只有预定义的标题集在创建表后初始化。如果请求中的标题与任何现有标题不匹配,则最终用户将无法在客户机主表中插入任何记录。这基本上是一项要求。