Para guardar un objeto de datos JDO en el almacén de datos, solo tienes que llamar al método makePersistent()
de la instancia PersistenceManager. La implementación de JDO en App Engine utiliza el campo de clave principal del objeto para realizar un seguimiento de qué entidad del almacén de datos corresponde al objeto de datos. Además, JDO puede generar claves para objetos nuevos de forma automática. Puedes usar claves para recuperar entidades rápidamente y crear claves a partir de valores conocidos (como el identificador de una cuenta).
Cómo crear objetos persistentes
Para almacenar un objeto de datos simple en el almacén de datos, llama al método makePersistent()
de PersistenceManager y pásale 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 devuelve ningún valor hasta que se guarda el objeto y se actualizan los índices.
Para guardar varios objetos en JDO, llama al método makePersistentAll(...)
con una colección de objetos. Este método usará una sola operación de guardado por lotes de bajo nivel que es más eficiente que una serie de invocaciones makePersistent(...)
individuales.
Nota: Si alguno de los campos persistentes del objeto de datos hace referencia a otros objetos de datos persistentes y alguno de esos objetos nunca se ha guardado o ha cambiado desde que se cargó, los objetos a los que se hace referencia también se guardan en el almacén de datos. Consulta Relaciones.
Claves
Cada entidad cuenta con una clave que es única entre todas las entidades de App Engine. Una clave completa incluye varios datos, como el ID de aplicación, el tipo y un ID de entidad. Las claves también contienen información sobre los grupos de entidades. Consulta Transacciones para obtener más información.
La clave de un objeto se almacena en un campo de la instancia. Para identificar el campo de clave principal, usa la anotación @PrimaryKey
.
La aplicación puede facilitar el fragmento de ID de la clave como cadena cuando se crea el objeto o permitir que el almacén de datos genere un ID numérico de forma automática. La clave completa debe ser única entre todas las entidades del almacén de datos. Es decir, un objeto debe tener un ID que sea único entre todos los objetos de un mismo tipo y con el mismo grupo de entidades principal (si procede). Puedes decidir el comportamiento de la clave mediante el tipo de campo y las anotaciones.
Si la clase se usa como clase "secundaria" en una relación, el campo de clave debe ser de un tipo capaz de representar un elemento superior de un grupo de entidades: una instancia de Key o un valor de Key codificado 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.
Nota: Si la aplicación crea un objeto nuevo y le asigna el mismo ID de cadena que a otro objeto del mismo tipo (y el mismo elemento superior del grupo de entidades), al guardar el objeto nuevo se sobrescribirá el otro objeto en el almacén de datos. Para detectar si un ID de cadena ya está en uso antes de crear un objeto, puedes usar una transacción para intentar obtener una entidad con un ID determinado y, a continuación, crear una si no existe. Consulta Transacciones.
Existen cuatro tipos de campos de clave principal:
- Long
-
Un número entero largo (
java.lang.Long
), un ID de entidad generado automáticamente por el almacén de datos. Úsalo para objetos sin grupos de entidades principales cuyos ID deba generarlos automáticamente el almacén de datos. El campo de clave largo de una instancia se rellena al guardar dicha instancia.import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; // ... @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id;
- String (cadena sin codificar)
-
Una cadena (
java.lang.String
), un ID de entidad ("nombre de clave") proporcionado por la aplicación cuando se crea el objeto. Úsalo para objetos sin grupos de entidades principales cuyos ID deba facilitarlos la aplicación. La aplicación asigna el ID deseado a este campo antes del guardado.import javax.jdo.annotations.PrimaryKey; // ... @PrimaryKey private String name;
- Clave
-
Una instancia Key (
com.google.appengine.api.datastore.Key
). El valor de la clave incluye la clave del elemento superior del grupo de entidades (si lo hay) y el ID de cadena asignado por la aplicación o el ID numérico generado por el sistema. Para crear un objeto con un ID de cadena asignado por la aplicación, debes crear el valor de Key con dicho ID y asignar el valor al campo. Para crear el objeto con un ID numérico asignado por el sistema, debes dejar el campo de la clave como "null". Para obtener información sobre cómo usar los superiores de grupos 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 mediante 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 (cadena codificada)
-
Es similar a Key, con la excepción de que el valor es la clave en forma de cadena codificada. Las claves de cadena codificada permiten escribir tu aplicación de forma que pueda transferirse y seguir contando con las ventajas 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; // ... @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true") private String encodedKey;
La aplicación puede rellenar este valor antes del guardado mediante una clave con un nombre o puede dejarlo como "null". Si el campo de la clave codificada es "null", el sistema genera una clave para el campo al guardar el objeto.
Las instancias de clave se pueden convertir a la representación de cadena codificada y viceversa mediante los métodos
keyToString()
ystringToKey()
de KeyFactory.Cuando se usan cadenas de claves codificadas, se puede proporcionar acceso al ID de cadena o numérico de un objeto con un campo adicional:
@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"
se puede asignar a un nombre de clave antes de guardar el objeto. Cuando el objeto se haya guardado, el campo de la clave codificada se rellenará con la clave completa, que incluye el nombre de la clave. Su tipo debe serString
.Un campo
"gae.pk-id"
se rellena cuando se guarda el objeto y no se puede modificar. Debe ser del tipo Long.
Cuando se crea un objeto con una clave generada (un campo de clave que usa valueStrategy = IdGeneratorStrategy.IDENTITY
), su valor de clave empieza por null
. El campo de la clave se rellena cuando el objeto se escribe en el almacén de datos. Si usas una transacción, el objeto se escribe cuando esta se produce. De lo contrario, el objeto se escribe cuando se llama al método makePersistent()
si se está creando el objeto, o cuando se llama al método close()
de la instancia de PersistenceManager si se está actualizando el objeto.
Para obtener más información sobre cómo crear claves, consulte Entidades, propiedades y claves.
Obtención de un objeto mediante una clave
Para obtener un objeto a partir de su clave, usa el método getObjectById()
de PersistenceManager. El método obtiene la clase del objeto y la clave:
Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com"); Employee e = pm.getObjectById(Employee.class, k);
Si la clase usa un campo de clave que es un ID de cadena sin codificar (String
) o un ID numérico (Long
), getObjectByID()
puede tomar el valor simple como parámetro de clave:
Employee e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");
El argumento de la clave puede ser de cualquiera de los tipos de campos de clave admitidos (ID de cadena, ID numérico, valor de clave, cadena de clave codificada) y de un tipo distinto al campo de clave de la clase. App Engine debe ser capaz de obtener la clave completa a partir del nombre de la clase y del valor proporcionado. Los ID numéricos y de cadena son exclusivos, por lo que una invocación que utilice un ID numérico nunca devuelve una entidad con un ID de cadena. Si se emplea un valor de Key o una cadena de clave codificada, la clave debe hacer referencia a una entidad cuyo tipo quede representado por la clase.
Actualización de un objeto
Un modo de actualizar un objeto con JDO es extraer el objeto y, a continuación, modificarlo mientras la interfaz PersistenceManager que ha devuelto el objeto sigue abierta. Los cambios persisten una vez que PersistenceManager se cierre. 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(); } }
Como PersistenceManager ha devuelto la instancia Employee
, conoce las modificaciones que se hagan en los campos persistentes de Employee
y actualiza automáticamente el almacén de datos con estas modificaciones cuando se cierra PersistenceManager. Lo sabe porque la instancia de Employee está "asociada" a PersistenceManager.
Puedes modificar un objeto después de que se haya cerrado PersistenceManager declarando la clase como "desacoplable". Para ello, añade el atributo detachable
a la anotación @PersistenceCapable
:
import javax.jdo.annotations.PersistenceCapable; @PersistenceCapable(detachable="true") public class Employee { // ... }
De este modo puedes leer y escribir en los campos de un objeto Employee después de que la interfaz PersistenceManager que lo ha cargado se cierre. En el siguiente ejemplo se muestra la utilidad de un objeto independiente:
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 todetachCopy
ordetachCopyAll
. 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); } }
Los objetos independientes son una buena alternativa a la creación de objetos de transferencia de datos. Para obtener más información sobre cómo trabajar con objetos independientes, consulta la documentación de DataNucleus.
Eliminación de un objeto
Para eliminar un objeto del almacén de datos, llama al método deletePersistent()
de PersistenceManager con el objeto:
pm.deletePersistent(e);
Para eliminar varios objetos en JDO, llama al método deletePersistentAll(...)
con una colección de objetos. Este método usará una sola operación de eliminación por lotes de bajo nivel, que es más eficiente que una serie de invocaciones deletePersistent(...)
individuales.
Si un objeto tiene campos que contengan objetos secundarios que también sean persistentes, también se eliminan los objetos secundarios. Consulta Relaciones para obtener más información.
Para eliminar todos los objetos que coincidan con una consulta, puedes usar la función "eliminar por consulta" de JDOQL. Consulta más información en el artículo Eliminar entidades mediante una consulta.