Utilisation de JPA avec App Engine

Java Persistence API (JPA) est une interface standard permettant d'accéder à des bases de données en Java. Elle fournit un mappage automatique entre les classes Java et les tables de base de données. Un plug-in Open Source est disponible pour utiliser JPA avec Datastore. Cette page explique comment faire vos premiers pas avec ce plug-in.

Avertissement : Nous pensons que la plupart des développeurs pourront améliorer leur expérience en tirant parti de l'API Datastore de bas niveau ou de l'une des API Open Source développées spécifiquement pour Datastore, comme Objectify. JPA a été conçue pour être utilisée avec des bases de données classiques et n'a donc aucun moyen de représenter explicitement certains des aspects qui différencient Datastore des bases de données relationnelles, tels que les groupes d'entités et les requêtes ascendantes. Cela peut entraîner des problèmes subtils, difficiles à comprendre et à résoudre.

Le SDK Java App Engine intègre la version 2.x du plug-in DataNucleus pour Datastore. Ce plugin correspond à la version 3.0 de la plate-forme d'accès DataNucleus, ce qui vous permet d'utiliser App Engine Datastore via JPA 2.0.

Pour plus d'informations sur JPA, consultez la documentation d'Access Platform 3.0, en particulier les sections concernant JPA et l'API JPA.

Avertissement : La version 2.x du plug-in DataNucleus pour App Engine utilise DataNucleus en version 3.x. Le plug-in 2.x n'est pas totalement rétrocompatible avec le plug-in précédent 1.x. Si vous effectuez une mise à niveau vers la nouvelle version, veillez à mettre à jour votre application et à la tester.

Compiler des outils compatibles avec JPA 2.x et 3.0

Vous pouvez utiliser Apache Ant ou Maven pour utiliser la version 2.x ou 3.0 du plug-in DataNucleus pour App Engine :

  • Pour les utilisateurs d'Ant : le SDK comprend une tâche Ant qui effectue la phase d'enrichissement. Vous devez copier les fichiers JAR et créer le fichier de configuration au moment où vous configurez votre projet.
  • Pour les utilisateurs de Maven : vous pouvez enrichir les classes avec les configurations suivantes dans votre fichier pom.xml :
                <plugin>
                    <groupId>org.datanucleus</groupId>
                    <artifactId>maven-datanucleus-plugin</artifactId>
                    <version>3.2.0-m1</version>
                    <configuration>
                        <api>JDO</api>
                        <props>${basedir}/datanucleus.properties</props>
                        <verbose>true</verbose>
                        <enhancerName>ASM</enhancerName>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>process-classes</phase>
                            <goals>
                                <goal>enhance</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.datanucleus</groupId>
                            <artifactId>datanucleus-api-jdo</artifactId>
                            <version>3.1.3</version>
                        </dependency>
                    </dependencies>
                </plugin>

Migrer vers la version 2.x du plug-in DataNucleus

Cette section fournit des instructions vous permettant de mettre à niveau votre application pour qu'elle utilise la version 2.x du plug-in DataNucleus pour App Engine, qui correspond à la plate-forme d'accès DataNucleus 3.0 et à JPA 2.0. La version 2.x du plug-in n'est pas totalement rétrocompatible avec la version 1.x, et elle est susceptible d'être modifiée sans préavis. Si vous effectuez une mise à niveau, veillez à mettre à jour le code de votre application et à le tester.

Nouveaux comportements par défaut

