Hesaplanan mülkler JPA ve Hazırda Bekletme ile nasıl eşleştirilir


104

Java fasulyemin bir childCount özelliği var. Bu özellik bir veritabanı sütununa eşlenmez . Bunun yerine, Java çekirdeğimin ve alt öğelerinin birleşiminde çalışan bir COUNT()işlevle veritabanı tarafından hesaplanmalıdır . Bu özelliğin talep üzerine / "tembelce" hesaplanması daha da iyi olur, ancak bu zorunlu değildir.

En kötü senaryoda, bu bean'in özelliğini HQL veya Criteria API ile ayarlayabilirim, ancak bunu yapmamayı tercih ederim.

Hazırda Bekletme @Formulanotu yardımcı olabilir, ancak neredeyse hiç belge bulamadım.

Herhangi bir yardım çok takdir edildi. Teşekkürler.

Yanıtlar:


162

JPA, türetilmiş mülk için herhangi bir destek sunmaz, bu nedenle sağlayıcıya özgü bir uzantı kullanmanız gerekir. Bahsettiğiniz gibi, @FormulaHibernate kullanırken bunun için mükemmel. Bir SQL parçası kullanabilirsiniz:

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

Veya diğer tablolardaki karmaşık sorgular:

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

Mevcut varlığın nerede idolduğu id.

Aşağıdaki blog yazısı okunmaya değer: Hazırda Bekletmeden Türetilen Özellikler - Performans ve Taşınabilirlik .

Daha fazla ayrıntı olmadan daha kesin bir cevap veremem ama yukarıdaki bağlantı yardımcı olabilir.

Ayrıca bakınız:


Teşekkürler Pascal. Aşağıdakilerin neden işe yaramadığına dair bir fikriniz var mı? @Formula (value = "( ic.category_id = c.id ve c.id = id) 'nin ic iç birleşiminden say ( ) seçin ") public Integer getCountInternal () {return countInternal; } Sorgu TAMAM ve günlüklerde çalıştırıldığını görüyorum. Eşleştirme iyi görünüyor: ana org.hibernate.cfg.Ejb3Column - bağlama formülü (select count ( ) blah blah blah Ama countInternal başlangıç ​​değerine (-1) ayarlı kalıyor :( Alıcı ek açıklamaları yerine alan açıklamalarını kullanmayı denedim, ancak hala çalışmıyor.
Francois

Teşekkürler, görevimde bana gerçekten çok yardımcı oldu!
Mythul

13
@NeilMcGuigan: @FormulaEk açıklama HQL değil SQL kullanıyor.
user1438038

7
Sorgunun etrafına parantez koymanın ne kadar önemli olduğunu öğrendim. Her zaman bir SQL İstisnası ile sonuçlanır, çünkü bu sorgu elbette ana makine nesnesi yüklendiğinde bir alt sorgu haline gelir. MySQL, parantezsiz satır içi seçimi beğenmedi.
sorrymissjackson


53

Bu makalede açıklandığı gibi , üç seçeneğiniz var:

  • Ya özelliği bir @Transientyöntem kullanarak hesaplıyorsunuz
  • @PostLoadvarlık dinleyicisini de kullanabilirsiniz
  • veya Hazırda Bekletmeye özel @Formulaek açıklamayı kullanabilirsiniz

Hibernate, @Formula kullanmanıza izin verirken , JPA ile, bir geçici özelliği bazı hesaplamaların sonucuyla doldurmak için @PostLoad geri aramasını kullanabilirsiniz :

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

Daha karmaşık sorgular için, bu makalede@Formula açıklandığı gibi Hazırda Bekletme'yi kullanabilirsiniz :

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

7
Ancak bu, daha karmaşık sorgulara izin vermez
Hubert Grzeskowiak

2
Cevabı güncelledim, böylece artık daha karmaşık sorgular için bir çözümünüz var.
Vlad Mihalcea

1

JPA üzerinde çalışan ve birinci sınıf DTO desteği sağlayan Blaze-Persistence Varlık Görünümlerine bir göz atın . Varlık Görünümleri içindeki özniteliklere her şeyi yansıtabilirsiniz ve hatta mümkünse ilişkilendirmeler için mevcut birleştirme düğümlerini yeniden kullanır.

İşte örnek bir eşleme

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

Bunu getirmek, buna benzer bir JPQL / HQL sorgusu oluşturacak

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

İşte sizin için de ilginç olabilecek özel alt sorgu sağlayıcıları hakkında bir blog yazısı: https://blazebit.com/blog/2017/entity-view-mapping-subqueries.html


0

bunu kodumda denedim

 @Formula(value = "(select DATEDIFF(expiry_date,issue_date)  from document_storage)")
    private String  myColumn;

Bıyık üzerindeki sütunu görüntülemeye çalışmadan önce bile çalıştırdığımda ve görüntülediğimde aldığım hatalar böyle bir şey

java.lang.NullPointerException
    at java.base/java.lang.String$CaseInsensitiveComparator.compare(String.java:1241)
    at java.base/java.lang.String$CaseInsensitiveComparator.compare(String.java:1235)
    at java.base/java.util.TreeMap.getEntryUsingComparator(TreeMap.java:374)
    at java.base/java.util.TreeMap.getEntry(TreeMap.java:343)
    at java.base/java.util.TreeMap.get(TreeMap.java:277)
    at com.mysql.cj.result.DefaultColumnDefinition.findColumn(DefaultColumnDefinition.java:182)

sorduğum soru Hesaplanan sütunun değerlerini mySQL ile JPA / Hibernate kullanarak almanın bir yolu var mı?

Neyi yanlış yapıyorum ?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.