我有一个家长,其中存储了孩子的清单。当我更新子项(添加/编辑/删除)时,是否有一种方法可以根据外键自动确定要删除或编辑的子项?还是我必须手动检查所有孩子以查看哪些是新的或修改的?
父母阶级
@Entity
@EntityListeners(PermitEntityListener.class)
public class Permit extends Identifiable {
@OneToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL, mappedBy = "permit")
private List<Coordinate> coordinates;
}
儿童班
@Entity
public class Coordinate extends Identifiable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "permit_id", referencedColumnName = "id")
private Permit permit;
private double lat;
private double lon;
}
父母的控制人
@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);
}
= EDIT =
创建控制器
@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);
}
控制器更新
@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);
}
我已经测试过并且可以正常工作,没有简化的方法吗?
答案 0 :(得分:2)
您已接近解决方案。您唯一缺少的是一对多映射上的orphanRemoval = true:
@Entity
@EntityListeners(PermitEntityListener.class)
public class Permit extends Identifiable {
@OneToMany(mappedBy = "permit", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Coordinate> coordinates;
}
对映射进行标记以删除孤立对象将告诉基础ORM删除不再属于任何父实体的任何实体。由于已从列表中删除了子元素,因此在保存父元素时将删除该子元素。 创建新元素并更新旧元素是基于CascadeType的。由于具有CascadeType.ALL,因此在保存父实体时,列表中所有没有ID的元素都将保存到数据库中并分配新的ID,并且列表中已经存在并具有ID的所有元素都将被更新。 / p>
另一方面,您可能需要更新setter方法以使List坐标看起来像这样:
public void setCoordinates(List<Coordinates> coordinates) {
this.coordinates = coordinates;
this.coordinates.forEach(coordinate -> coordinates.setPermit(this));
}
或者,如果要使用JSON,则只需使用@JsonManagedReference和@JsonBackReference。
答案 1 :(得分:0)
我有一个家长,其中存储了孩子的清单。
让我们为其编写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"
}]
}
它将在表“ permit”中创建一行,并在表“ coordinate”中创建两行,这两个坐标都绑定到许可行。结果将包括设置的ID。
但是:您将必须进行验证工作(检查id是否为null,检查坐标是否未引用其他许可,...)!
必须使用DELETE方法删除坐标:
DELETE /permit/972/coordinate/3826648305