【问题标题】:How to map the latest child of a collection with JPA and Hibernate如何使用 JPA 和 Hibernate 映射集合的最新子项
【发布时间】:2015-06-06 20:47:56
【问题描述】:

我有一个Product 实体类,我希望它加入Price 表。

我的目标是保留旧的报告价格,当我得到 Product 实体时,它应该根据最新日期映射到最新价格。

请解释我如何在 Hibernate JPA 关系中实现这一点。如果可能的话,分享一个代码 sn-p。

【问题讨论】:

    标签: java database hibernate jpa orm


    【解决方案1】:

    你的域模块可以使用@JoinFormula,像这样:

    @Entity
    public class Product {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private String name;
    
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "product", orphanRemoval = true)
        private List<Price> prices = new ArrayList<>();
        
        @ManyToOne
        @JoinFormula(
            "(SELECT id FROM price ORDER BY created_on DESC LIMIT 1)"
        )
        private Price latestPrice;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Price> getPrices() {
            return prices;
        }
    
        public void addPrice(BigDecimal priceValue) {
            Price price = new Price();
            price.setPrice(priceValue);
            prices.add(price);
            price.setProduct(this);
            latestPrice = price;
        }
        
        public Price getLatestPrice() {
            return latestPrice;
        }
    }
    
    @Entity(name = "Price")
    public class Price {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @ManyToOne
        private Product product;
        
        @Column(name = "created_on", nullable=false, updatable=false)
        private Date createdOn;
    
        private BigDecimal price;
    
        public void setProduct(Product product) {
            this.product = product;
        }
    
        public BigDecimal getPrice() {
            return price;
        }
    
        public void setPrice(BigDecimal price) {
            this.price = price;
        }
        
        @PrePersist
        public void prePersist() {
            createdOn = new Date();        
        }
    }
    

    这是您更新产品价格的方式:

    Long id = ...;
    BigDecimal newPriceValue = ...;
    
    Product product = entityManager.find(Product, id);
    Price oldPrice = product.getLatestPrice();    
    
    product.addPrice(newPriceValue);
    

    【讨论】:

    • 我看到你刚刚添加了DESC,但我认为你还需要将select语句放入括号中
    • 当然。我意识到如果没有 DESC,我不会返回最新条目,而是返回第一个条目。我还按照您的建议添加了括号。
    • @VladMihalcea 你能问一下为什么latestPrice 属性用@ManyToOne 注释吗?
    • 因为这是一对一的关系。 @ManyToOne@OneToOne 都应该可以工作。
    • 投票给这个注解@LastEllementCollection: hibernate.atlassian.net/browse/HHH-14696
    【解决方案2】:

    我真的很喜欢@vlad-mihalcea 的回答,可惜我还需要支持Oracle。我最终得到了一个不太优雅的解决方案,但它适用于 Oracle:

    ...
        @ManyToOne
        @JoinFormula(
            "(SELECT p.id FROM price p WHERE p.product_id = id and p.created_on = (select max(p2.created_on) from price p2 where p2.product_id = id))"
        )
        private Price latestPrice;
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2017-01-29
      • 1970-01-01
      • 2012-04-10
      相关资源
      最近更新 更多