Как сопоставить рассчитанные свойства с JPA и Hibernate - PullRequest
98 голосов
/ 07 июня 2010

Мой Java-бин имеет свойство childCount. Это свойство не сопоставлено со столбцом базы данных . Вместо этого он должен быть вычислен базой данных с помощью функции COUNT() , работающей на объединении моего Java-компонента и его дочерних элементов. Было бы еще лучше, если бы это свойство могло быть рассчитано по требованию / «лениво», но это не обязательно.

В худшем случае я могу установить свойство этого компонента с помощью HQL или Criteria API, но я бы предпочел этого не делать.

Может помочь аннотация Hibernate @Formula, но я едва смог найти какую-либо документацию.

Любая помощь с благодарностью. Спасибо.

Ответы [ 3 ]

152 голосов
/ 07 июня 2010

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 - производительность и переносимость .

Без подробностей я не могу дать более точный ответ, но приведенная выше ссылка должна быть полезной.

Смотри также:

45 голосов
/ 12 марта 2015

Как объясняется в этой статье , у вас есть три варианта:

  • либо вы вычисляете атрибут, используя @Transient метод
  • Вы также можете использовать @PostLoad слушатель сущностей
  • или вы можете использовать специфичную для Hibernate аннотацию @Formula 1013 *

Хотя Hibernate позволяет использовать @ Formula , в JPA вы можете использовать обратный вызов @ 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;
1 голос
/ 31 января 2019

Взгляните на 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

...