Mis favoritos | Español | Acceder

Creación, obtención y eliminación de datos

Para almacenar el objeto de datos JDO en el almacén de datos, sólo hay que ejecutar el método makePersistent() de la instancia PersistenceManager. La implementación de JDO de App Engine utiliza el campo de clave principal del objeto para realizar el seguimiento de la entidad del almacén de datos que se corresponde con el objeto de datos y puede generar claves de forma automática para nuevos objetos. Puedes utilizar claves para recuperar entidades de forma rápida y construir claves de valores conocidos (por ejemplo, las ID de cuentas).

Persistencia de los objetos

Para almacenar un objeto de datos sencillo en el almacén de datos, ejecuta el método makePersistent() del PersistenceManager y transfiérelo a la instancia.

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

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

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

La llamada a makePersistent() es síncrona y no regresa hasta que el objeto se guarda y los índices se actualizan.

Para guardar varios objetos en JDO, ejecuta el método makePersistentAll(...) con una colección de objetos. En la versión actual, esto se implementa de forma similar a una serie de llamadas a makePersistent(). En una versión posterior, este método ejecutará llamadas por lotes al almacén de datos de forma más eficaz.

Nota: si alguno de los campos persistentes del objeto de datos es una referencia a otros objetos de datos persistentes y si alguno de esos objetos nunca se ha guardado o modificado desde que se cargó, los objetos de referencia también se guardarán en el almacén de datos. Consulta Relaciones.

Claves

Cada entidad contiene una clave exclusiva con respecto al resto de entidades de App Engine. Una clave completa incluye varios datos, tales como la ID de la aplicación, el tipo y la ID de la entidad. (Las claves también incluyen información sobre los grupos de entidades; para obtener más información, consulta Transacciones).

La clave de un objeto está almacenada en un campo de la instancia. Identifica el campo de clave principal mediante la anotación @PrimaryKey.

La aplicación puede proporcionar la parte de la ID de la clave como una cadena al crear el objeto o permitir que el almacén de datos genere una ID de forma automática. La clave completa debe ser exclusiva en todas las entidades del almacén de datos. En otras palabras, un objeto debe contener una ID exclusiva para todos los objetos del mismo tipo y con la misma entidad principal del grupo de entidades (si la hubiera). A través del tipo de campo y de anotaciones, puedes seleccionar el comportamiento de la clave deseado.

Si la clase se utiliza como una clase "secundaria" en una relación, el tipo de campo de clave debe ser capaz de representar una entidad principal del grupo de entidades, ya sea una instancia de Key o un valor de·Key codificados como una cadena. Consulta Transacciones para obtener más información sobre los grupos de entidades y Relaciones para obtener más información sobre las relaciones.

Sugerencia: si la aplicación crea un nuevo objeto y le asigna la misma ID de cadena que a otro objeto del mismo tipo (así como la misma entidad principal del grupo de entidades), al guardar el nuevo objeto, se sobrescribirá el otro objeto en el almacén de datos. Si quieres saber si ya existe una ID de cadena antes de crear un nuevo objeto, puedes utilizar una transacción para intentar obtener una entidad con una determinada ID y, a continuación, crearla si no existe. Consulta Transacciones.

Existen 4 tipos de campos de clave principal:

Long (Largo)

Un número entero largo (java.lang.Long), una ID de entidad generada por el almacén de datos de forma automática. Utilízalo para objetos sin elementos principales del grupo de entidades, cuyas ID deberían generarse de forma automática a través del almacén de datos. El campo de clave largo de una instancia se rellena al guardar la instancia.

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

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
Cadena no codificada

Una cadena (java.lang.String), una ID de entidad ("nombre de clave") proporcionada por la aplicación al crear el objeto. Utilízala para objetos sin elementos principales del grupo de entidades, cuyas ID debería proporcionarlas la aplicación. Antes de guardar, la aplicación establece este campo en la ID deseada.

import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    private String name;
Key (Clave)

Una instancia de Key (com.google.appengine.api.datastore.Key). El valor de clave incluye la clave de la entidad principal del grupo de entidades (si la hubiera), así como la ID de cadena asignada por la aplicación o la ID numérica generada por el sistema. Para crear el objeto con la ID de cadena asignada por la aplicación, crea el valor de Key con la ID y establece el campo en el valor. Para crear el objeto con una ID numérica asignada por el sistema, deja el campo de clave vacío. (Para obtener más información sobre cómo utilizar los elementos principales del grupo de entidades, consulta Transacciones).

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

La aplicación puede crear una instancia de Key con la clase 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);
Key como una cadena codificada

Similar a Key, aunque el valor es la forma de cadena codificada de la clave. Las claves de cadena codificada te permiten crear tu aplicación de forma portátil y beneficiarte de los grupos de entidades del almacén de datos de App Engine.

import javax.jdo.annotations.Extension;
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)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String encodedKey;

Antes de guardar, la aplicación puede rellenar este valor mediante una clave con un nombre o puede dejarlo vacío. Si el campo de clave codificado está vacío, se rellena con una clave generada por el sistema al guardar el objeto.

Las instancias de Key se pueden convertir en y desde la representación de cadena codificada a través de los métodos KeyFactory keyToString() y stringToKey().

Al utilizar cadenas de clave codificadas, puedes autorizar el acceso a una ID numérica o cadena del objeto con un campo adicional:

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

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

    // OR:

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