La version 2.x du plug-in DataNucleus pour App Engine possède des valeurs par défaut différentes de la version précédente 1.x :

  • Le "fournisseur de persistance" JPA s'appelle désormais org.datanucleus.api.jpa.PersistenceProviderImpl.
  • La mise en cache de niveau 2 est activée par défaut. Pour revenir au comportement par défaut précédent, définissez la propriété de persistance datanucleus.cache.level2.type sur la valeur none. (Vous pouvez également inclure le plug-in datanucleus-cache dans le paramètre "classpath" et définir la propriété de persistance datanucleus.cache.level2.type sur la valeur javax.cache afin d'utiliser Memcache pour la mise en cache L2.)
  • L'élément IdentifierFactory de Datastore est désormais défini par défaut sur la valeur datanucleus2. Pour revenir au comportement précédent, définissez la propriété de persistance datanucleus.identifierFactory sur la valeur datanucleus1.
  • Les appels non transactionnels à EntityManager.persist(), EntityManager.merge() et EntityManager.remove() sont maintenant exécutés de manière atomique. (Auparavant, l'exécution avait lieu à la transaction suivante ou lors de l'appel à EntityManager.close().)
  • Dans JPA, retainValues est activé, ce qui signifie que les valeurs des champs chargés sont conservées dans les objets après un commit.
  • javax.persistence.query.chunkSize n'est plus utilisé. Utilisez datanucleus.query.fetchSize à la place.
  • Il n'y a plus d'exception sur l'allocation EMF en double. Si la propriété de persistance datanucleus.singletonEMFForName est définie sur la valeur true, elle renvoie l'EMF singleton actuellement alloué pour ce nom.
  • Les relations sans propriétaire sont désormais prises en charge.
  • Datastore Identity est désormais pris en charge.

Pour obtenir la liste complète des nouvelles fonctionnalités, consultez les notes de version.

Modifications apportées aux fichiers de configuration

Pour mettre à niveau votre application vers la version 2.x du plug-in DataNucleus pour App Engine, vous devez modifier certains paramètres de configuration dans les fichiers build.xml et persistence.xml. Si vous configurez une nouvelle application et souhaitez utiliser la dernière version du plug-in DataNucleus, passez à la section Configurer JPA 2.0.

Avertissement ! Après avoir mis à jour votre configuration, vous devez tester le code de votre application pour en garantir la rétrocompatibilité.

Dans build.xml

La cible copyjars doit être modifiée afin de prendre en charge DataNucleus 2.x :

  1. La cible copyjars a été modifiée. Remplacez la section ci-après :
      <target name="copyjars"
          description="Copies the App Engine JARs to the WAR.">
        <mkdir dir="war/WEB-INF/lib" />
        <copy
            todir="war/WEB-INF/lib"
            flatten="true">
          <fileset dir="${sdk.dir}/lib/user">
            <include name="**/*.jar" />
          </fileset>
        </copy>
      </target>

    par :
      <target name="copyjars"
          description="Copies the App Engine JARs to the WAR.">
        <mkdir dir="war/WEB-INF/lib" />
        <copy
            todir="war/WEB-INF/lib"
            flatten="true">
          <fileset dir="${sdk.dir}/lib/user">
            <include name="**/appengine-api-1.0-sdk*.jar" />
          </fileset>
          <fileset dir="${sdk.dir}/lib/opt/user">
            <include name="appengine-api-labs/v1/*.jar" />
            <include name="jsr107/v1/*.jar" />
            <include name="datanucleus/v2/*.jar" />
          </fileset>
        </copy>
      </target>
  2. La cible datanucleusenhance a été modifiée. Remplacez la section ci-après :
      <target name="datanucleusenhance" depends="compile"
          description="Performs enhancement on compiled data classes.">
        <enhance_war war="war" />
      </target>

    vers :
      <target name="datanucleusenhance" depends="compile"
          description="Performs enhancement on compiled data classes.">
          <enhance_war war="war">
                  <args>
                  <arg value="-enhancerVersion"/>
                  <arg value="v2"/>
              </args>
          </enhance_war>
      </target>

Dans persistence.xml

La cible <provider> a changé. Mettez à jour la section suivante :

        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>

vers :

        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>

Configurer JPA 2.0

Pour accéder au magasin de données au moyen de JPA, une application App Engine a besoin que les conditions suivantes soient remplies :

  • Les fichiers JAR de JPA et de Datastore doivent figurer dans le répertoire war/WEB-INF/lib/ de l'application.
  • Un fichier de configuration nommé persistence.xml doit figurer dans le répertoire war/WEB-INF/classes/META-INF/ de l'application, avec une configuration qui indique à JPA d'utiliser le magasin de données d'App Engine.
  • Le processus de compilation du projet doit exécuter une étape "d'enrichissement" post-compilation sur les classes de données compilées pour les associer à la mise en œuvre JPA.

Copie des fichiers JAR

Les fichiers JAR de JPA et du datastore sont inclus dans le SDK Java d'App Engine. Vous pouvez les trouver dans le répertoire appengine-java-sdk/lib/opt/user/datanucleus/v2/.

Copiez les fichiers JAR dans le répertoire war/WEB-INF/lib/ de votre application.

Assurez-vous que appengine-api.jar se trouve également dans le répertoire war/WEB-INF/lib/. (Vous l'avez peut-être déjà copié au moment de la création du projet.) Le plug-in DataNucleus App Engine utilise ce fichier JAR pour accéder au magasin de données.

Création du fichier persistence.xml

L'interface JPA requiert un fichier de configuration nommé persistence.xml dans le répertoire war/WEB-INF/classes/META-INF/ de l'application. Vous pouvez créer directement ce fichier à cet emplacement, ou paramétrer votre processus de compilation afin de copier ce fichier à partir d'un répertoire source.

Créez le fichier en y incluant le contenu suivant :

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
            <property name="datanucleus.singletonEMFForName" value="true"/>
        </properties>

    </persistence-unit>

</persistence>

Règles de lecture et durée maximale de l'appel au Datastore

Comme décrit sur la page Requêtes Datastore, vous pouvez définir dans le fichier EntityManagerFactory la règle de lecture (cohérence forte ou à terme) et la durée maximale de l'appel au datastore pour une instance persistence.xml. Ces paramètres sont définis dans l'élément <persistence-unit>. Tous les appels passés avec une instance EntityManager donnée utiliseront la configuration en vigueur lors de la création du gestionnaire par EntityManagerFactory. Vous pouvez également ignorer ces options pour un objet Query spécifique (comme décrit ci-dessous).

Pour définir les règles de lecture, incluez une propriété nommée datanucleus.appengine.datastoreReadConsistency. Ses valeurs possibles sont EVENTUAL (pour les lectures avec cohérence à terme) et STRONG (pour les lectures avec cohérence forte). Si aucune valeur n'est spécifiée, la valeur par défaut de cet argument est STRONG.

            <property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" />

Le délai d'appel vers le magasin de données que vous définissez pour les lectures peut différer de celui défini pour les écritures. Pour les lectures, utilisez la propriété standard JPA javax.persistence.query.timeout. Pour les écritures, utilisez datanucleus.datastoreWriteTimeout. La valeur du délai d'appel correspond à une durée exprimée en millisecondes.

            <property name="javax.persistence.query.timeout" value="5000" />
            <property name="datanucleus.datastoreWriteTimeout" value="10000" />

Si vous souhaitez utiliser des transactions (XG) entre les groupes, ajoutez la propriété suivante :

            <property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true" />

Vous pouvez avoir plusieurs éléments <persistence-unit> dans le même fichier persistence.xml, utilisant différents attributs name pour utiliser des instances EntityManager avec différentes configurations dans la même application. Par exemple, le fichier persistence.xml suivant établit deux configurations, l'une nommée "transactions-optional" et l'autre "eventual-reads-short-deadlines" :

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>

    <persistence-unit name="eventual-reads-short-deadlines">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>

            <property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" />
            <property name="javax.persistence.query.timeout" value="5000" />
            <property name="datanucleus.datastoreWriteTimeout" value="10000" />
            <property name="datanucleus.singletonEMFForName" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Pour en savoir plus sur la création d'une instance EntityManager avec un ensemble de configuration nommé, consultez la section EntityManager ci-dessous.

Vous pouvez ignorer les règles de lecture et la durée maximale de l'appel pour un objet Query spécifique. Pour ignorer les règles de lecture pour un Query, appelez sa méthode setHint() comme indiqué ici :

        Query q = em.createQuery("select from " + Book.class.getName());
        q.setHint("datanucleus.appengine.datastoreReadConsistency", "EVENTUAL");

Comme indiqué précédemment, les valeurs possibles sont "EVENTUAL" et "STRONG".

Pour ignorer le délai de lecture, appelez setHint() comme ci-dessous :

        q.setHint("javax.persistence.query.timeout", 3000);

Il n'existe aucun moyen d'ignorer la configuration de ces options lorsque vous récupérez des entités par leur clé.

Enrichissement du code des classes de données

La mise en œuvre DataNucleus de JPA ajoute au processus de compilation une étape "d'enrichissement" post-compilation, afin d'associer des classes de données à la mise en œuvre de JPA.

Pour appliquer l'opération d'enrichissement du code aux classes compilées, exécutez la commande ci-après à partir de la ligne de commande :

java -cp classpath org.datanucleus.enhancer.DataNucleusEnhancer
class-files

Le paramètre classpath doit contenir les fichiers JAR datanucleus-core-*.jar, datanucleus-jpa-*, datanucleus-enhancer-*.jar, asm-*.jar et geronimo-jpa-*.jar (où * représente le numéro de version adéquat pour chaque JAR) du répertoire appengine-java-sdk/lib/tools/, ainsi que toutes vos classes de données.

Pour plus d'informations sur l'outil d'enrichissement de bytecode DataNucleus, consultez la documentation relative à DataNucleus.

Récupérer une instance EntityManager

Une application interagit avec JPA à l'aide d'une instance de la classe EntityManager. Pour récupérer cette instance, vous devez instancier la classe EntityManagerFactory et appeler une méthode sur cet objet. La fabrique utilise la configuration JPA (identifiée par le nom "transactions-optional") pour créer des instances EntityManager.

Étant donné que l'initialisation d'une instance EntityManagerFactory demande un certain temps, il est recommandé de réutiliser cette dernière autant de fois que possible. Un moyen simple d'effectuer cette opération consiste à créer une classe wrapper singleton avec une instance statique à l'aide du code suivant :

EMF.java

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public final class EMF {
    private static final EntityManagerFactory emfInstance =
        Persistence.createEntityManagerFactory("transactions-optional");

    private EMF() {}

    public static EntityManagerFactory get() {
        return emfInstance;
    }
}

Conseil : "transactions-optional" fait référence au nom de l'ensemble de configuration figurant dans le fichier persistence.xml. Si votre application utilise plusieurs configurations, vous devrez étendre ce code pour appeler Persistence.createEntityManagerFactory() à votre guise. Votre code doit mettre en cache une instance unique de chaque EntityManagerFactory.

L'application utilise l'instance de fabrique afin de créer une instance EntityManager pour chaque requête qui accède au magasin de données.

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import EMF;

// ...
    EntityManager em = EMF.get().createEntityManager();

Vous utilisez l'instance EntityManager pour stocker, mettre à jour et supprimer des objets de données, ainsi que pour exécuter des requêtes de magasin de données.

Dès que vous avez terminé avec l'instance EntityManager, appelez sa méthode close(). L'instance EntityManager ne doit pas être utilisée après avoir appelé sa méthode close().

    try {
        // ... do stuff with em ...
    } finally {
        em.close();
    }

Annotations de classe et de champ

Chaque objet enregistré par JPA devient une entité du magasin de données App Engine. Le genre de l'entité est dérivé du nom simple de la classe (sans le nom du package). Chaque champ persistant de la classe représente une propriété de l'entité, dont le nom correspond au nom du champ (en respectant la distinction majuscules-minuscules).

Pour indiquer qu'une classe Java peut être stockée et extraite du magasin de données à l'aide de JPA, associez à cette classe une annotation @Entity. Exemple :

import javax.persistence.Entity;

@Entity
public class Employee {
    // ...
}

Les champs de la classe de données qui doivent être stockés dans le magasin de données doivent être d'un type persistant par défaut ou être explicitement déclarés comme persistants. Vous pouvez trouver un graphique détaillant le comportement de persistance par défaut de JPA sur le site Web de DataNucleus. Pour déclarer explicitement un champ comme persistant, attribuez-lui une annotation @Basic :

import java.util.Date;
import javax.persistence.Enumerated;

import com.google.appengine.api.datastore.ShortBlob;

// ...
    @Basic
    private ShortBlob data;

Les types de champs possibles sont répertoriés ci-dessous :

  • L'un des types de base pris en charge par le magasin de données
  • Une collection (telle qu'un objet java.util.List<...>) de valeurs de l'un des types de datastore de base
  • Une instance ou une collection d'instances d'une classe @Entity
  • Une classe encapsulée, stockée sous forme de propriétés dans l'entité

Une classe de données doit disposer d'un constructeur par défaut public ou protégé, ainsi que d'un champ dédié au stockage de la clé primaire de l'entité correspondante dans le magasin de données. Vous pouvez choisir parmi quatre genres de champs de clé, chacun utilisant un type de valeur et des annotations distincts. (Pour plus d'informations, consultez la page Créer des données : clés.) Le champ de clé le plus simple correspond à un entier long qui est automatiquement renseigné par JPA avec une valeur unique pour l'ensemble des instances de la classe lorsque l'objet est enregistré pour la première fois dans le magasin de données. Les clés de type entier long utilisent une annotation @Id et une annotation @GeneratedValue(strategy = GenerationType.IDENTITY) :

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

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

// ...
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;

Voici un exemple de classe de données :

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

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;

    private String firstName;

    private String lastName;

    private Date hireDate;

    // Accessors for the fields. JPA doesn't use these, but your application
    does.

    public Key getKey() {
        return key;
    }

    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getHireDate() {
        return hireDate;
    }
    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }
}

