[英]spring data jpa: after update @many side table, can't get correct changes by findAll @one side table in the same method
I have a procedure entity, and a procedure contains a list of cards entity. 我有一个过程实体,并且一个过程包含一张卡实体列表。 Any card can be moved between procedures. 任何卡都可以在过程之间移动。 So now if I do a move (actually setProcedure of a card to another procedure), and immediately findAll() at the next line, it returns [] for both procedures. 因此,现在如果我进行移动(实际上是将卡的setProcedure移到另一个过程),并立即在下一行找到findAll(),则这两个过程都将返回[]。
tried using saveAndFlush() instead of save() before findAll() but doesn't work too. 尝试在findAll()之前使用saveAndFlush()而不是save(),但也无法正常工作。
entities: 实体:
@Entity
@Table(name = "procedures")
public class Procedure {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@OneToMany(mappedBy = "procedure", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonManagedReference
private List<Card> cards = new ArrayList<>();
//...getter setter constructor
}
@Entity
@Table(name = "cards")
public class Card {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@ManyToOne
@JsonBackReference
private Procedure procedure;
//...getter setter constructor
}
controller 控制者
@GetMapping("/card/move/{cid}/{nextPid}")
@Transactional
public List<Procedure> moveCard(@PathVariable Long cid, @PathVariable Long nextPid) {
return cardService.moveCard(cid, nextPid);
}
inside service 内部服务
List<Procedure> moveCard(Long cid, Long nextPid) {
Card card = cardRepository.findById(cid).get();
Procedure toProcedure = procedureService.findById(nextPid);
card.setIndex(toProcedure.getCards().size());
card.setProcedure(toProcedure);
cardRepository.saveAndFlush(card);
return procedureService.findAll();
}
eg if I have 1 card in procedure 1, after I call this api, it returns the following: 例如,如果在过程1中有1张卡,则在调用此api后,它将返回以下内容:
[
{
"id": 1,
"cards": [],
},
{
"id": 2,
"cards": [],
}
]
but I expect: 但我期望:
[
{
"id": 1,
"cards": [],
},
{
"id": 2,
"cards": [{id: 123}],
}
]
You have to maintain the other side of the relationship too. 您也必须保持关系的另一面。
Your code must look like: 您的代码必须如下所示:
List<Procedure> moveCard(Long cid, Long nextPid) {
Card card = cardRepository.findById(cid).get();
// Remove the card from the procedure
card.getProcedure().getCards().remove(card);
Procedure toProcedure = procedureService.findById(nextPid);
// Add it to the new procedure
toProcedure.getCards().add(card);
card.setIndex(toProcedure.getCards().size());
card.setProcedure(toProcedure);
cardRepository.saveAndFlush(card);
return procedureService.findAll();
}
As hinted at elsewhere where a relationship is bidirectional then it is up to you to maintain both sides. 正如在其他关系是双向关系的地方所暗示的,则取决于您是保持双方。
You should so this by encapsulating the operations to modify the collection in order to guarantee that the in-memory model is always consistent. 您应该通过封装修改集合的操作来做到这一点,以确保内存模型始终保持一致。
public class Procedure{
public Set<Card> cards; // or list
public void addCard(Card Card){
card.getProcedure().removeCard(card);
this.cards.add(card);
card.setProcedure(this);
{
public void removeCard(Card card){
cards.remove(card);
card.setProedure(null);
}
public Set<Card> getCards(){
//force client code to use add/remove operations
//to ensure in-memory model **always** consistent
return Collections.unmodifiableSet(cards); // or list
}
}
Think in terms of aggregate roots ( https://www.baeldung.com/spring-persisting-ddd-aggregates ) and work with Procedure: 根据聚合根( https://www.baeldung.com/spring-persisting-ddd-aggregates )进行思考,并使用Procedure:
void moveCard(Long cid, Long nextPid) {
Card card = cardRepository.findById(cid).get();
Procedure fromProcedure = card.getProcedure();
Procedure toProcedure = procedureService.findById(nextPid);
formProcedure.removeCard(card);
toProcedure.addcard(card);
card.setIndex(toProcedure.getCards().size()); ??
//if method is executed in transaction then no need to call saveAndFlush
//the following 2 lines can be removed.
cardRepository.saveAndFlush(fromProcedure);
cardRepository.saveAndFlush(toProcedure);
}
This is what worked for me, the only change was removing and adding in the procedures from/to and you don't need to flush the changes straight as well: 这是对我有用的方法,唯一的更改是从/到过程中删除和添加了过程,您也不需要直接刷新更改:
@Transactional
List<Procedure> moveCard(Long cid, Long nextPid) {
Card card = cardRepository.findById(cid).get();
Procedure toProcedure = procedureService.findById(nextPid);
Procedure fromProcedure = card.getProcedure();
//this keeps the object in memory updated and returned by findAll after
fromProcedure.getCards().remove(card);
toProcedure.getCards().add(card);
card.setIndex(toProcedure.getCards().size());
card.setProcedure(toProcedure);
cardRepository.save(card);
return procedureService.findAll();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.