Menggunakan JPA dengan App Engine

Java Persistence API (JPA) adalah antarmuka standar untuk mengakses database di Java, yang menyediakan pemetaan otomatis antara class Java dan tabel database. Ada plugin open source yang tersedia untuk menggunakan JPA dengan Datastore, dan halaman ini memberikan informasi tentang cara mulai menggunakannya.

Peringatan: Menurut kami, sebagian besar developer akan memiliki pengalaman yang lebih baik menggunakan Datastore API tingkat rendah, atau salah satu API open source yang dikembangkan khusus untuk Datastore, seperti Objectify. JPA dirancang untuk digunakan dengan database relasional tradisional, sehingga tidak memiliki cara untuk secara eksplisit mewakili beberapa aspek Datastore yang membuatnya berbeda dengan database relasional, seperti entity group dan kueri ancestor. Hal ini dapat menyebabkan masalah ringan yang sulit dipahami dan diperbaiki.

App Engine Java SDK menyertakan versi 2.x dari plugin DataNucleus untuk Datastore. Plugin ini sesuai dengan DataNucleus Access Platform versi 3.0, yang memungkinkan Anda menggunakan App Engine Datastore melalui JPA 2.0.

Lihat dokumentasi Access Platform 3.0 untuk informasi selengkapnya tentang JPA. Secara khusus, lihat Dokumentasi JPA.

Peringatan: Plugin DataNucleus versi 2.x untuk App Engine menggunakan DataNucleus v3.x. Plugin 2.x tidak sepenuhnya kompatibel dengan plugin sebelumnya, yakni plugin 1.x. Jika Anda mengupgrade ke versi baru, pastikan untuk mengupdate dan menguji aplikasi.

Alat build yang mendukung JPA 2.x dan 3.0

Anda dapat menggunakan Apache Ant atau Maven untuk menggunakan plugin DataNucleus versi 2.x atau 3.0 untuk App Engine:

  • Untuk pengguna Ant: SDK menyertakan tugas Ant yang melakukan langkah peningkatan. Anda harus menyalin JAR dan membuat file konfigurasi saat menyiapkan project.
  • Untuk pengguna Maven: Anda dapat meningkatkan class dengan konfigurasi berikut di file 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>

Bermigrasi ke Versi 2.x Plugin DataNucleus

Bagian ini memberikan petunjuk untuk mengupgrade aplikasi Anda agar dapat menggunakan plugin DataNucleus versi 2.x untuk App Engine, yang sesuai dengan DataNucleus Access Platform 3.0 dan JPA 2.0. Versi plugin 2.x tidak sepenuhnya kompatibel dengan versi 1.x dan dapat berubah tanpa peringatan. Jika Anda mengupgrade, pastikan untuk mengupdate dan menguji kode aplikasi.

Perilaku Default Baru

