2010-05-26 3 views
29

Existe-t-il un moyen de comptabiliser la taille d'une collection associée sans l'initialiser?Taille de la collection de comptage Hibernate sans initialisation

par exemple.

Select count(p.children) from Parent p 

(il y a une bonne raison pour laquelle je ne peux pas faire ce toute autre manière que ma clause where est plus compliquée et ma de clause est une requête polymorphique)

Merci.

+0

Prenez garde que vous semblez avoir peu de contrôle sur la clé utilisée lors de la vérification de l'existence avec contient sur un LazyCollection. C'est un peu un gotcha parce que vous ne pouvez pas utiliser les clés naturelles pour faire le contrôle de l'existence. –

Répondre

53

Une solution possible autre que les requêtes peut être le mappage children avec lazy="extra" (en notation XML). De cette façon, vous pouvez récupérer le parent avec n'importe quelle requête dont vous avez besoin, puis appeler parent.getChildren().size() sans charger la collection entière (seule une requête de type SELECT COUNT est exécutée).

avec annotations, il serait

@OneToMany 
@org.hibernate.annotations.LazyCollection(
org.hibernate.annotations.LazyCollectionOption.EXTRA 
) 
private Set<Child> children = new HashSet<Child>(); 

Mise à jour: Citation de Java Persistence with Hibernate, ch. 13.1.3:

Un proxy est initialisé si vous appelez une méthode qui n'est pas la méthode identifiant getter , une collection est initialisé si vous commencez à itérer ses éléments ou si vous appeler l'une des collection de gestion opérations, telles que size() et . Hibernate fournit un paramètre supplémentaire qui est surtout utile pour les grandes collections; ils peuvent être mappés comme supplémentaire paresseux. [...]

[mappée comme ci-dessus,] la collection est plus initialisé si vous appelez size(), ou isEmpty() - la base de données est interrogé pour récupérer les informations nécessaires. S'il s'agit d'un Map ou d'un List, les opérations containsKey() et get() interrogent également directement la base de données.

donc avec une entité mappée comme ci-dessus, vous pouvez alors faire

Parent p = // execute query to load desired parent 
// due to lazy loading, at this point p.children is a proxy object 
int count = p.getChildren().size(); // the collection is not loaded, only its size 
+0

pouvez-vous élaborer un peu plus à ce sujet. –

+1

@Varun, voir ma mise à jour. –

+2

Attention, il y a un bug: https://hibernate.atlassian.net/browse/HHH-9227 –

1

Vous pouvez utiliser Session # createFilter qui est une forme de HQL qui fonctionne explicitement sur les collections. Par exemple, vous mentionnez parents et enfants, donc si vous avez une personne p la forme la plus simple serait:

session.createFilter(p.getChildren(), "").list() 

Ce simplement vous renvoie une liste des enfants. Il est important de noter que la collection retournée n'est pas "live", elle n'est en aucun cas associée à p.

La partie intéressante vient du second argument. C'est un fragment HQL. Ici, par exemple, vous voudrez peut-être:

session.createFilter(p.getChildren(), "select count(*)").uniqueResult(); 

Vous avez dit que vous avez une clause where, vous voudrez peut-être aussi:

session.createFilter(p.getChildren(), "select count(*) where this.age > 18").uniqueResult(); 

avis il n'y a de l'article. C'est-à-dire que la clause from est implicite de l'association.Les éléments de la collection reçoivent l'alias 'this' de sorte que vous pouvez vous y référer à partir d'autres parties du fragment HQL.

-2

Vous pouvez faire la même chose comme ceci:

@Override 
public FaqQuestions getFaqQuestionById(Long questionId) { 
    session = sessionFactory.openSession(); 
    tx = session.beginTransaction(); 
    FaqQuestions faqQuestions = null; 
    try { 
     faqQuestions = (FaqQuestions) session.get(FaqQuestions.class, 
       questionId); 
     Hibernate.initialize(faqQuestions.getFaqAnswers()); 

     tx.commit(); 
     faqQuestions.getFaqAnswers().size(); 
    } finally { 
     session.close(); 
    } 
    return faqQuestions; 
} 

Il suffit d'utiliser faqQuestions.getFaqAnswers() taille() nin votre contrôleur et vous obtiendrez la taille si paresseusement liste réactiver les, sans aller chercher la liste elle-même..

+1

Que se passe-t-il exactement ici et pourquoi cela devrait-il fonctionner? Pourquoi commettre une transaction? – h22

Questions connexes