Creazione, recupero ed eliminazione dei dati in JDO

Per salvare un oggetto dati JDO nel datastore, è sufficiente chiamare il metodo makePersistent() dell'istanza PersistenceManager. L'implementazione JDO di App Engine utilizza il campo della chiave primaria dell'oggetto per tenere traccia dell'entità Datastore corrispondente all'oggetto dati e può generare automaticamente le chiavi per i nuovi oggetti. Puoi utilizzare le chiavi per recuperare rapidamente le entità e puoi crearle a partire da valori noti (ad esempio gli ID account).

Rendere gli oggetti permanenti

Per archiviare un semplice oggetto dati nel datastore, chiami il metodo makePersistent() di PersistenceManager, passandogli l'istanza.

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

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

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

La chiamata a makePersistent() è sincrona e non restituisce un valore finché l'oggetto non viene salvato e gli indici non vengono aggiornati.

Per salvare più oggetti in JDO, chiama il metodo makePersistentAll(...) con una raccolta di oggetti. Questo metodo utilizzerà una singola operazione di salvataggio batch a basso livello, più efficiente di una serie di singole invocazioni di makePersistent(...).

Nota:se uno dei campi permanenti dell'oggetto dati è un riferimento ad altri oggetti dati permanenti e nessuno di questi oggetti non è mai stato salvato o è cambiato dal caricamento, anche gli oggetti a cui si fa riferimento vengono salvati nel data store. Vedi Relazioni.

Chiavi

Ogni entità ha una chiave univoca per tutte le entità in App Engine. Una chiave completa include diverse informazioni, tra cui l'ID applicazione, il tipo e un ID entità. Le chiavi contengono anche informazioni sui gruppi di entità. Per ulteriori informazioni, consulta Transazioni.

La chiave di un oggetto viene archiviata in un campo dell'istanza. Il campo della chiave primaria viene identificato utilizzando l'annotazione @PrimaryKey.

L'app può fornire la parte di ID della chiave come stringa quando viene creato l'oggetto oppure può consentire al datastore di generare automaticamente un ID numerico. La chiave completa deve essere univoca in tutte le entità del data store. In altre parole, un oggetto deve avere un ID univoco per tutti gli oggetti dello stesso tipo e con lo stesso gruppo di entità padre (se presente). Seleziona il comportamento desiderato della chiave utilizzando il tipo di campo e le annotazioni.

Se la classe viene utilizzata come classe "secondaria" in una relazione, il campo chiave deve essere di un tipo in grado di rappresentare un gruppo di entità principale: un'istanza Key o un valore Key codificato come stringa. Per saperne di più sui gruppi di entità, consulta la sezione Transazioni e per saperne di più sulle relazioni, consulta la sezione Relazioni.

Suggerimento:se l'app crea un nuovo oggetto e gli assegna lo stesso ID stringa di un altro oggetto dello stesso tipo (e dello stesso gruppo di entità principale), il salvataggio del nuovo oggetto sovrascrive l'altro oggetto nel datastore. Per rilevare se un ID stringa è già in uso prima di creare un nuovo oggetto, puoi utilizzare una transazione per tentare di ottenere un'entità con un determinato ID, quindi crearne una se non esiste. Vedi Transazioni.

Esistono quattro tipi di campi della chiave primaria:

Lungo

Un numero intero lungo (java.lang.Long), un ID entità generato automaticamente dal datastore. Utilizzalo per gli oggetti senza gruppi di entità principali i cui ID devono essere generati automaticamente dal datastore. Il campo della chiave lunga di un'istanza viene compilato quando l'istanza viene salvata.

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

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
Stringa non codificata

Una stringa (java.lang.String), un ID entità ("nome chiave") fornito dall'applicazione al momento della creazione dell'oggetto. Utilizzalo per gli oggetti senza gruppi di entità principali i cui ID devono essere forniti dall'applicazione. L'applicazione imposta questo campo sull'ID desiderato prima del salvataggio.

import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    private String name;
Chiave

Un'istanza Key (com.google.appengine.api.datastore.Key). Il valore della chiave include la chiave del gruppo di entità principale (se presente) e l'ID stringa assegnato dall'app o l'ID numerico generato dal sistema. Per creare l'oggetto con un ID stringa assegnato dall'app, crea il valore della chiave con l'ID e imposta il campo sul valore. Per creare l'oggetto con un ID numerico assegnato dal sistema, lascia il campo della chiave null. Per informazioni su come utilizzare i gruppi di entità principali, vedi Transazioni.

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'app può creare un'istanza Key utilizzando 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);
Chiave come stringa codificata

