web-dev-qa-db-ja.com

JPAおよびHibernateで計算されたプロパティをマップする方法

Java Beanには、childCountプロパティがあります。このプロパティはデータベース列にマップされていないです。代わりに、COUNT()関数を使用してデータベースで計算 Java Beanとその子の結合で操作する必要があります。このプロパティをオンデマンドで/「怠 "に」計算できればさらに良いでしょうが、これは必須ではありません。

最悪のシナリオでは、このBeanのプロパティをHQLまたはCriteria APIで設定できますが、そうしない方がよいでしょう。

Hibernate @Formulaアノテーションは役立つかもしれませんが、ドキュメントはほとんど見つかりませんでした。

どんな助けも大歓迎です。ありがとう。

98
Francois

JPAは派生プロパティのサポートを提供しないため、プロバイダー固有の拡張機能を使用する必要があります。あなたが述べたように、@FormulaはHibernateを使用するときにこれに最適です。 SQLフラグメントを使用できます。

@Formula("PRICE*1.155")
private float finalPrice;

または、他のテーブルでの複雑なクエリでも:

@Formula("(select min(o.creation_date) from Orders o where o.customer_id = id)")
private Date firstOrderDate;

idは、現在のエンティティのidです。

次のブログ投稿は読む価値があります: Hibernate Derived Properties-Performance and Portability

詳細がなければ、より正確な答えを出すことはできませんが、上記のリンクは役に立つはずです。

こちらもご覧ください:

153
Pascal Thivent

この記事 で説明されているように、3つのオプションがあります。

  • @Transientメソッドを使用して属性を計算するか、
  • @PostLoadエンティティリスナーを使用することもできます
  • または、Hibernate固有の@Formulaアノテーションを使用できます

HibernateではJPAで @ Formula を使用できますが、 @ PostLoad コールバックを使用してtransient何らかの計算の結果を持つプロパティ:

@Column(name = "price")
private Double price;

@Column(name = "tax_percentage")
private Double taxes;

@Transient
private Double priceWithTaxes;

@PostLoad
private void onLoad() {
    this.priceWithTaxes = price * taxes;
}

より複雑なクエリの場合は、 この記事 で説明されているように、Hibernate @Formulaを使用できます。

@Formula(
    "round(" +
    "   (interestRate::numeric / 100) * " +
    "   cents * " +
    "   date_part('month', age(now(), createdOn)" +
    ") " +
    "/ 12) " +
    "/ 100::numeric")
private double interestDollars;
46
Vlad Mihalcea

Blaze-Persistence Entity Views を見てください。これはJPAの上で動作し、ファーストクラスのDTOサポートを提供します。エンティティビュー内の属性には何でも投影でき、可能な場合は既存の結合ノードを関連付けに再利用します。

マッピングの例を次に示します

@EntityView(Order.class)
interface OrderSummary {
  Integer getId();
  @Mapping("SUM(orderPositions.price * orderPositions.amount * orderPositions.tax)")
  BigDecimal getOrderAmount();
  @Mapping("COUNT(orderPositions)")
  Long getItemCount();
}

これを取得すると、次のようなJPQL/HQLクエリが生成されます

SELECT
  o.id,
  SUM(p.price * p.amount * p.tax),
  COUNT(p.id)
FROM
  Order o
LEFT JOIN
  o.orderPositions p
GROUP BY
  o.id

あなたにとっても興味深いかもしれないカスタムサブクエリプロバイダーについてのブログ投稿があります: https://blazebit.com/blog/2017/entity-view-mapping-subqueries.html

1