Création, récupération et suppression de données dans JDO

Enregistrer un objet de données JDO dans le magasin de données consiste simplement à appeler la méthode makePersistent() de l'instance de PersistenceManager. L'implémentation de JDO par App Engine utilise le champ de clé primaire de l'objet pour déterminer l'entité du magasin de données qui correspond à l'objet de données. Cette implémentation peut générer automatiquement des clés pour les nouveaux objets. Vous pouvez utiliser des clés pour récupérer rapidement des entités, et construire des clés à partir de valeurs connues (telles que les identifiants de compte).

Déclarer des objets comme persistants

Pour stocker un objet de données simple dans le magasin de données, appelez la méthode makePersistent() de la classe PersistenceManager en lui transmettant l'instance.

PersistenceManager pm = PMF.get().getPersistenceManager();

Employee e = new Employee("Alfred", "Smith", new Date());

try {
    pm.makePersistent(e);
} finally {
    pm.close();
}

L'appel à makePersistent() est synchrone et ne rend la main qu'une fois l'objet enregistré et les index mis à jour.

Pour enregistrer plusieurs objets en JDO, appelez la méthode makePersistentAll(...) sur une collection d'objets. Cette méthode utilise une unique opération d'enregistrement par lots de bas niveau, plus efficace qu'une série d'invocations individuelles de makePersistent(...).

Remarque : Si des champs persistants d'objets de données constituent des références à d'autres objets de données persistants, et que certains de ces objets n'ont jamais été enregistrés ni modifiés depuis leur chargement, les objets référencés sont également enregistrés dans le magasin de données. Pour plus d'informations, consultez la page relative aux Relations.

Clés

Chacune des entités dans App Engine est associée à une clé unique. Une clé complète intègre différentes informations, telles que l'identifiant d'application, le genre et un identifiant d'entité. (Les clés contiennent également des informations sur les groupes d'entités. Pour plus d'informations, consultez la documentation sur les Transactions.)

La clé d'un objet est stockée dans un champ de l'instance. Vous identifiez le champ de clé primaire au moyen de l'annotation @PrimaryKey.

L'application peut fournir la partie identifiant de la clé sous la forme d'une chaîne lorsque l'objet est créé, ou elle peut autoriser le magasin de données à générer automatiquement un identifiant numérique. La clé complète de chacune des entités du magasin de données doit être unique. En d'autres termes, tous les objets de même genre et dotés du même parent de groupe d'entités (s'il y a lieu) doivent disposer d'un identifiant qui leur est propre. Vous sélectionnez le comportement souhaité de la clé à l'aide du type du champ et des annotations.

Si la classe est utilisée en tant que classe "enfant" dans une relation, le champ de clé doit être d'un type capable de représenter un parent de groupe d'entités : soit une instance de Key, soit une valeur de type Key codée sous forme de chaîne. Pour obtenir plus d'informations sur les groupes d'entités, consultez la page Transactions. Reportez-vous également à la page concernant les relations pour en savoir plus sur ces dernières.

