Como criar, conseguir e excluir dados no JDO

Para salvar um objeto de dados JDO no armazenamento de dados, basta chamar o método makePersistent() da instância PersistenceManager. A implementação JDO do App Engine utiliza o campo de chave principal do objeto para rastrear qual entidade do armazenamento de dados corresponde ao objeto de dados. Além disso, ela pode gerar chaves para novos objetos automaticamente. É possível usar essas chaves para recuperar entidades rapidamente e construir chaves a partir de valores conhecidos (como IDs de conta).

Como tornar objetos persistentes

Para salvar um objeto de dados simples no armazenamento de dados, chame o método makePersistent() do PersistenceManager, o encaminhando para a instância.

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

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

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

A chamada para makePersistent() é síncrona e não retorna até que o objeto seja salvo e os índices, atualizados.

Para salvar vários objetos no JDO, chame o método makePersistentAll(...) com uma coleção de objetos. Esse método usará uma única operação de gravação em lote de baixo nível que é mais eficiente do que uma série de invocações makePersistent(...) individuais.

Observação: se algum dos campos persistentes do objeto de dados for uma referência a outros objetos de dados persistentes e se qualquer um desses objetos nunca tiver sido salvo ou se tiver sido alterado desde o carregamento, os objetos referenciados também serão salvos no armazenamento de dados. Consulte Relacionamentos.

Chaves

Cada entidade tem uma chave exclusiva entre todas as entidades do App Engine. Uma chave completa inclui várias informações, incluindo o ID do aplicativo, o tipo e um código de entidade. As chaves também contêm informações sobre grupos de entidades. Consulte Transações para saber mais.

A chave de um objeto é armazenada em um campo da instância. Você identifica o campo da chave primária usando a anotação @PrimaryKey.

O aplicativo pode fornecer a porção do código da chave como uma string quando o objeto for criado ou pode permitir que o armazenamento de dados gere um código numérico automaticamente. A chave completa precisa ser exclusiva entre todas as entidades do armazenamento de dados. Em outras palavras, um objeto precisa ter um código exclusivo entre todos os objetos do mesmo tipo e com o mesmo pai de grupo de entidades (se houver). Use o tipo do campo e anotações para selecionar o comportamento desejado para a chave.

Se a classe for usada como uma classe "filho" em um relacionamento, o campo de chave precisa ser de um tipo capaz de representar um pai de grupo de entidades: uma instância Key ou um valor Key codificado como uma string. Consulte Transações, para saber mais sobre grupos de entidades e Relacionamentos, para saber mais sobre relacionamentos.

Dica: se o aplicativo criar um novo objeto e der a ele o mesmo código de string de outro objeto do mesmo tipo (e mesmo pai de grupo de entidades), salvar o novo objeto substituirá o outro objeto no armazenamento de dados. Para detectar se um código de string já está em uso antes de criar um novo objeto, use uma transação para tentar receber uma entidade com o código e depois criar outra, caso esta não exista. Consulte Transações.

Há quatro tipos de campos de chave principais:

Longo

Um número inteiro longo (java.lang.Long), um código de entidade gerado automaticamente pelo armazenamento de dados. Use isso para objetos sem pais de grupos de entidades em que os códigos precisem ser gerados automaticamente pelo armazenamento de dados. O campo de chave longo de uma instância é preenchido quando a instância é salva.

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

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
String não codificada

Uma string (java.lang.String), um código de entidade ("nome da chave") fornecido pelo aplicativo quando o objeto é criado. Use isso para objetos sem pais de grupos de entidades com códigos que precisem ser fornecidos pelo aplicativo. O aplicativo define esse campo com o código desejado antes de salvar.

import javax.jdo.annotations.PrimaryKey;

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

Uma instância Key (com.google.appengine.api.datastore.Key). O valor da chave inclui a chave do pai do grupo de entidades (se houver) e o código de string atribuído pelo aplicativo ou o código numérico gerado pelo sistema. Para criar o objeto com um código de string atribuído pelo aplicativo, você precisa criar o valor Key com o código e definir o campo para ele. Para criar o objeto com um código numérico atribuído pelo sistema, o campo de chave precisa ser nulo. Para saber mais sobre como usar os pais do grupo de entidades, consulte Transações.

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

O aplicativo pode criar uma instância Key usando a 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);
Chave como string codificada

Semelhante à chave, mas o valor é a forma de string codificada da chave. Com as chaves de string codificada, é possível gravar seu aplicativo de maneira portável e aproveitar os grupos de entidade do armazenamento de dados do 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;