Héritage

JPA prend en charge la création de classes de données qui utilisent des stratégies d'héritage. Avant d'aborder le fonctionnement de l'héritage JPA dans App Engine, nous vous recommandons de consulter la documentation DataNucleus sur ce sujet, puis de reprendre votre lecture de cette documentation. C'est fait ? D'accord. L'héritage JPA dans App Engine fonctionne comme décrit dans la documentation de DataNucleus, avec quelques restrictions supplémentaires. Cette section spécifie ces restrictions, puis en présente quelques exemples concrets.

La stratégie d'héritage "JOINED" (par jointure) vous permet de fractionner les données d'un même objet de données dans différentes "tables". Toutefois, du fait que le magasin de données d'App Engine n'est pas compatible avec les jointures, l'utilisation d'un objet de données avec cette stratégie d'héritage nécessite un appel de procédure à distance pour chaque niveau d'héritage. C'est un fonctionnement potentiellement très inefficace. Par conséquent, la stratégie d'héritage "JOINED" n'est pas compatible avec les classes de données.

Par ailleurs, la stratégie d'héritage "SINGLE_TABLE" (table unique) vous permet de stocker les données d'un objet de données dans une "table" unique associée à la classe persistante figurant à la racine de votre hiérarchie d'héritage. Bien que cette stratégie ne présente pas de risque d'inefficacité, elle n'est pas prise en charge à ce jour. Cet aspect sera éventuellement modifié dans les versions ultérieures.