Conseil : Si l'application crée un objet auquel elle attribue le même identifiant de chaîne qu'un autre objet de même genre (et doté du même parent de groupe d'entités), l'enregistrement de ce nouvel objet écrase l'autre objet dans le magasin de données. Afin de déterminer si un identifiant de chaîne est déjà en cours d'utilisation avant de créer un objet, vous pouvez utiliser une transaction pour tenter de récupérer une entité disposant d'un identifiant spécifique, puis créer cette entité si elle n'existe pas. Pour plus d'informations, consultez la page des Transactions.

Il existe quatre types de champs de clé primaire :

Long

Un entier long (java.lang.Long), identifiant d'entité généré automatiquement par le datastore. Utilisez ce type de champ pour les objets dépourvus de parent de groupe d'entités dont l'identifiant doit être généré automatiquement par le magasin de données. Le champ de clé long d'une instance est renseigné lorsque l'instance est enregistrée.

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
Chaîne non encodée

Une chaîne (java.lang.String), identifiant d'entité ("nom de clé") fourni par l'application lors de la création de l'objet. Utilisez ce type de champ pour les objets dépourvus de parent de groupe d'entités dont l'identifiant doit être fourni par l'application. L'application définit ce champ sur l'identifiant souhaité avant l'enregistrement.

import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    private String name;
Clé

Une instance de clé (com.google.appengine.api.datastore.Key). La valeur de clé inclut la clé du parent de groupe d'entités (s'il y a lieu), ainsi que l'identifiant de chaîne attribué par l'application ou l'identifiant numérique généré par le système. Pour créer l'objet avec un identifiant de chaîne attribué par l'application, vous créez la valeur Key avec l'identifiant, puis vous définissez le champ sur cette valeur. Pour créer l'objet avec un identifiant numérique généré par le système, laissez le champ de clé associé à la valeur null. (Pour plus d'informations sur l'utilisation des parents de groupes d'entités, consultez la documentation sur les Transactions.)

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    public void setKey(Key key) {
        this.key = key;
    }

L'application peut créer une instance Key à l'aide de la classe KeyFactory :

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

// ...
        Key key = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
        Employee e = new Employee();
        e.setKey(key);
        pm.makePersistent(e);
Clé sous forme de chaîne encodée

Type de champ semblable au type clé, mais doté d'une valeur correspondant à la forme chaîne encodée de la clé. Les clés au format de chaîne encodée vous permettent d'écrire votre application sous forme portable tout en tirant parti des groupes d'entités de magasin de données App Engine.

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String encodedKey;

L'application peut renseigner cette valeur avant l'enregistrement à l'aide d'une clé dotée d'un nom, ou bien laisser le champ défini sur null. Si le champ de clé encodée est associé à la valeur null, il est renseigné avec une clé générée par le système lors de l'enregistrement de l'objet.

Les instances de clé peuvent être converties de/vers la représentation en chaîne encodée à l'aide des méthodes respectives stringToKey() et keyToString().

Si vous utilisez des chaînes de clé encodées, vous pouvez donner accès à la chaîne ou à l'identifiant numérique d'un objet à travers un champ supplémentaire :

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String encodedKey;

    @Persistent
    @Extension(vendorName="datanucleus", key="gae.pk-name", value="true")
    private String keyName;

    // OR:

    @Persistent
    @Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
    private Long keyId;

Un champ "gae.pk-name" peut être défini sur un nom de clé avant l'enregistrement de l'objet. Lorsque l'objet est enregistré, le champ de clé encodée est renseigné avec la clé complète, qui inclut notamment le nom de la clé. Ce champ doit être de type String.

Un champ "gae.pk-id" est renseigné à l'enregistrement de l'objet et ne peut pas être modifié. Ce champ doit être de type Long.

Lorsqu'un nouvel objet ayant une clé générée (un champ de clé utilisant valueStrategy = IdGeneratorStrategy.IDENTITY) est créé, la valeur de sa clé est initialement null. Le champ de clé est renseigné au moment où l'objet est écrit dans le magasin de données. Si vous utilisez une transaction, l'objet est écrit lorsque la transaction est validée. Sinon, l'objet est écrit à l'appel de la méthode makePersistent() si l'objet est en cours de création ou à l'appel de la méthode close() de l'instance PersistenceManager si l'objet est mis à jour.

Pour plus d'informations sur la création de clés, consultez la documentation Entités, Propriétés et Clés.

Récupérer un objet par sa clé

Pour récupérer un objet à partir de sa clé, utilisez la méthode getObjectById() de la classe PersistenceManager. Cette méthode utilise la classe de l'objet, ainsi que la clé :

        Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
        Employee e = pm.getObjectById(Employee.class, k);

Si la classe utilise un champ de clé qui est un ID de chaîne non codé (String) ou un ID numérique (Long), getObjectByID() peut prendre la valeur simple en tant que paramètre de clé :

        Employee e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");