Plugin App Engine DataNucleus versi 2.x memiliki beberapa default yang berbeda dari versi 1.x sebelumnya:

  • "Penyedia persistensi" JPA sekarang menjadi org.datanucleus.api.jpa.PersistenceProviderImpl.
  • Caching Level2 diaktifkan secara default. Untuk mendapatkan perilaku default sebelumnya, tetapkan properti persistensi datanucleus.cache.level2.type ke none. (Atau, sertakan plugin datanucleus-cache di classpath, dan tetapkan properti persistensi datanucleus.cache.level2.type ke javax.cache agar menggunakan Memcache untuk caching L2.
  • Datastore IdentifierFactory kini ditetapkan secara default ke datanucleus2. Untuk mendapatkan perilaku sebelumnya, tetapkan properti persistensi datanucleus.identifierFactory ke datanucleus1.
  • Panggilan non-transaksi ke EntityManager.persist(), EntityManager.merge(), dan EntityManager.remove() sekarang dijalankan secara atomik. (Sebelumnya, eksekusi terjadi pada transaksi berikutnya atau pada EntityManager.close().
  • JPA telah mengaktifkan retainValues, yang berarti nilai kolom yang diisi akan dipertahankan dalam objek setelah commit.
  • javax.persistence.query.chunkSize tidak digunakan lagi. Sebagai gantinya, gunakan datanucleus.query.fetchSize.
  • Sekarang tidak ada lagi pengecualian pada alokasi EMF duplikat. Jika Anda menetapkan properti persistensi datanucleus.singletonEMFForName ke true, properti tersebut akan menampilkan EMF singleton yang saat ini dialokasikan untuk nama tersebut.
  • Hubungan yang tidak dimiliki kini didukung.
  • Datastore Identity sekarang didukung.

Untuk daftar lengkap fitur baru, lihat catatan rilis.

Perubahan pada File Konfigurasi

Untuk mengupgrade aplikasi agar menggunakan plugin DataNucleus versi 2.0 untuk App Engine, Anda perlu mengubah beberapa setelan konfigurasi di build.xml dan persistence.xml. Jika Anda menyiapkan aplikasi baru dan ingin menggunakan plugin DataNucleus versi terbaru, lanjutkan ke Menyiapkan JPA 2.0.

Peringatan! Setelah mengupdate konfigurasi, Anda harus menguji kode aplikasi untuk memastikan kompatibilitas mundur.

Di build.xml

Target copyjars perlu diubah untuk mengakomodasi DataNucleus 2.x:

  1. Target copyjars telah diubah. Perbarui bagian ini:
      <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>

    menjadi:
      <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. Target datanucleusenhance telah diubah. Perbarui bagian ini:
      <target name="datanucleusenhance" depends="compile"
          description="Performs enhancement on compiled data classes.">
        <enhance_war war="war" />
      </target>

    menjadi:
      <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>

Di persistence.xml

Target <provider> telah diubah. Perbarui bagian ini:

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

menjadi:

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

Menyiapkan JPA 2.0

Untuk menggunakan JPA guna mengakses datastore, aplikasi App Engine memerlukan hal berikut:

  • JPA dan JAR datastore harus berada di direktori war/WEB-INF/lib/ aplikasi.
  • File konfigurasi bernama persistence.xml harus berada di direktori war/WEB-INF/classes/META-INF/ aplikasi, dengan konfigurasi yang memberi tahu JPA agar menggunakan datastore App Engine.
  • Proses build project harus melakukan langkah "peningkatan" pascakompilasi pada class data yang dikompilasi untuk mengaitkannya dengan implementasi JPA.

Menyalin JAR

JPA dan JAR datastore disertakan dengan App Engine Java SDK. Anda dapat menemukannya di direktori appengine-java-sdk/lib/opt/user/datanucleus/v2/.

Salin JAR ke direktori war/WEB-INF/lib/ aplikasi Anda.

Pastikan appengine-api.jar juga ada dalam direktori war/WEB-INF/lib/. (Anda mungkin sudah menyalin ini saat membuat project.) Plugin DataNucleus App Engine menggunakan JAR ini untuk mengakses datastore.

Membuat File persistence.xml

Antarmuka JPA memerlukan file konfigurasi bernama persistence.xml di direktori war/WEB-INF/classes/META-INF/ aplikasi. Anda dapat membuat file ini di lokasi ini secara langsung, atau meminta proses build menyalin file ini dari direktori sumber.

Buat file dengan konten berikut:

<?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>

Kebijakan Baca Datastore dan Batas Waktu Panggilan

Seperti yang dijelaskan di halaman Kueri Datastore, Anda dapat menetapkan kebijakan baca (konsistensi kuat vs. konsistensi tertunda) dan batas waktu panggilan datastore untuk EntityManagerFactory di file persistence.xml. Setelan ini masuk ke elemen <persistence-unit>. Semua panggilan yang dilakukan dengan instance EntityManager tertentu menggunakan konfigurasi yang dipilih saat pengelola dibuat oleh EntityManagerFactory. Anda juga dapat mengganti opsi ini untuk setiap Query (dijelaskan di bawah).

Untuk menetapkan kebijakan baca, sertakan properti bernama datanucleus.appengine.datastoreReadConsistency. Kemungkinan nilainya adalah EVENTUAL (untuk pembacaan dengan konsistensi tertunda) dan STRONG (untuk pembacaan dengan konsistensi kuat). Jika tidak ditentukan, jumlah defaultnya adalah STRONG.

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

Anda dapat menetapkan batas waktu panggilan datastore terpisah untuk pembacaan dan penulisan. Untuk pembacaan, gunakan properti standar JPA javax.persistence.query.timeout. Untuk penulisan, gunakan datanucleus.datastoreWriteTimeout. Nilainya adalah jumlah waktu, dalam milidetik.

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

Jika Anda ingin menggunakan transaksi lintas grup (XG), tambahkan properti berikut:

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

Anda dapat memiliki beberapa elemen <persistence-unit> dalam file persistence.xml yang sama, dengan menggunakan atribut name yang berbeda, untuk menggunakan instance EntityManager dengan konfigurasi yang berbeda di aplikasi yang sama. Misalnya, file persistence.xml berikut membuat dua kumpulan konfigurasi, satu bernama "transactions-optional" dan lainnya bernama "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>

Lihat Mendapatkan Instance EntityManager di bawah untuk informasi tentang cara membuat EntityManager dengan set konfigurasi bernama.

Anda dapat mengganti kebijakan baca dan memanggil batas waktu untuk setiap objek Query. Guna mengganti kebijakan baca untuk Query, panggil metode setHint() sebagai berikut:

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

Seperti di atas, kemungkinan nilainya adalah "EVENTUAL" dan "STRONG".

Untuk mengganti waktu tunggu baca, panggil setHint() sebagai berikut:

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

Tidak ada cara lain untuk mengganti konfigurasi opsi ini saat Anda mengambil entity berdasarkan kunci.

Meningkatkan Class Data

Implementasi DataNucleus JPA menggunakan langkah "peningkatan" pascakompilasi dalam proses build untuk mengaitkan class data dengan implementasi JPA.

Anda dapat melakukan langkah peningkatan pada class yang dikompilasi dari command line dengan perintah berikut:

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

Classpath harus berisi JAR datanucleus-core-*.jar, datanucleus-jpa-*, datanucleus-enhancer-*.jar, asm-*.jar, dan geronimo-jpa-*.jar (dengan * adalah nomor versi yang sesuai untuk setiap JAR) dari direktori appengine-java-sdk/lib/tools/, serta semua class data Anda.

Untuk mengetahui informasi selengkapnya tentang DataNucleus bytecode enhancer, lihat dokumentasi DataNucleus.

Mendapatkan Instance EntityManager

Aplikasi berinteraksi dengan JPA menggunakan instance class EntityManager. Anda mendapatkan instance ini dengan membuat instance dan memanggil metode pada instance class EntityManagerFactory. Factory menggunakan konfigurasi JPA (yang diidentifikasi dengan nama "transactions-optional") untuk membuat instance EntityManager.

Karena instance EntityManagerFactory memerlukan waktu untuk diinisialisasi, sebaiknya gunakan kembali satu instance sebanyak mungkin. Cara mudah untuk melakukannya adalah dengan membuat class wrapper singleton dengan instance statis, seperti berikut:

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;
    }
}