Maintenant, voici la bonne nouvelle : les stratégies "TABLE_PER_CLASS" et "MAPPED_SUPERCLASS" fonctionnent comme décrit dans la documentation de DataNucleus. Voyons un exemple :

Worker.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@Entity
@MappedSuperclass
public abstract class Worker {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;

    private String department;
}

Employee.java

// ... imports ...

@Entity
public class Employee extends Worker {
    private int salary;
}

Intern.java

import java.util.Date;
// ... imports ...

@Entity
public class Intern extends Worker {
    private Date internshipEndDate;
}

Dans cet exemple, nous avons ajouté une annotation @MappedSuperclass à la déclaration de la classe Worker. Cela indique à JPA de stocker tous les champs persistants de la classe Worker dans les entités du magasin de données correspondant à ses sous-classes. L'entité du magasin de données créée à la suite de l'appel de persist() sur une instance Employee possède deux propriétés nommées "department" et "salary". L'entité du magasin de données créée à la suite de l'appel de persist() sur une instance Intern possède deux propriétés nommées "department" et "internshipEndDate". Le magasin de données ne contient aucune entité du genre "Worker".

Passons maintenant à un aspect un peu plus intéressant. Supposons qu’en plus des classes Employee et Intern, nous souhaitons également disposer d'une spécialisation de la classe Employee représentant les employés qui ont quitté la société :

