【问题标题】:Mapping calculated properties with JPA使用 JPA 映射计算属性
【发布时间】:2010-11-24 11:38:50
【问题描述】:

有没有办法使用 JPA 映射计算的属性?

假设我有一个 Invoice 对象,其中包含一个或多个 InvoiceLineItems,我希望在 Invoice 类上有一个持久计算属性,它可以为我提供总金额:

class Invoice {
    ...

    @Column(name = "TOTAL_AMOUNT")
    public BigDecimal getTotalAmount() {
        BigDecimal amount = BigDecimal.ZERO;
        for (InvoiceLineItem lineItem : lineItems) {
            amount = amount.add(lineItem.getTotalAmount());
        }
        return amount;
    }
}

现在,我可以创建一个受保护的无操作 setTotalAmount 方法来让 JPA 满意,但我想知道是否有办法让 JPA 知道映射只是一种方法,并避免创建多余的 setter 方法.

谢谢, 亚历克斯

【问题讨论】:

    标签: java jpa persistence


    【解决方案1】:

    我知道我正在删除这个线程,但也许它可以帮助某人。

    如果您想计算读取时的值,@PostLoad 注释可能是您想要的:

    @Transient
    private BigDecimal totalAmount;
    
    @PostLoad
    public void onPostLoad() {
        BigDecimal amount = BigDecimal.ZERO;
        for (InvoiceLineItem lineItem : lineItems) {
            amount = amount.add(lineItem.getTotalAmount());
        }
        this.totalAmount = amount;
    }
    

    【讨论】:

    • 实际上不是 OPs 问题的答案,但顺便说一句,这只是我的问题的正确答案,因为我想要一些与 OP 略有不同的东西......所以感谢您在这里发布! +1
    【解决方案2】:

    也许 PrePersist 注释可以用于此。

    @Column(name = "TOTAL_AMOUNT")
    private BigDecimal totalAmount;
    
    @PrePersist
    public void updateTotalAmount() {
        BigDecimal amount = BigDecimal.ZERO;
        for (InvoiceLineItem lineItem : lineItems) {
            amount = amount.add(lineItem.getTotalAmount());
        }
        this.totalAmount = amount;
    }
    

    【讨论】:

    • 很高兴知道这一点,谢谢。但是,每当我查看它时,我都需要更新总数,不仅是在它被持久化之前,所以它在我的特定情况下不起作用。
    • Braaaains...我的意思是,你为什么不拥有一个私有的updateTotalAmount() 方法,并从getTotalAmount() 访问器以及@PrePersist 调用它?这不就是 getter 的用途吗?
    【解决方案3】:

    您所描述的不是 JPA 意义上的计算属性。您在自己的方法中计算它 - 只需将该方法标记为 @Transient,JPA 就会忽略它。

    如果您确实需要计算属性(其中“计算”表示“通过 SQL 表达式计算”),则需要根据您的 JPA 提供程序对其进行注释。对于 Hibernate,您可以通过 @Formula 注释来做到这一点:

    @Formula("col1 * col2")
    public int getValue() {
     ...
    }
    

    其他提供商可能有自己的配置方式;没有 JPA 标准。

    【讨论】:

    • 将属性标记为@Transient 对我没有帮助。我不希望 JPA 忽略它——我希望将总量保留在数据库中,这样我就可以直接查询它,而不必从子表中聚合信息。所以我要问的是如何持久化一个计算属性(在 Java 意义上,与持久性完全无关),而不必为它实现不必要的 setter。
    • 你的例子很奇怪。如果您要存储此值并对其进行查询,为什么要在 getter 中重新计算它?但是,底线是,如果您要注释 getter 方法(而不是属性),则必须有一个相应的 setter(它可能是私有的),以便 JPA 在您的实体上填充该值。
    • 我给出的示例是对我正在使用的域模型的严重过度简化,它具有多个级别的一对多关系,每个级别的计算属性都取决于子级。在 Java 中根据需要计算值比尝试更新总数要容易得多,因为添加、删除或修改了(深层)层次结构中的子对象,这就是我重新计算它的原因。
    • 但是,持久化总数会使基于存储根对象的表的数量的查询变得更加简单,这是我想在保存对象时持久化它,但真的不想再次加载它(这就是为什么我不需要也不太关心二传手的原因)。这就是为什么我希望有一种方法可以告诉 JPA 从持久性的角度将属性视为只写。无论如何,感谢您的回答,我想我将不得不离开除了让 JPA 高兴之外没有其他目的的二传手:-(
    猜你喜欢
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 2012-04-05
    • 1970-01-01
    相关资源
    最近更新 更多