java - Hibernate @Formula 在 PUT 响应中返回旧值

标签 java hibernate spring-boot

我的 Spring boot 应用程序有 2 个实体 - 文档和卡片。卡具有 dtFrom 列。客户必须使用 daysOnDtConfirm 列(Document.dtConfirm - dtFrom)。 GET 请求的注释 @Formula 效果很好,但在 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;
    }
       ...
}

休息 Controller :

    @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;
    }
...
}

最佳答案

问题似乎来自 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 不会从缓存中获取它。

这种方式对我有用。希望对您有帮助。

关于java - Hibernate @Formula 在 PUT 响应中返回旧值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48641052/

相关文章:

Java 2 ME GameCanvas -- 如何接收所有 keyPressed 事件?

java - Spring framework : HTTP OPTIONS returning all METHODS (get, put, post, delete, trace, head, options)

java - 我的 Hibernate 拦截器不工作

java - 使用加载/获取使用泛型

java - 关于 ContainerBackgroundProcessor 的错误

java - Spring:如果可用,使用@Qualifier()-qualified bean,否则使用任何

java - Spark 是否与 OpenJ9 和 Java 8 一起运行?

java - 如何使用 Java Swing 制作动画数字计数器?

java - 为什么 ConfigurationProperties 类中的嵌套类需要是静态的?

spring - 从 Controller 运行 Spring 批处理作业