FormerEmployee.java

import java.util.Date;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
// ... imports ...

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class FormerEmployee extends Employee {
    private Date lastDay;
}

Dans cet exemple, nous avons ajouté une annotation @Inheritance à la déclaration de la classe FormerEmployee, avec un attribut strategy défini sur InheritanceType.TABLE_PER_CLASS. Cela indique à JPA de stocker tous les champs persistants de la classe FormerEmployee et de ses super-classes dans les entités de datastore correspondant aux instances FormerEmployee. L'entité du magasin de données créée à la suite de l'appel de persist() sur une instance FormerEmployee possède trois propriétés nommées "department", "salary" et "lastDay". Il n'y aura jamais d'entité du genre "Employee" correspondant à un FormerEmployee mais, si vous appelez persist() avec un objet dont le type d'exécution est Employee, vous créez une entité de type "Employee".

L'utilisation combinée de relations et de stratégies d'héritage fonctionne tant que les types déclarés de vos champs de relations correspondent aux types d'exécution des objets que vous attribuez à ces champs. Pour plus d'informations, reportez-vous à la section sur les relations polymorphes. Bien que cette section présente des exemples relatifs à JDO, les concepts et les restrictions qui s'appliquent à JDO sont les mêmes que pour JPA.

Fonctionnalités non compatibles de JPA 2.0

Les fonctionnalités de l'interface JPA non prises en charge par l'implémentation App Engine sont les suivantes :

  • Relations d'appartenance plusieurs à plusieurs.
  • Requêtes "Join". Vous ne pouvez pas utiliser un champ d'une entité enfant dans un filtre lorsque vous exécutez une requête sur le genre parent. Notez que vous pouvez tester directement le champ de relation du parent dans une requête à l'aide d'une clé.
  • Requêtes d'agrégation (GROUP BY, HAVING, SUM, AVG, MAX, MIN).
  • Requêtes polymorphes. Vous ne pouvez pas exécuter de requête d'une classe pour récupérer des instances d'une sous-classe. Chaque classe est représentée par un genre d'entité distinct dans le datastore.
Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Environnement standard App Engine pour Java