L'argument de clé peut être de l'un des types de champs de clé pris en charge (identifiant de chaîne, identifiant numérique, valeur Key, chaîne de clé encodée), ce type pouvant être différent de celui du champ de clé dans la classe. App Engine doit être en mesure de déterminer la clé complète à partir du nom de la classe et de la valeur fournie. Les identifiants de chaîne et les identifiants numériques s'excluent mutuellement ; en d'autres termes, un appel utilisant un identifiant numérique ne renvoie jamais d'entité avec un identifiant de chaîne. En cas d'utilisation d'une valeur Key ou d'une chaîne de clé encodée, la clé doit faire référence à une entité dont le genre est représenté par la classe.

Mettre un objet à jour

L'une des méthodes possibles pour mettre à jour un objet avec JDO consiste à récupérer ce dernier, puis à le modifier pendant que le gestionnaire PersistenceManager ayant renvoyé l'objet est encore ouvert. Les modifications sont conservées après la fermeture du gestionnaire PersistenceManager. Exemple :

public void updateEmployeeTitle(User user, String newTitle) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    try {
        Employee e = pm.getObjectById(Employee.class, user.getEmail());
        if (titleChangeIsAuthorized(e, newTitle) {
            e.setTitle(newTitle);
        } else {
            throw new UnauthorizedTitleChangeException(e, newTitle);
        }
    } finally {
        pm.close();
    }
}

Puisque l'instance Employee a été renvoyée par l'objet PersistenceManager, celui-ci est informé de toutes les modifications apportées aux champs Persistent de l'objet Employee et met automatiquement à jour le magasin de données avec ces modifications à la fermeture de l'objet PersistenceManager. En effet, l'instance de classe Employee est "attachée" à l'objet PersistenceManager.

Vous pouvez modifier un objet après la fermeture du PersistenceManager en déclarant la classe comme "détachable". Pour ce faire, ajoutez l'attribut detachable à l'annotation @PersistenceCapable :

import javax.jdo.annotations.PersistenceCapable;

@PersistenceCapable(detachable="true")
public class Employee {
    // ...
}

Vous êtes alors en mesure de lire et de modifier les champs d'un objet Employee après la fermeture du gestionnaire PersistenceManager qui a chargé cet objet. L'exemple qui suit illustre l'utilité d'un objet détaché :

public Employee getEmployee(User user) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    Employee employee, detached = null;
    try {
        employee = pm.getObjectById(Employee.class,
            "Alfred.Smith@example.com");

        // If you're using transactions, you can call
        // pm.setDetachAllOnCommit(true) before committing to automatically
        // detach all objects without calls to detachCopy or detachCopyAll.
        detached = pm.detachCopy(employee);
    } finally {
        pm.close();
    }
    return detached;
}

public void updateEmployeeTitle(Employee e, String newTitle) {
    if (titleChangeIsAuthorized(e, newTitle) {
        e.setTitle(newTitle);
        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            pm.makePersistent(e);
        } finally {
            pm.close();
        }
    } else {
        throw new UnauthorizedTitleChangeException(e, newTitle);
    }
}

Les objets détachés constituent une alternative efficace à la création d'objets de transfert de données. Pour plus d'informations sur l'utilisation d'objets détachés, consultez la documentation de DataNucleus.

Suppression d'un objet

Pour supprimer un objet du magasin de données, appelez la méthode deletePersistent() de la classe PersistenceManager sur l'objet :

pm.deletePersistent(e);

Pour supprimer plusieurs objets en JDO, appelez la méthode deletePersistentAll(...) sur une collection d'objets. Cette méthode utilise une unique opération de suppression par lots de bas niveau, plus efficace qu'une série d'invocations individuelles de deletePersistent(...).

Si un objet comporte des champs contenant des objets enfants eux-mêmes persistants, ces derniers sont également supprimés. Pour plus d'informations, consultez la page des Relations.

Pour supprimer tous les objets correspondant à une requête, vous pouvez utiliser la fonction "Supprimer par requête" de JDOQL. Pour plus d'informations, consultez la page Supprimer des entités par requête.

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Environnement standard App Engine pour Java 8