Tips: "transactions-optional" merujuk pada nama konfigurasi yang ditetapkan dalam file persistence.xml. Jika aplikasi Anda menggunakan beberapa set konfigurasi, Anda harus memperluas kode ini untuk memanggil Persistence.createEntityManagerFactory() seperti yang diinginkan. Kode Anda harus menyimpan instance singleton setiap EntityManagerFactory dalam cache.

Aplikasi menggunakan instance factory untuk membuat satu instance EntityManager untuk setiap permintaan yang mengakses datastore.

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

import EMF;

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

Anda menggunakan EntityManager untuk menyimpan, memperbarui, dan menghapus objek data, serta menjalankan kueri datastore.

Setelah selesai dengan instance EntityManager, Anda harus memanggil metode close()-nya. Menggunakan instance EntityManager setelah memanggil metode close() merupakan error.

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

Anotasi Class dan Kolom

Setiap objek yang disimpan oleh JPA akan menjadi entity di datastore App Engine. Jenis entity berasal dari nama sederhana class (tanpa nama paket). Setiap kolom persisten dari class ini mewakili properti entity, menggunakan nama properti yang sama dengan nama kolom (kapitalisasinya tetap).

Untuk mendeklarasikan class Java sebagai dapat disimpan dan diambil dari datastore dengan JPA, berikan anotasi @Entity pada class tersebut. Misalnya:

import javax.persistence.Entity;

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

Kolom class data yang akan disimpan di datastore harus berjenis yang dipertahankan secara default atau dideklarasikan secara eksplisit sebagai persisten. Anda dapat menemukan diagram yang menjelaskan perilaku persistensi default JPA di situs DataNucleus. Untuk mendeklarasikan kolom sebagai persisten secara eksplisit, Anda memberinya anotasi @Basic:

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

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

// ...
    @Basic
    private ShortBlob data;

Jenis kolom dapat berupa salah satu dari berikut:

  • salah satu jenis inti yang didukung oleh datastore
  • Koleksi (seperti java.util.List<...>) nilai jenis datastore inti
  • instance atau Koleksi instance dari class @Entity
  • class yang disematkan, disimpan sebagai properti pada entity

Class data harus memiliki konstruktor default publik atau yang dilindungi, dan satu kolom yang dikhususkan untuk menyimpan kunci utama entity datastore yang sesuai. Anda dapat memilih antara empat jenis kolom kunci yang berbeda, masing-masing menggunakan jenis nilai dan anotasi yang berbeda. (Lihat Membuat Data: Kunci untuk informasi selengkapnya.) Kolom kunci yang paling sederhana adalah nilai bilangan bulat panjang yang otomatis diisi oleh JPA dengan nilai unik di semua instance class lainnya saat objek disimpan ke datastore untuk pertama kalinya. Kunci bilangan bulat panjang menggunakan anotasi @Id, dan anotasi @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;

