web-dev-qa-db-de.com

Berechnete Eigenschaften mit JPA und Hibernate

Meine Java-Bean verfügt über eine childCount-Eigenschaft. Diese Eigenschaft ist einer Datenbankspalte nicht zugeordnet. Stattdessen sollte es von der Datenbank mit einer COUNT()-Funktion berechnet werden, die auf den Join meiner Java-Bean und ihrer untergeordneten Elemente angewendet wird. Es wäre noch besser, wenn diese Eigenschaft auf Nachfrage/"faul" berechnet werden könnte, dies ist jedoch nicht zwingend.

Im schlimmsten Fall kann ich die Eigenschaft dieser Bean mit HQL oder der Criteria API festlegen, aber ich würde es nicht vorziehen.

Die Hibernate @Formula-Anmerkung kann hilfreich sein, aber ich konnte kaum Dokumentation finden.

Jede Hilfe sehr geschätzt. Vielen Dank.

91
Francois

JPA bietet keine Unterstützung für abgeleitete Eigenschaften, daher müssen Sie eine anbieterspezifische Erweiterung verwenden. Wie Sie bereits erwähnt haben, ist @Formula ideal, wenn Sie Hibernate verwenden. Sie können ein SQL-Fragment verwenden:

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

Oder auch komplexe Abfragen zu anderen Tabellen:

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

Wobei id die id der aktuellen Entität ist.

Der folgende Blogbeitrag ist das Lesen wert: Hibernate Abgeleitete Eigenschaften - Leistung und Portabilität .

Ohne weitere Details kann ich keine genauere Antwort geben, aber der obige Link sollte hilfreich sein.

Siehe auch:

145
Pascal Thivent

Wie in diesem Artikel erklärt, haben Sie drei Möglichkeiten:

  • entweder berechnen Sie das Attribut mit einer @Transient-Methode
  • sie können auch @PostLoad-Entitätenlistener verwenden
  • oder Sie können die Hibernate-spezifische @Formula-Anmerkung verwenden

Mit Hibernate können Sie @Formula mit JPA verwenden. Mit dem @PostLoad - Callback können Sie eine transient - Eigenschaft mit dem Ergebnis einiger Berechnungen füllen:

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

Für komplexere Abfragen können Sie den Hibernate @Formula verwenden, wie in diesem Artikel erläutert:

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

Werfen Sie einen Blick auf Blaze-Persistence Entity Views , das auf JPA aufbaut und erstklassigen DTO-Support bietet. Sie können Attribute in Entity Views projizieren, und vorhandene Verknüpfungsknoten werden nach Möglichkeit sogar für Verknüpfungen verwendet.

Hier ist ein Beispiel für ein Mapping

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

Durch das Abrufen dieses Befehls wird eine ähnliche JPQL/HQL-Abfrage generiert

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

Hier ist ein Blog-Post über Anbieter von benutzerdefinierten Unterabfragen, die für Sie ebenfalls interessant sein könnten: https://blazebit.com/blog/2017/entity-view-mapping-subqueries.html

0