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.
tried using saveAndFlush() instead of save() before findAll() but doesn't work too.
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:
[
{
"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:
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();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.