Berikut adalah contoh class data:

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;
    }
}

Pewarisan

JPA mendukung pembuatan class data yang menggunakan pewarisan. Sebelum membahas cara kerja pewarisan JPA di App Engine, sebaiknya baca dokumentasi DataNucleus tentang subjek ini, lalu kembali lagi. Selesai? Oke. Pewarisan JPA di App Engine berfungsi seperti yang dijelaskan dalam dokumentasi DataNucleus dengan beberapa batasan tambahan. Kita akan membahas batasan ini dan memberikan beberapa contoh konkret.

Strategi pewarisan "JOINED" memungkinkan Anda membagi data untuk satu objek data di beberapa "tabel", tetapi karena App Engine datastore tidak mendukung penggabungan, operasi pada objek data dengan strategi pewarisan ini memerlukan remote procedure call untuk setiap tingkat pewarisan. Hal ini berpotensi sangat tidak efisien, sehingga strategi pewarisan "JOINED" tidak didukung pada class data.

Kedua, strategi pewarisan "SINGLE_TABLE" memungkinkan Anda menyimpan data untuk objek data dalam satu "tabel" yang terkait dengan class persisten di root hierarki pewarisan Anda. Meskipun tidak ditemukan inefisiensi dalam strategi ini, strategi tersebut saat ini tidak didukung. Kami dapat memeriksanya kembali dalam rilis mendatang.

Kabar baiknya: Strategi "TABLE_PER_CLASS" dan "MAPPED_SUPERCLASS" berfungsi seperti yang dijelaskan dalam dokumentasi DataNucleus. Perhatikan contohnya:

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;
}

Dalam contoh ini, kami telah menambahkan anotasi @MappedSuperclass ke deklarasi class Worker. Kode ini memberi tahu JPA untuk menyimpan semua kolom persisten Worker dalam entity datastore subclass-nya. Entity datastore yang dibuat sebagai hasil pemanggilan persist() dengan instance Employee akan memiliki dua properti bernama "department" dan "salary". Entity datastore yang dibuat sebagai hasil pemanggilan persist() dengan instance Intern akan memiliki dua properti bernama "department" dan "inernshipEndDate". Tidak akan ada entity jenis "Worker" di datastore.

Sekarang mari kita buat sedikit lebih menarik. Misalkan, selain memiliki Employee dan Intern, kita juga menginginkan spesialisasi Employee yang mendeskripsikan karyawan yang telah keluar dari perusahaan:

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;
}

Dalam contoh ini, kami telah menambahkan anotasi @Inheritance ke deklarasi class FormerEmployee dengan atribut strategy yang ditetapkan ke InheritanceType.TABLE_PER_CLASS. Kode ini memberi tahu JPA untuk menyimpan semua kolom persisten FormerEmployee dan superclass-nya di entity datastore yang terkait dengan instance FormerEmployee. Entity datastore yang dibuat sebagai hasil pemanggilan persist() dengan instance FormerEmployee akan memiliki tiga properti yang bernama "department", "salary", dan "lastDay". Tidak akan pernah ada entity jenis "Employee" yang sesuai dengan FormerEmployee, tetapi jika Anda memanggil persist() dengan objek yang jenis runtime-nya adalah Employee, Anda akan menciptakan entitas jenis "Employee.

Mengombinasikan hubungan dengan pewarisan dapat dilakukan asalkan jenis kolom hubungan yang dideklarasikan cocok dengan jenis runtime objek yang Anda tetapkan ke kolom tersebut. Lihat bagian tentang Hubungan Polimorf untuk informasi selengkapnya. Bagian ini berisi contoh JDO, tetapi konsep dan batasannya sama untuk JPA.

Fitur JPA 2.0 yang Tidak Didukung

Fitur antarmuka JPA berikut tidak didukung oleh implementasi App Engine:

  • Memiliki hubungan many-to-many.
  • Kueri "Gabung". Anda tidak dapat menggunakan kolom entity turunan di filter saat menjalankan kueri pada jenis induk. Perhatikan, Anda dapat menguji kolom hubungan induk secara langsung dalam kueri menggunakan kunci.
  • Kueri agregasi (dikelompokkan dengan memiliki, sum, avg, max, min)
  • Kueri polimorf. Anda tidak dapat menjalankan kueri class untuk mendapatkan instance subclass. Setiap class diwakili oleh jenis entity terpisah di datastore.