2009-07-07 9 views
1

Je convertis une implémentation iBatis héritée en Hibernate, et pour des raisons de rétrocompatibilité, je dois présenter les comptes des collections d'un objet plutôt que les collections elles-mêmes. La requête initiale était:Comment implémenter cette requête dans Hibernate?

select A.*, (select count(*) from B where B.A_id = A.id) as B_count from A; 

et b_count serait présenté dans la réponse. Je voudrais être en mesure de faire la même chose sans chargement paresseux A de la collection de B pour chaque résultat de la requête.

Des idées ou des suggestions?

+0

Un collègue de mon bureau a recommandé une annotation @Formula. Je vais écrire la résolution comme une réponse. –

Répondre

2

La meilleure méthode semble utiliser une formule Hibernate, mis en correspondance avec le getter et setter de mon BCount attribut dans la classe A. Mon code:

public class A { 
    // ... 
    private long bCount; 

    // ... 

    @Formula("(select count(*) from B where B.A_id = id") 
    public long getBCount() { 
     return this.bCount; 
    } 

    public void setBCount(long bCount) { 
     this.bCount = bCount; 
    } 
} 

grande chose au sujet de cette méthode est que le compte est retourné dans le même chercher pour hydrater l'objet initial, et ne donne pas lieu à 1 + N requêtes pour la collecte requête resul ts!

+0

Je ne savais même pas que c'était possible. Je sais qu'il y a quelques endroits dans mon code qui pourraient en bénéficier. – Jesse

0

Vous pouvez utiliser une projection.

La syntaxe pour le nombre de lignes est ci-dessous:

Criteria crit = session.createCriteria(B.class); 
    crit.setProjection(Projections.rowCount()); 
    List results = crit.list(); 

Edit: Après relecture, je pense que cela peut ne pas être ce que vous demandez ....

+0

Ce n'était pas ce que je cherchais, mais c'est toujours apprécié! –

0

filtres Hibernate sont utilisé pour appliquer des restrictions supplémentaires aux résultats de la requête (par exemple, pensez à eux dans le cadre de la clause "where"), de sorte qu'ils ne feront pas ce que vous voulez. Vous avez deux options:

A) Vous pouvez avec impatience obtenir collection d'hôtes pour votre A:

from A a left join fetch a.Bs b
Si vous le faites, gardez à l'esprit que pour les requêtes qui reviendraient multiples Comme vous pouvez obtenir des doublons dans le résultat liste (par exemple, si vous avez 2 As et que chacun d'eux a 3 Bs, vous obtiendrez 6 résultats). Enveloppez-les dans un ensemble pour assurer l'unicité.

B) En supposant que vous avez un constructeur approprié A, vous pouvez effectuer les opérations suivantes:

 
select new A(a.field1, a.field2, ... a.fieldN, count(*) as B_count) 
    from A a left join a.Bs b 
    group by a.field1, a.field2, ... a.fieldN