Spring 如何使用JpaRepository高效地更新
我有一个存储孩子列表的家长。当我更新子项(添加/编辑/删除)时,是否有方法根据外键自动决定删除或编辑哪个子项?或者我必须手动检查所有子项以查看哪些是新的或修改的 父类Spring 如何使用JpaRepository高效地更新,spring,postgresql,spring-data-jpa,sql-update,Spring,Postgresql,Spring Data Jpa,Sql Update,我有一个存储孩子列表的家长。当我更新子项(添加/编辑/删除)时,是否有方法根据外键自动决定删除或编辑哪个子项?或者我必须手动检查所有子项以查看哪些是新的或修改的 父类 @Entity @EntityListeners(PermitEntityListener.class) public class Permit extends Identifiable { @OneToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL, mappe
@Entity
@EntityListeners(PermitEntityListener.class)
public class Permit extends Identifiable {
@OneToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL, mappedBy = "permit")
private List<Coordinate> coordinates;
}
家长控制器
@PutMapping("")
public @ResponseBody ResponseEntity<?> update(@RequestBody Permit permit) {
logger.debug("update() with body {} of id {}", permit, permit.getId());
if (!repository.findById(permit.getId()).isPresent()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
Permit returnedEntity = repository.save(permit);
repository.flush();
return ResponseEntity.ok(returnedEntity);
}
@PutMapping(“”)
public@ResponseBody-ResponseEntity更新(@RequestBody-Permit-Permit){
debug(“id为{}的{}体的update(),permit,permit.getId());
如果(!repository.findById(permit.getId()).isPresent()){
返回ResponseEntity.status(HttpStatus.BAD_请求).body(null);
}
Permit returnedEntity=存储库.保存(Permit);
repository.flush();
return ResponseEntity.ok(returnedEntity);
}
=编辑=
控制器创建
@Override
@PostMapping("")
public @ResponseBody ResponseEntity<?> create(@RequestBody Permit permit) {
logger.debug("create() with body {}", permit);
if (permit == null || permit.getId() != null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
List<Coordinate> coordinates = permit.getCoordinates();
if (coordinates != null) {
for (int x = 0; x < coordinates.size(); ++x) {
Coordinate coordinate = coordinates.get(x);
coordinate.setPermit(permit);
}
}
Permit returnedEntity = repository.save(permit);
repository.flush();
return ResponseEntity.ok(returnedEntity);
}
@覆盖
@邮戳(“”)
public@ResponseBody ResponseEntity创建(@RequestBody-Permit-Permit){
debug(“create()和body{}”,permit);
if(permit==null | | permit.getId()!=null){
返回ResponseEntity.status(HttpStatus.BAD_请求).body(null);
}
列表坐标=permit.getCoordinates();
if(坐标!=null){
对于(int x=0;x
控制器更新
@PutMapping("")
public @ResponseBody ResponseEntity<?> update(@RequestBody Permit permit) {
logger.debug("update() with body {} of id {}", permit, permit.getId());
if (!repository.findById(permit.getId()).isPresent()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
List<Coordinate> repoCoordinate = coordinateRepository.findByPermitId(permit.getId());
List<Long> coordinateIds = new ArrayList<Long>();
for (Coordinate coordinate : permit.getCoordinates()) {
coordinate.setPermit(permit);
//if existing coordinate, save the ID in coordinateIds
if (coordinate.getId() != null) {
coordinateIds.add(coordinate.getId());
}
}
//loop through coordinate in repository to find which coordinate to remove
for (Coordinate coordinate : repoCoordinate) {
if (!(coordinateIds.contains(coordinate.getId()))) {
coordinateRepository.deleteById(coordinate.getId());
}
}
Permit returnedEntity = repository.save(permit);
repository.flush();
return ResponseEntity.ok(returnedEntity);
}
@PutMapping(“”)
public@ResponseBody-ResponseEntity更新(@RequestBody-Permit-Permit){
debug(“id为{}的{}体的update(),permit,permit.getId());
如果(!repository.findById(permit.getId()).isPresent()){
返回ResponseEntity.status(HttpStatus.BAD_请求).body(null);
}
List repocordinate=coordinatorepository.findByPermitId(permit.getId());
List coordinateds=new ArrayList();
对于(坐标:permit.getCoordinates()){
协调设置许可证(许可证);
//如果存在坐标,则将ID保存在CoordinateID中
if(coordinate.getId()!=null){
add(coordinate.getId());
}
}
//循环遍历存储库中的坐标,以查找要删除的坐标
用于(坐标:坐标){
if(!(coordinateIds.contains(coordinate.getId())){
CoordinatoreRepository.deleteById(coordinator.getId());
}
}
Permit returnedEntity=存储库.保存(Permit);
repository.flush();
return ResponseEntity.ok(returnedEntity);
}
我已经测试过了,它正在工作,没有简化的方法吗
我有一个存储孩子列表的家长
让我们为它编写DDL
TABLE parent (
id integer pk
)
TABLE child(
id integer pk
parent_id integer FOREIGN KEY (parent.id)
)
当我更新子项(添加/编辑/删除)时,是否有方法根据外键自动决定删除或编辑哪个子项
假设您有一个新的孩子5与父母2绑定,并且:
parent.getChilds()
都必须(!)返回在执行事务之前存在的所有实体,并返回刚刚提交到数据库的实体的同一实例
然后,如果删除父级2的子级5,并且事务成功执行parent。getChilds()
必须返回所有实体,而不返回子级5
特殊情况:
如果删除父#2,并且在DDL和Java代码中都有级联删除,则必须从数据库中删除所有子项以及刚刚删除的数据库中的父#2。在这种情况下,父#2不再绑定到jpa上下文,父#2的所有子项也不再绑定到jpa上下文
=编辑=
您可以使用merge
。这将适用于以下构造:
POST {
"coordinates": [{
"lat":"51.33",
"lon":"22.44"
},{
"lat":"50.22",
"lon":"22.33"
}]
}
它将在表“许可”中创建一行,在表“坐标”中创建两行,两个坐标都绑定到许可行。结果将包括设置的ID
但是:您必须进行验证工作(检查id是否为空,检查坐标是否未引用不同的许可证,…)
必须使用删除方法删除坐标:
DELETE /permit/972/coordinate/3826648305
你已经接近解决方案了。您唯一缺少的是一对多映射上的orphanRemovation=true:
@Entity
@EntityListeners(PermitEntityListener.class)
public class Permit extends Identifiable {
@OneToMany(mappedBy = "permit", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Coordinate> coordinates;
}
@实体
@EntityListeners(permitityListener.class)
公共类许可证{
@OneToMany(mappedBy=“permit”,cascade=CascadeType.ALL,orphan=true)
私人名单协调;
}
将映射标记为孤立删除将告诉基础ORM删除不再属于任何父实体的任何实体。由于从列表中删除了子元素,因此在保存父元素时将删除该子元素。
创建新元素和更新旧元素基于级联类型。因为您有CascadeType.com,所以在保存父实体时,列表中所有没有ID的元素都将保存到数据库并分配一个新ID,并且列表中所有已经有ID的元素都将更新
另一方面,您可能需要更新列表坐标的setter方法,使其看起来像:
public void setCoordinates(List<Coordinates> coordinates) {
this.coordinates = coordinates;
this.coordinates.forEach(coordinate -> coordinates.setPermit(this));
}
public void集合坐标(列表坐标){
这个。坐标=坐标;
this.coordinates.forEach(坐标->坐标.setPermit(this));
}
或者,如果使用JSON,只需使用@JsonManagedReference和@JsonBackReference。我想做的是更复杂的事情。。因为当用户修改记录时,他们可以添加新的子项、删除现有子项和编辑现有子项,
public void setCoordinates(List<Coordinates> coordinates) {
this.coordinates = coordinates;
this.coordinates.forEach(coordinate -> coordinates.setPermit(this));
}