O aplicativo pode preencher esse valor antes de salvar usando uma chave com um nome ou pode deixá-lo nulo. Se o campo de chave codificada for nulo, ele será preenchido com uma chave gerada pelo sistema quando o objeto for salvo.

As instâncias Key podem ser convertidas para a representação de string codificada e vice-versa usando os métodos KeyFactory keyToString() e stringToKey().

Ao usar strings de chave codificada, é possível fornecer acesso ao código em string ou valor numérico de um objeto com um 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;

Um campo "gae.pk-name" pode ser configurado para um nome de chave antes de salvar o objeto. Quando o objeto é salvo, o campo de chave codificada é preenchido com a chave completa que inclui o nome de chave. Seu tipo precisa ser String.

Um campo "gae.pk-id" é preenchido quando o objeto é salvo e não pode ser modificado. Seu tipo precisa ser Longo.

Quando um novo objeto com uma chave gerada (um campo usando valueStrategy = IdGeneratorStrategy.IDENTITY) é criado, o valor de chave começa com null. O campo de chave é preenchido quando o objeto é gravado no armazenamento de dados. Se estiver usando uma transação, o objeto será gravado no momento em que a transação for executada. Caso contrário, o objeto é gravado quando o método makePersistent() é chamado se o objeto estiver sendo criado ou quando o método close() da instância do PersistenceManager for chamado se o objeto estiver sendo atualizado.

Para saber mais sobre como criar chaves, consulte Entidades, propriedades e chaves.

Como conseguir um objeto por meio da chave

Para recuperar um objeto específico com a chave, use o método getObjectById() do PersistenceManager. O método toma a classe do objeto e a chave:

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

Se a classe usar um campo de chave que é um código de string não codificado (String) ou um código numérico (Long), getObjectByID() pode assumir o valor simples como parâmetro da chave:

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

O argumento de chave pode ser de qualquer um dos tipos de campo de chave compatíveis (código de string, código numérico, valor Key, string de chave codificada) e pode ser de um tipo diferente do campo de chave da classe. O App Engine precisa ser capaz de derivar a chave completa a partir do nome de classe e do valor fornecido. Os códigos de string e numéricos são exclusivos. Por isso, uma chamada usando um código numérico nunca retorna uma entidade com um código de string. Se for usado um valor Key ou uma string de chave codificada, a chave precisará se referir a uma entidade em que o tipo seja representado pela classe.

Como atualizar um objeto

Uma maneira de atualizar um objeto com JDO é buscar o objeto e depois modificá-lo enquanto o PersistenceManager que retornou o objeto ainda está aberto. As alterações são mantidas quando o PersistenceManager é fechado. Por exemplo:

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

Quando a instância Employee é retornada pelo PersistenceManager, ele sabe as modificações feitas nos campos persistentes em Employee e atualiza automaticamente o armazenamento de dados com essas modificações antes de fechar. Isso ocorre porque a instância "Employee" está "vinculada" ao PersistenceManager.

É possível modificar um objeto depois que o PersistenceManager é fechado ao declarar a classe como "removível". Para isso, adicione o atributo detachable à anotação @PersistenceCapable:

import javax.jdo.annotations.PersistenceCapable;

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

Agora, é possível ler e gravar os campos de um objeto "Employee" depois que o PersistenceManager que o carregou é fechado. O exemplo a seguir ilustra como um objeto desanexado pode ser útil:

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

Objetos desanexados são uma boa alternativa para a criação de objetos de transferência de dados. Para saber mais sobre como trabalhar com objetos desanexados, consulte a Documentação do DataNucleus.

Como excluir um objeto

Para excluir um objeto do armazenamento de dados, chame o método deletePersistent() do PersistenceManager com o objeto:

pm.deletePersistent(e);

Para excluir vários objetos no JDO, chame o método deletePersistentAll(...) com uma coleção de objetos. Esse método usará uma única operação de exclusão de lote de baixo nível que seja mais eficiente do que uma série de deletePersistent(...) individuais.

Se um objeto tiver campos contendo objetos filhos que também são persistentes, os objetos filhos também serão excluídos. Consulte Relacionamentos para saber mais.

Para excluir todos os objetos que correspondem a uma consulta, você pode usar o recurso "excluir por consulta" do JDOQL. Consulte Como excluir entidades por consulta para saber mais.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Java 8