2010-02-17 23 views
16

Yapacağım statik sorgular için JPA'da Named Queries'in fikrini beğeniyorum, ancak genellikle sorgunun sonucunun yanı sıra sorgunun bazı alt kümelerinden sonuç listesi almak istiyorum. Neredeyse iki benzer NamedQueries yazmamayı tercih ederim.Sonuç kümesiyle JPA Adlandırılmış Sorgu için sayı boyutunu elde etmenin bir yolu var mı?

@NamedQuery(name = "getAccounts", query = "SELECT a FROM Account") 
. 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = q.getCount(); 

Yani d s 0 ve Hesabına 400 satır olduğunda, 10 olduğunu varsayalım: İdeal olarak, ne olmasını istiyorum gibi bir şeydir. R'nin 10 öğenin bir listesini olmasını beklerdim, ancak toplam 400 satır olduğunu bilmek isterim. İkinci bir @NamedQuery yazabilirsiniz:

@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account") 

ama KURU ihlali ben her zaman sadece sayımı isteyeceğim eğer bunu gibi görünüyor. Bu basit durumda, ikisini senkronize tutmak kolaydır, ancak eğer sorgu değiştiyse, değerleri hizalamak için her iki @NamedQueries'i güncellemek zorunda olduğumdan daha az ideal görünmektedir.

Buradaki yaygın bir kullanım durumu, öğelerin bazı alt kümelerini getiriyor, ancak toplam sayımı belirtmenin bir yoluna ihtiyaç duyuyordu ("1-10/400 gösteriliyor"). setFirstResult/setMaxResults bir sonuç kümesinde bir alt kümesini döndürmez do kullanma

cevap

13

Bu yüzden, kullandığım çözüm, sonuç kümesi için bir tane olmak üzere iki tane @NamedQuerys oluşturmak, ancak DRY'yi korumak için temel sorguyu statik bir dizede yakalamak ve her iki sorgunun tutarlı kalmasını sağlamaktı. Yani yukarıdaki için, şöyle bir şey olurdu: Bu örnek ile Açıkçası

@NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery) 
@NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery) 
. 
static final String accountQuery = " FROM Account"; 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue(); 

, sorgu beden önemsiz ve bu overkill. Ancak çok daha karmaşık sorgularla, sorgu gövdesinin tek bir tanımına sahip olursunuz ve iki sorguyu senkronize edebildiğinizden emin olabilirsiniz. Ayrıca, sorguların önceden derlenmiş olması ve en azından Eclipselink ile, sorguyu çağırmak yerine, başlangıç ​​zamanında doğrulamayı almanız avantajına sahip olursunuz.

İki sorgu arasında tutarlı bir adlandırma yaparak, kodun gövdesini, her iki kümeyi, yalnızca sorgunun temel adını temel alarak çalıştırmak için sarmak mümkündür.

+0

sonunda namedQueries için de çalışıyor! Teşekkürler – Zavael

+0

İlginç, ek açıklamaları yapılandırırken statik finallere başvurabileceğinizi bile bilmiyordum. Ancak, iki ayrı adlandırılmış sorgu gerektirmeyen bir çözüm hala ideal olacaktır. – aroth

5

, sorgu bile bu yöntemleri çağırdığınızda çalıştırmak değil, onlar getResultList çağrılırken çalıştırılacaktır oluşturulan SELECT sorgusu etkiler. Toplam kayıt sayısını elde etmek istiyorsanız, SELECT COUNT varlıklarınızı ayrı bir sorguda (genellikle sayfalandırılmadan önce) yapmanız gerekir.

Tam bir örnek için Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs'a bakın.

+0

Evet. Sorgunun sonuçlanacağı tam sayımı elde etmek istiyorum. Dolayısıyla, örnekte saymak r.size() ile uyuşmayacaktı ya da sadece bunu kullanacağım. Potansiyel kullanım durumu, listeleme hesapları için bir sonuç sayfası elde etmek istememdir, ancak toplam kaç sayfalık bir sayfa olmasına izin vermek için, toplam 25 sonucu elde etmeme rağmen sorgudan toplam sayımı istiyorum. – Tim

+0

@Tim Cevabımı açıklığa kavuşturdum. Hala açık değilse, bana bildirin. –

+0

Teşekkürler. Sorumu açıklığa kavuşturmaya çalıştım. Temel olarak, değiştiricilerin çalıştırılmadan önce sorguyu değiştirdiğini biliyorum. Ne yapmayı umduğum tek bir @NamedQuery var bir sayımı almak için bir sorgu ve bir geri dönüş seti için bir tane yazmak yerine, bir sayı alma gibi bir alt kümesi için temel olarak davranır. İdeal olarak hala @NamedQuery kullanıyor. Referans ettiğiniz bağlantıyı kontrol edeceğim. – Tim

1

oh iyi sizin gibi adlandırılmış sorguları ek açıklamaları almak için iç gözlem kullanabilirsiniz:

String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) { 
    NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class); 
    NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value(); 

    String code = null; 
    for (NamedQuery namedQuery : namedQueryAnnotations) { 
     if (namedQuery.name().equals(namedQueryKey)) { 
      code = namedQuery.query(); 
      break; 
     } 
    } 

    if (code == null) { 
     if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) { 
      code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey); 
     } 
    } 

    //if not found 
    return code; 
} 
+0

Bunun benim soruma nasıl uygulandığından emin değil. Pre-derleme, önbellekleme ve diğer optimizasyonların avantajları için NamedQuery'yi kullanmak istiyorum. İki sorgunun bir sonuç döndürmesi ve bir geri sayım hariç aynı olması istiyorum. Ve ben DRY'yi takip etmek ve şartlı hükümleri kopyalayıp yapıştırmak istemiyorum. – Tim

İlgili konular