Un campo "gae.pk-name" puede establecerse en un nombre de clave antes de guardar el objeto. Al guardar el objeto, el campo de clave codificado se rellena con la clave completa que incluye el nombre de clave. El tipo debe ser String.

Un campo "gae.pk-id" se rellena al guardar el objeto y no se puede modificar. El tipo debe ser Long.

Al crear un nuevo objeto con una clave generada (un campo de clave que utiliza valueStrategy = IdGeneratorStrategy.IDENTITY), el valor de clave empieza en null. El campo de clave se rellena al crear el objeto en el almacén de datos. Si utilizas una transacción, el objeto se crea al confirmarla. De lo contrario, el objeto se crea al ejecutar el método makePersistent() si se está generando el objeto o al ejecutar el método de la instancia PersistenceManager close() si el objeto se está actualizando.

Creación y uso de las claves

Si la aplicación está al tanto de todos los elementos de la clave completa de una entidad, puede crear el objeto correspondiente Key sin el objeto.

Para la clave de una entidad sin una entidad principal del grupo de entidades, puedes utilizar el método estático createKey() de la clase KeyFactory. Este método requiere un tipo (el nombre sencillo de una clase), así como una ID de cadena asignada por la aplicación o una ID numérica asignada por el sistema, y devuelve un objeto Key. Por ejemplo, para volver a crear la clave de una entidad de tipo "Employee" sin nombre de clave "Alfred.Smith@example.com" (y sin una entidad principal del grupo de entidades):

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

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

Para volver a crear una clave de una entidad de tipo "Employee" con una ID numérica asignada por el sistema de 52234 (y sin una entidad principal del grupo de entidades):

        Key k = KeyFactory.createKey(Employee.class.getSimpleName(), 52234);

Las claves se pueden convertir en y desde una representación de cadena a través de los métodos keyToString() y stringToKey() de la clase KeyFactory respectivamente. (Ten en cuenta que este método es diferente del método toString() de la clase Key, que devuelve un valor interpretable por humanos y apropiado para la depuración).

Para la clave de una entidad con una entidad principal del grupo de entidades, puedes utilizar la clase KeyFactory.Builder:

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

// ...
        Key k = new KeyFactory.Builder(Employee.class.getSimpleName(), 52234).addChild(ExpenseReport.class.getSimpleName(), "A23Z79").getKey();

El método de la instancia Builder addChild() devuelve el compilador para que puedas encadenar llamadas y añadir cada elemento de la ruta de clave. Para obtener el valor completo de Key para un determinado compilador, ejecuta el método getKey() del compilador.

Para obtener más información sobre grupos de entidades, consulta Transacciones.

Obtención de un objeto por la clave

Para recuperar un objeto según su clave, utiliza el método getObjectById() de PersistenceManager. El método requiere la clase del objeto y de la clave:

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

Si la clase utiliza un campo de clave que consiste en una ID de cadena no codificada (String) o en una ID numérica (Long), getObjectByID() puede requerir el valor sencillo con un parámetro de clave:

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

El argumento de clave puede ser de cualquiera de los tipos de campos de clave compatibles (ID de cadena, ID numérica, valor de Key, cadena de clave codificada) y puede ser diferente del campo de clave de la clase. App Engine debe ser capaz de derivar la clave completa del nombre de clase y del valor proporcionado. Las ID de cadenas y las ID numéricas son exclusivas, de modo que una llamada que utilice una ID numérica nunca devolverá una entidad que contenga una ID de cadena. Si se utiliza un valor de Key o una cadena de clave codificada, la clave debe hacer referencia a una entidad, cuyo tipo esté representado por la clase.

Actualización de un objeto

Una forma de actualizar un objeto que contenga JDO es extraer el objeto y, a continuación, modificarlo mientras que el parámetro PersistenceManager que devuelve el objeto siga abierto. Los cambios se conservan al cerrar PersistenceManager. Por ejemplo:

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

Puesto que PersistenceManager devolvió la instancia Employee, está al tanto de cualquier modificación aplicada a los campos Persistent en Employee, de modo que actualiza de forma automática el almacén de datos con estas modificaciones al cerrar el PersistenceManager. Está al tanto de esto porque la instancia Employee está "vinculada" a PersistenceManager.

Puedes modificar un objeto después de cerrar PersistenceManager declarando la clase como "desvinculable". Para hacer esto, añade el atributo detachable a la anotación @PersistenceCapable:

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Employee {
    // ...
}

Ahora podrás leer y rellenar los campos de un objeto Employee después de cerrar el parámetro PersistenceManager que lo cargó. El siguiente ejemplo muestra cómo un objeto desvinculado puede ser útil:

public Employee getEmployee(User user) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    pm.setDetachAllOnCommit(true);
    try {
        e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");
    } finally {
        pm.close();
    }
    return e;
}

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

Los objetos desvinculados son una buena alternativa a la creación de objetos de transferencia de datos. Para obtener más información sobre cómo utilizar objetos desvinculados, consulta la documentación de DataNucleus.

Eliminación de un objeto

Para eliminar un objeto del almacén de datos, ejecuta el método deletePersistent() de PersistenceManager que contenga el objeto:

        pm.deletePersistent(e);

Si un objeto tiene campos que contienen objetos secundarios que son persistentes, también se eliminarán los objetos secundarios. Para obtener más información, consulta Relaciones.