简体   繁体   English

spring数据jpa:更新@许多边表后,无法以相同方法通过findAll @one边表获得正确的更改

[英]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.

相关问题 Spring Data JPA findAll与介于两者之间的表(PropertyReferenceException) - Spring Data JPA findAll with table in between (PropertyReferenceException) Spring JPA多对多:删除实体,删除连接表中的条目,但不删除另一方 - Spring JPA Many to Many: remove entity, remove entry in join table, BUT NOT REMOVE the other side Spring Data JPA一对多关系不保存子表 - Spring Data JPA One to Many relationship not saving child table Spring Data JPA不会一对多填充子表 - Spring Data JPA not populating child table in one to many JPA多对一:删除一对多方面 - JPA Many to One: Deleting One to Many side spring数据JPA方法findAll()与Predicate - QueryDslPredicateExecutor - spring data JPA method findAll() with Predicate - QueryDslPredicateExecutor 多对多。 弹簧。 仅保存表B(管理侧)就可以更新表A中的(B)数据列表 - ManyToMany. Spring. Possible to update list of (B) data in table A, by only saving table B(managing side) Spring Boot 无法通过 findAll 或 findByColumnName 方法获取关系实体 - Spring Boot Can't get the relation entity with findAll or findByColumnName method Spring 数据 JPA - 将@Query 与多对多关系/联接表一起使用 - Spring Data JPA - Using @Query with Many to Many Relationships / Join Table JPA2——如何在“多”侧自动删除一个方向的多对一映射数据? - JPA2 -- how to auto remove one direction many-to-one mapping data on `many` side?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM