Mon bean Java a une propriété childCount. Cette propriété est non mappée à une colonne de base de données . Au lieu de cela, il devrait être calculé par la base de données avec une fonction COUNT()
opérant sur la jointure de mon bean Java et de ses enfants. Ce serait encore mieux si cette propriété pouvait être calculée sur demande/"paresseusement", mais ce n'est pas obligatoire.
Dans le pire des cas, je peux définir la propriété de ce bean avec HQL ou l'API Criteria, mais je préférerais ne pas le faire.
L'annotation Hibernate @Formula
peut aider, mais je pouvais à peine trouver de la documentation.
Toute aide grandement appréciée. Merci.
JPA n'offre aucun support pour les propriétés dérivées, vous devez donc utiliser une extension spécifique au fournisseur. Comme vous l'avez mentionné, @Formula
est parfait pour cela lorsque vous utilisez Hibernate. Vous pouvez utiliser un fragment SQL:
@Formula("PRICE*1.155")
private float finalPrice;
Ou même des requêtes complexes sur d'autres tables:
@Formula("(select min(o.creation_date) from Orders o where o.customer_id = id)")
private Date firstOrderDate;
Où id
est la id
de l'entité actuelle.
Le billet de blog suivant vaut la peine d'être lu: Propriétés dérivées d'Hibernate - Performances et portabilité .
Sans plus de détails, je ne peux pas donner de réponse plus précise, mais le lien ci-dessus devrait être utile.
Comme expliqué dans cet article , vous avez trois options:
@Transient
@PostLoad
entité écouteur@Formula
spécifique à HibernateBien qu'Hibernate vous permette d'utiliser @Formula , avec JPA, vous pouvez utiliser le callback @PostLoad pour remplir une propriété transient avec le résultat d'un calcul:
@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;
}
Pour des requêtes plus complexes, vous pouvez utiliser le code Hibernate @Formula
, comme expliqué dans cet article :
@Formula(
"round(" +
" (interestRate::numeric / 100) * " +
" cents * " +
" date_part('month', age(now(), createdOn)" +
") " +
"/ 12) " +
"/ 100::numeric")
private double interestDollars;
Jetez un coup d’œil à Blaze-Persistence Entity Views qui fonctionne au-dessus de JPA et fournit un support DTO de première classe. Vous pouvez projeter n'importe quoi sur des attributs dans Entity Views et il pourra même réutiliser des nœuds de jointure existants pour des associations, si possible.
Voici un exemple de mapping
@EntityView(Order.class)
interface OrderSummary {
Integer getId();
@Mapping("SUM(orderPositions.price * orderPositions.amount * orderPositions.tax)")
BigDecimal getOrderAmount();
@Mapping("COUNT(orderPositions)")
Long getItemCount();
}
Cela va générer une requête JPQL/HQL similaire à this
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
Voici un article de blog sur les fournisseurs de sous-requêtes personnalisés qui pourrait également vous intéresser: https://blazebit.com/blog/2017/entity-view-mapping-subqueries.html