Как сопоставить рассчитанные свойства с JPA и Hibernate
У моей Java bean есть свойство childCount. Это свойство не отображается в столбце базы данных. Вместо этого он должен быть рассчитан с помощью базы данных с помощью функции COUNT()
, действующей при объединении моей Java bean и ее дочерних элементов. Было бы еще лучше, если бы это имущество могло быть рассчитано по требованию/ "лениво", но это не обязательно.
В худшем случае я могу установить это свойство bean с помощью HQL или API критериев, но я бы предпочел не делать этого.
Аннотации Hibernate @Formula
могут помочь, но я едва мог найти какую-либо документацию.
Любая помощь очень ценится. Спасибо.
Ответы
Ответ 1
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 - производительность и переносимость.
Без более подробной информации я не могу дать более точный ответ, но приведенная выше ссылка должна быть полезной.
Смотрите также:
Ответ 2
Как объясняется в этой статье, у вас есть три варианта:
- либо вы рассчитываете атрибут, используя метод
@Transient
- Вы также можете использовать слушатель сущности
@PostLoad
- или вы можете использовать специфичную для
@Formula
аннотацию @Formula
В то время как Hibernate позволяет вам использовать @Formula, с JPA вы можете использовать обратный вызов @PostLoad для заполнения переходного свойства результатом некоторого вычисления:
@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;
Ответ 3
Взгляните на Blaze-Persistence Entity Views, который работает поверх JPA и обеспечивает первоклассную поддержку DTO. Вы можете проецировать что угодно на атрибуты в Entity Views, и он даже будет использовать существующие узлы соединения для ассоциаций, если это возможно.
Вот пример сопоставления
@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