Hibernate @Formula在PUT响应中返回一个旧值

时间:2018-02-06 10:42:51

标签: java hibernate spring-boot

我的Spring启动应用程序有2个实体 - 文档和卡。卡有列dtFrom。客户必须使用列daysOnDtConfirm(Document.dtConfirm - dtFrom)。注释@Formula for GET请求效果很好,但在PUT响应中返回旧值daysOnDtConfirm。如何返回新值?

@Entity
@Table(name="document")
public class Document extends BaseEntity{
  private String name; 

  @Column(name = "dt_confirm")       
  @Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  @JsonFormat(shape = JsonFormat.Shape.STRING)
  private LocalDateTime dtConfirm ;

  @Column(name = "contragent_name")
  private String contragentName;
     ....
  //CARD
  @OneToMany(mappedBy="document" , fetch = FetchType.EAGER)
  private List<Card> cards = new ArrayList<Card>();

  public  List<Card> getCards() {
    if (this.cards == null) {
        this.cards = new ArrayList<Card>();
    }
    return this.cards;
   }

 public void setCard(Card card) {
      getCards().add(card);
      card.setDocument(this);
  }

 public int getNrOfCards() {
    return getCards().size();
  }
 ....
}

@Entity
@Table(name="card")
public class Card extends BaseEntity {
  @ManyToOne
  @JsonIgnore
  @JoinColumn(name = "document_id")
  private Document document;

  private String name;

  private double quantity;

  @Column(name = "dt_from")
  @Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  @JsonIgnore
  private LocalDate dtFrom ;

  @Formula("(select IFNULL(DATEDIFF(Document.dt_confirm , dt_from), 0) from 
   Document where Document.id = document_id )")
  private int daysOnDtConfirm;
  ...
  public void setDtFrom(LocalDate dtFrom) {
    this.dtFrom = dtFrom;
   }

  public void setDtFrom(int daysOnDtConfirm) {
    if (this.document.getDtConfirm() != null){
        LocalDate dateTo = this.document.getDtConfirm().toLocalDate();
        this.dtFrom = dateTo.minusDays(daysOnDtConfirm);
     }
   }
    ...
}

服务:

@Service
public class DocumentServiceImpl implements DocumentService {    
  @Autowired
  DocumentRepository documentRepository;
  @Autowired
  CardRepository cardRepository;
       ...
  @Override
  @Transactional
  public void changeCard(Document document, Card card) {

     //IF ID is NULL then isNew==true!!!!
     if (card.isNew()){
            card.setDocument(document);                
            card.setDtFrom(card.getDaysOnDtConfirm());
            document.setCard(card);
            cardRepository.saveAndFlush(card);    
        }
        else{
            Card cardEdit = cardRepository.findOne(card.getId());
            if (cardEdit != null) {
                cardEdit.setDocument(document);
                cardEdit.setName(card.getName());
                cardEdit.setUnit(card.getUnit());
                cardEdit.setQuantity(card.getQuantity());
                //cardEdit.setDtFrom(card.getDtFrom());
                cardEdit.setDtFrom(card.getDaysOnDtConfirm());
                cardEdit.setDescription(card.getDescription());
                cardRepository.saveAndFlush(cardEdit);
            }

        }

    @Override
    @Transactional
    public Document changeDocumentAndCards(Document document) {
        Document documentEdit = changeDocument(document);   
        List<Card> cards = document.getCards();
        //check if the same rows in DB and Client, DELETE difference
        deleteCardsFromDocument(document);
        //if not empty received from client rows  then change
        if (!cards.isEmpty()) {
            for (Card card : cards) {
                changeCard(documentEdit, card);

            }
        }

        return documentEdit;
    }
       ...
}

RestController:

    @RestController
    @RequestMapping("/api/docs")
    public class DocController  {
        @Autowired
        DocumentService documentService;

        @RequestMapping(value = "",
                method = RequestMethod.GET,
                produces = {"application/json", "application/xml"})
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody
        List<Document> getAllDocument(HttpServletRequest request, HttpServletResponse response) {
            List<Document> list = new ArrayList<>();
            Iterable<Document> documents = this.documentService.getDocumentAll();
            documents.forEach(list::add);
            return list;
        }
....
@RequestMapping(value = "/{id}",
            method = RequestMethod.PUT,
            consumes = {"application/json", "application/xml"},
            produces = {"application/json", "application/xml"})
    @ResponseStatus(HttpStatus.OK)
    public Document updateDocument(//@ApiParam(value = "The ID of the existing Document resource.", required = true)
                                   @PathVariable("id") Long id,
                                   @RequestBody Document document,
                                   HttpServletRequest request, HttpServletResponse response) {
        Document documentEdit = documentService.changeDocumentAndCards(document);
        return documentEdit;
    }
...
}

1 个答案:

答案 0 :(得分:1)

问题似乎来自changeDocument(Document document)方法。 saveAndFlush()调用的返回值应分配回documentEdit

<强>更新

问题是hibernate在更新后不会重新计算@Formula字段。它只是从缓存中获取它。

我设法在我的机器上运行的唯一方法是在更新后刷新卡实体。为了实现这一点,我需要在服务类中添加一个实体管理器。

DocumentServiceImpl(实际上可以是任何服务类)类中添加以下内容:

public class DocumentServiceImpl implements DocumentService {

    //...

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void refreshEntity(Object entity) {
        em.refresh(entity);
    }

然后,您应该在更新后调用此refreshEntity()方法,以便hibernate不从缓存中获取它。

这种方式对我有用。希望它可以帮到你。