Introduction
Nous avons vu dans la première partie du tutoriel, comment créer des objets Java annotés avec JDO pour être sauvegardés dans le datastore de Google App Engine. Pour cette seconde partie, nous allons voir comment faire des requêtes sur le datastore. Avec JDO, il y a plusieurs façons de faire de requêtes, ici, nous allons vous présenter la façon la plus orientée Java. Comme pour le premier article, nous allons faire la comparaison avec MySQL pour que l’on retrouve rapidement nos repères. Bien entendu, nous allons faire les explications par l’exemple et nous allons reprendre les mêmes classes que dans la première partie, à savoir User, Level et Score.
PersistenceManagerFactory
Une application interagit avec JDO en utilisant une instance de la classe PersistenceManager. On récupère cette instance en instanciant et en appellant une méthode sur la classe PersistenceManagerFactory. La fabrique utilise la configuration de JDO pour créer les instances de PersistenceManager.
Etant donné que le PersistenceManagerFactory prend beaucoup de temps pour être initialisé, il est préférable qu’une application réutilise la même instance. Une exception est levée lorsque l’application instancie plusieurs fois un PersistenceManagerFactory avec le même identifiant. Une manière simple de gérer l’instance de PersistenceManagerFactory est de créer une classe enveloppe singleton avec une instance statique. On crée donc la classe PMF que l’on utilisera à chaque fois que l’on souhaite obtenir notre fabrique pour pouvoir ensuite récupérer le PersistenceManager. C’est bon vous suivez ?
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
public final class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
private PMF() {}
public static PersistenceManagerFactory get() {
return pmfInstance;
}
}
Select avec une condition
Afin d’organiser un peu son code, nous vous conseillons de créer une classe DBManager qui va contenir un ensemble de fonctions statiques pour gérer toutes les requêtes au datastore.
Allez, on démarre tout de suite avec un premier exemple, un simple SELECT avec une condition. Nous souhaitons retourner les Users qui ont un login correspondant à une certaine chaine de caractère. En SQL simple, nous ferions cette requête :
SELECT * FROM `user` WHERE login='bob'
En Java avec JDO, c’est un peu plus compliqué, mais pas insurmontable. Voici la fonction commentée pour faire la requête que nous souhaitons :
public static List<User> getLogin(String pLogin) {
// on récupère notre fameux PersistenceManager
PersistenceManager pm = PMF.get().getPersistenceManager();
// on fait une requête sur la "table" User
Query query = pm.newQuery(User.class);
// on ajoute une condition WHERE
// 'login' est le champ de la classe User
// 'loginParam' est le paramètre définit dans declareParameters()
query.setFilter("login == loginParam");
// on déclare le paramètre de la condition en précisant son type
query.declareParameters("String loginParam");
// on exécute la requête on passant le paramètre
return (List<User>) query.execute(pLogin);
}
Select avec plusieurs conditions
Passons à un exemple un tout petit peu plus compliqué avec deux conditions. En SQL, on ajoute un AND :
SELECT * FROM `user` WHERE login='bob' AND password='azertyuiop'
Pour reprendre notre exemple, il nous suffit de modifier l’expression booléenne de la méthode setFilter, de déclarer deux paramètres et de passer les deux valeurs au exécute :
public static List<User> getLogin(String pLogin, String pPassword) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(User.class);
query.setFilter("login == loginParam && password == passwordParam");
query.declareParameters("String loginParam, String passwordParam");
return (List<User>) query.execute(pLogin, pPassword);
}
Select avec une condition sur un type non primitif
Là, vous allez nous dire, oui, c’est bien jolie vos filtres, mais dans le datastore, un objet ne contient pas que des données avec des types simples contrairement à MySQL. Ne vous inquiétez pas, tout est prévu. Si l’on veut passer un objet de type non primitif en paramètre d’une requête, il suffit simplement de faire un import de cette classe (ici Key) sur l’objet Query grâce à la méthode declareImports. Voici un exemple d’une requête où nous ajoutons une condition avec un objet Key.
public static List<Level> getLevel(Key pKey) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(Level.class);
query.setFilter("key == keyParam");
query.declareImports("import com.google.appengine.api.datastore.Key;");
query.declareParameters("Key keyParam");
return (List<Level>) query.execute(pKey);
}
Sachez tout de même que l’exemple précédent sert à vous montrer comment utiliser la méthode declareImports(), si il s’agit uniquement de faire une requête aussi triviale que récupérer un objet via sa clé, vous pouvez le faire beaucoup plus simplement :
public static Level getLevel(Key pKey) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Level level = pm.getObjectById(Level.class, pKey);
return level;
}
Enregistrement
Passons maintenant à l’enregistrement de données. En SQL, nous avons une requête d’insertion différente pour chaque table, le nom de la table étant différent à chaque fois, ainsi que ses colonnes. Si nous souhaitons enregistrer un User en SQL, nous ferions donc comme ceci :
INSERT INTO `user` (`user_id` ,`login` ,`password`)
VALUES ('' , 'jean', 'qsdfghjklm');
Si nous voulons enregistrer un level, la requête n’a rien à voir :
INSERT INTO `tuto_jdo`.`level` (`level_id` ,`name`)
VALUES ('' , 'l003');
Avec NoSQL, c’est plus simple, il n’y a pas de notion de table, c’est comme si tout s’enregistrait dans la même table. C’est donc la même fonction qui va enregistrer tous les objets. Voici le code, c’est incroyablement simple :
public static void save(Object obj) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(obj);
} finally {
pm.close();
}
}
Notre tutorial en deux parties s’achève ici, nous espérons que ce tutorial vous aidera pour réaliser vos applications !
C’est dans cette optique que nous nous sommes penchés sur 