Simile a Chiave, ma il valore è la forma di stringa codificata della chiave. Le chiavi di stringa codificate ti consentono di scrivere l'applicazione in modo portabile e di sfruttare comunque i gruppi di entità del datastore di 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'app può compilare questo valore prima del salvataggio utilizzando una chiave con un nome oppure può lasciarlo null. Se il campo della chiave codificata è nullo, il campo viene compilato con una chiave generata dal sistema quando l'oggetto viene salvato.

Le istanze di chiavi possono essere convertite nella rappresentazione di stringa codificata e viceversa utilizzando i metodi KeyFactory keyToString() e stringToKey().

Quando utilizzi stringhe chiave codificate, puoi fornire l'accesso all'ID numerico o di stringa di un oggetto con un campo aggiuntivo:

    @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 campo "gae.pk-name" può essere impostato su un nome chiave prima di salvare l'oggetto. Quando l'oggetto viene salvato, il campo della chiave codificata viene compilato con la chiave completa che include il nome della chiave. Il tipo deve essere String.

Un campo "gae.pk-id" viene compilato quando l'oggetto viene salvato e non può essere modificato. Il tipo deve essere Long.

Quando viene creato un nuovo oggetto con una chiave generata (un campo della chiave che utilizza valueStrategy = IdGeneratorStrategy.IDENTITY), il valore della chiave inizia con null. Il campo della chiave viene compilato quando l'oggetto viene scritto nel data store. Se utilizzi una transazione, l'oggetto viene scritto al momento del commit della transazione. In caso contrario, l'oggetto viene scritto quando viene chiamato il metodo makePersistent() se l'oggetto viene creato o quando viene chiamato il metodo close() dell'istanza PersistenceManager se l'oggetto viene aggiornato.

Per ulteriori informazioni sulla creazione delle chiavi, consulta Entità, proprietà e chiavi.

Ottenere un oggetto tramite chiave

Per recuperare un oggetto in base alla relativa chiave, utilizza il metodo getObjectById() di PersistenceManager. Il metodo prende la classe dell'oggetto e la chiave:

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

Se la classe utilizza un campo chiave che è un ID stringa non codificato (String) o un ID numerico (Long), getObjectByID() può assumere il valore semplice come parametro chiave:

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

L'argomento chiave può essere di uno qualsiasi dei tipi di campi chiave supportati (ID stringa, ID numerico, Valore chiave, Stringa chiave codificata) e può essere di tipo diverso rispetto al campo chiave della classe. App Engine deve essere in grado di dedurre la chiave completa dal nome della classe e dal valore fornito. Gli ID stringa e numerici sono esclusivi, pertanto una chiamata che utilizza un ID numerico non restituisce mai un'entità con un ID stringa. Se viene utilizzato un valore chiave o una stringa di chiavi codificata, la chiave deve fare riferimento a un'entità il cui tipo è rappresentato dalla classe.

Aggiornamento di un oggetto

Un modo per aggiornare un oggetto con JDO è recuperarlo e modificarlo mentre PersistenceManager che ha restituito l'oggetto è ancora aperto. Le modifiche vengono mantenute quando PersistenceManager viene chiuso. Ad esempio:

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

Poiché l'istanza Employee è stata restituita da PersistenceManager, PersistenceManager è a conoscenza di eventuali modifiche apportate ai campi permanenti su Employee e aggiorna automaticamente il datastore con queste modifiche quando PersistenceManager viene chiuso. Lo sa perché l'istanza Employee è "collegata" a PersistenceManager.

Puoi modificare un oggetto dopo la chiusura di PersistenceManager dichiarando la classe come "scollegata". A tal fine, aggiungi l'attributo detachable all'annotazione @PersistenceCapable:

import javax.jdo.annotations.PersistenceCapable;

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

Ora puoi leggere e scrivere i campi di un oggetto Employee dopo la chiusura del PersistenceManager che lo ha caricato. L'esempio seguente illustra come può essere utile un oggetto scollegato:

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

Gli oggetti scollegati sono un'ottima alternativa alla creazione di oggetti di trasferimento dati. Per saperne di più sull'utilizzo di oggetti scollegati, consulta la documentazione di DataNucleus.

Eliminazione di un oggetto

Per eliminare un oggetto dal datastore, chiama il metodo deletePersistent() di PersistenceManager con l'oggetto:

pm.deletePersistent(e);

Per eliminare più oggetti in JDO, chiama il metodo deletePersistentAll(...) con una raccolta di oggetti. Questo metodo utilizzerà una singola operazione di eliminazione collettiva a basso livello, più efficiente di una serie di singole invocazioni di deletePersistent(...).

Se un oggetto contiene campi che contengono oggetti secondari che sono anche permanenti, vengono eliminati anche gli oggetti secondari. Per saperne di più, consulta la sezione Relazioni.

Per eliminare tutti gli oggetti corrispondenti a una query, puoi utilizzare la funzionalità "Elimina per query" di JDOQL. Per ulteriori informazioni, consulta la sezione Eliminare entità per query.