Author: fdesbois Date: 2010-06-15 00:38:21 +0200 (Tue, 15 Jun 2010) New Revision: 2014 Url: http://nuiton.org/repositories/revision/topia/2014 Log: Update TopiaQuery documentation Modified: trunk/topia-persistence/src/site/rst/TopiaQuery.rst Modified: trunk/topia-persistence/src/site/rst/TopiaQuery.rst =================================================================== --- trunk/topia-persistence/src/site/rst/TopiaQuery.rst 2010-06-14 21:50:20 UTC (rev 2013) +++ trunk/topia-persistence/src/site/rst/TopiaQuery.rst 2010-06-14 22:38:21 UTC (rev 2014) @@ -68,7 +68,7 @@ BoatDAO dao = ModelDAOHelper.getBoatDAO(transaction); TopiaQuery query = dao.createQuery(); -ou Depuis un topiaContext :: +ou depuis un topiaContext :: TopiaContext transaction = rootContext.beginTransaction(); TopiaQuery query = transaction.createQuery(Boat.class, "B"); @@ -76,7 +76,7 @@ L'intérêt de passer par un DAO est de pouvoir par la suite executer la requête avec ce même DAO. Il est également possible d'utiliser des alias pour l'élément principal de la requête pour pouvoir plus facilement gérer les cas de jointure. -Il suffit de préciser l'alias au moment de l'instantiation :: +Il suffit de préciser l'alias au moment de l'instanciation :: TopiaContext transaction = rootContext.beginTransaction(); BoatDAO dao = ModelDAOHelper.getBoatDAO(transaction); @@ -85,7 +85,7 @@ Ajout d'éléments au WHERE ------------------------- -Les méthodes de base nécessaire concerne l'ajout d'élements dans le WHERE de la +Les méthodes de base nécessaires concernent l'ajout d'élements dans le WHERE de la requête. Plusieurs méthodes sont disponibles suivant les besoins pour ajouter simplement un élément au where :: @@ -295,6 +295,15 @@ } // Utilisation de la première requête comme sous-requête + query2.add("C2." + Contact.CREATION_DATE + " = (" + query1.fullQuery() + ")"); + // Ajout des paramètres nécessaires de la première requête dans la deuxième + query2.addParams(query1.getParams()); + +Depuis la 2.3.4, la méthode **addSubQuery(String statement, TopiaQuery subquery)** +permet de faciliter l'injection d'une sous-requête notamment pour la gestion +des paramètres automatiquement (avec prise en charge des doublons) :: + + // Même chose que précédemment en utilisant la méthode addSubQuery query2.addSubQuery("C2." + Contact.CREATION_DATE + " = (?)", query1); La requête sous forme HQL :: @@ -317,9 +326,8 @@ --------- Plusieurs méthodes sont disponibles pour récupérer les résultats de la requête. -Pour chaque méthode, il est possible de l'appeler avec en paramètre le contexte -topia ou directement, si la requête a été instancié avec un DAO qui contient -lui même le contexte. La méthode de base est la méthode execute() qui renvoie +Pour chaque méthode, il est nécessaire de l'appeler avec le contexte +topia. La méthode de base est la méthode execute() qui renvoie une liste non typé à l'instar de la méthode find(...) du TopiaContext. Il est cependant possible de récupérer directement un objet, un entier (pour un aggregat par exemple) ou une chaîne de caractères suivant le select de la @@ -349,17 +357,60 @@ // résultats du 50ème au 60ème query.setLimit(49, 59); +// depuis 2.3.4 + +Pour éviter d'embarquer ces paramètres à chaque fois qu'ils sont nécessaires +lors d'un filtrage paginée, un bean, *EntityFilter* est disponible. +Il contient les attributs suivants : + +- startIndex : index de début des résultats. + +- endIndex : index de fin des résultats. + +- orderBy : propriétés à ordonner (l'ajout des mots clés 'asc' et 'desc' est + possible). + +- referenceId : identifiant d'une référence utile à la requête. + +- referenceProperty : nom de la propriété correspondant à la valeur du referenceId. + +Exemple : Nous souhaitons les contacts 30 à 60 triés par 'creationDate' décroissant et +'personName' croissant pour un navire donné par son topiaId :: + + EntityFilter filter = new EntityFilter(); + filter.setStartIndex(30); + filter.setEndIndex(60); + filter.setOrderBy("creationDate desc, personName"); + filter.setReferenceId(boat.getTopiaId()); + // ou filter.setReference(boat); + filter.setReferenceProperty("boat"); + + TopiaQuery query = contactDAO.createQuery().addFilter(filter); + +L'intérêt de l'EntityFilter est de pouvoir l'instancier et le manipuler directement +depuis votre interface (Swing, Web, ...) et de l'utiliser sur une requête métier. +La méthode **addFilter(EntityFilter filter)** permettra d'injecter les paramètres +s'ils possèdent une valeur. + +Note + L'ordre définit par défaut est celui de création par ordre décroissant : + *topiaCreateDate desc*. + Utilisation des DAO ~~~~~~~~~~~~~~~~~~~ Les DAO fournissent également quelques méthodes permettant de récupérer plus facilement les résultats avec le type souhaité : +- **countByQuery(TopiaQuery query)** : compte le nombre de résultats de la + requête. +- **existByQuery(TopiaQuery query)** : renvoie vrai si la requête à retourner + au moins 1 résultat. - **findByQuery(TopiaQuery query)** : renvoie une entité (un seul résultat) - **findAllByQuery(TopiaQuery query)** : renvoie une liste d'entités - **findAllMappedByQuery(TopiaQuery query)** : renvoie une map d'entités avec pour clé le topiaId de l'entité. -- **findAllMappedByQuery(TopiaQuery, Class keyClass, String keyProperty)** : +- **findAllMappedByQuery(TopiaQuery query, Class keyClass, String keyProperty)** : renvoie une map d'entités avec pour clé la propriété passée en argument. Exemple :: @@ -368,6 +419,13 @@ BoatDAO dao = ModelDAOHelper.getBoatDAO(transaction); TopiaQuery query = dao.createQuery(); ... + // pour vérifier l'existance de résultat + boolean hasResult = dao.existByQuery(query); + + // pour savoir le nombre de résultats + int count = dao.countByQuery(query); + + // pour récupérer les résultats Map<String, Boat> boatMap = dao.findAllMappedByQuery(query); // ou List<Boat> boatList = dao.findAllByQuery(query); @@ -377,14 +435,16 @@ Map<Integer, Boat> boatMapImma = dao.findAllMappedByQuery(query, Integer.class, Boat.IMMATRICULATION); + Résultats complexes ~~~~~~~~~~~~~~~~~~~ Certains cas de requête peuvent avoir des résultats plus complexes, notamment -lorsqu'il s'agit de propriété de différentes entités ou avec des aggrégats ( -AVG, SUM, COUNT). Dans ce cas il faut utiliser la méthode de base **execute()** -qui renvoie une liste non typée. Lorsqu'il y a plus d'un élément dans le select -la liste renvoyée est une List<Object[]>, le tableau pour chaque ligne +lorsqu'il s'agit de propriétés de différentes entités ou avec l'utilisation d' +aggrégats (AVG, SUM, COUNT). Dans ce cas il faut utiliser la méthode de base +**findByQuery(TopiaQuery query)** depuis une transaction +qui renverra une liste non typée. Lorsqu'il y a plus d'un élément dans le +select la liste renvoyée est une List<Object[]>, le tableau pour chaque ligne correspondant aux valeurs des résultats. Exemple :: TopiaContext transaction = rootContext.beginTransaction(); @@ -394,7 +454,7 @@ TopiaQuery query = dao.createQuery(). setSelect(boatImma, "COUNT(*)").addGroup(boatImma); - List<Object[]> results = query.execute(); + List<Object[]> results = transaction.findByQuery(query); // Parcours des résultats for (Object[] result : results) { Integer immatriculation = (Integer)result[0]; @@ -407,8 +467,8 @@ Chargement des donnees ---------------------- -Généralement une fois la requête exécuté, la transaction utilisé est directement -fermé (topiaContext.closeContext()). Dans ce cas, il est souvent nécessaire de +Généralement une fois la requête exécutée, la transaction utilisée est directement +fermée (topiaContext.closeContext()). Dans ce cas, il est souvent nécessaire de charger certaines entités pour éviter les malencontreuses LazyException d'Hibernate. Plusieurs possibilités s'offrent à vous : @@ -422,6 +482,8 @@ myapp.entity.Contact.attribute.boat.tagvalue.lazy=false +(*myapp.entity.Contact* étant le nom qualifié de la classe Contact) + Ainsi chaque contact récupéré aura automatiquement son navire associé de chargé. **Attention** cependant, il ne faut pas abuser du tagvalue *lazy* car sinon Hibernate @@ -447,7 +509,7 @@ modèle d'exemple, il est possible de charger le navire associé aux contacts en utilisant : queryContact.addLoad(Contact.BOAT); -Dans le cas du addLoad, plusieurs requêtes seront exécutés suivant le nombre +Dans le cas du addLoad, plusieurs requêtes seront exécutées suivant le nombre de Contact résultats. Il est dans ce cas plus judicieux d'utiliser le addFetch qui chargera directement les Boat au moment de la récupération des Contact : queryContact.addFetch(Contact.BOAT); L'alias peut s'avérer indispensable pour @@ -474,8 +536,8 @@ - Si addLoad non utilisable (trop de chargement de collections) : effectuer un chargement manuelle en parcourant les résultats. Pour le chargement d'une entité simple, il suffit d'utiliser le getter correspondant pour la charger, - tandis que pour une collection, l'appel à la méthode size permet de charger - l'intégralité des éléments. + tandis que pour une collection, l'appel à la méthode size associée permet de + charger l'intégralité des éléments.
participants (1)
-
fdesbois@users.nuiton.org