terça-feira, 25 de março de 2008

Classes de chave primária e chaves composta

A especificação Java Persistence fornece múltiplas maneiras de permitir que uma chave primária seja composta de varias propriedades persistente. Uma delas é por meio da anotação @javax.persistence.IdClass, a outra é por meio da @javax.persistence.EmbeddedId.

 

*@IdClass

A primeira maneira de definir uma classe de chave primária (e, nesse sentido, chaves compostas) é utilizar a anotação @IdClass.  É uma anotação no nível de classe e especifica qual classe de chave primária você deve utilizar ao interagir com o gerenciador de entidade. Na classe bean, designamos uma ou mais propriedades que compõem a chave primária, utilizando a anotação @Id. Essas propriedades devem mapear exatamente para propriedades na @IdClass.


*@EmbeddedId

Outra maneira de definir as classes de chave primária e as chaves compostas é embutir a classe da chave primária diretamente em sua classe bean. A anotação @javax.persistence.EmbeddedId é utilizada para esse propósito em conjunto com a anotação @javax.persistence.Embeddable.

Há duas maneiras de mapear as propriedades da classe de chave primária para colunas em uma tabela. Uma é especificar os mapeamentos @Column dentro do código-fonte da classe de chave primária; a outra é utilizar @AttributeOverrides.

Chaves primárias

Uma chave primária é a identidade de um determinado bean de entidade. Cada bean de entidade dete ter uma chave primária. A chave primária pode mapear para uma ou mais propriedades e deve mapear para um dos tipos a seguir: qualquer tipo Java primitivo (incluindo empacotadores), java.lang.String ou uma classe de chave primária composta de primitivos e/ou strings.

*@Id

A anotação @javax.persistence.Id identifica uma ou mais propriedades que compõem a chave primária para a tabela.

Podemos gerar a chave primária para os beans de entidade manualmente ou fazer com que o provedor de persistência gere essa chave. Para serem geradas pelo provedor, temos que utilizar a anotação @javax.persistence.GeneratedValue:

Os provedores de persistência precisam fornecer a geração de chave  para a chave primária primitiva. Podemos definir o tipo de gerador primário utilizando o atributo stategy(). A estratégia GeneratorType.AUTO é a configuração mais comumente utilizada.

terça-feira, 11 de março de 2008

Interagindo com um EntityManager

A API Entity Manager tem métodos para inserir e remover entidades de um banco de dados e também mesclar atualizações das instâncias de entidade desacopladas. Há também uma rica API de consulta que pode ser acessada para criar objetos de consulta a partir de certos métodos EntityManager.


*Persistindo entidades
Persistir uma entidade é o ato de inseri-la dentro de um banco de dados. Podemos persistir entidades que ainda não foram criadas no banco de dados. Para criar uma entidade, você primeiro aloca uma instância dela, configura suas propriedades e ativa quaisquer relacionamentos que ela possa ter com outros objetos. Em outras palavras, você inicializa um bean de entidade assim como faria com qualquer outro objeto Java. Depois de fazer isso, você interage com o serviço do gerenciador de entidades chamando o método EntityManager.persist().


Quando esse método é chamado, o gerenciador da entidade enfileira o Address para inserção no banco de dados e a instâncias do objeto torna-se gerenciada. O momento em que a inserção real acontece depende de algumas variáveis. Se persist() for chamado dentro de uma transação, a inserção poderia acontecer imediatamente ou ser enfileirada até o fim da transação, dependendo do modo flush (de gravação). Você sempre pode forçar a inserção manualmente dentro de uma transação chamando o método flush(). Você pode chamar persist() fora de uma transação se e somente se o gerenciador de entidades for um contexto de persistência EXTENDED. Ao chamar persist() fora de uma transação com um contexto de persistência EXTENDED, a inserção é enfileirada até o contexto de persistência ser associado com uma transação. Um contexto de persistência estendido injetado é automaticamente associado a uma transação JTA pelo contêiner EJB. Para outros contextos estendidos criados manualmente com a API EntityManagerFactor, você precisa chamar Entity.Manager.joinTransaction() para realizar a associação da transação.
O método persist() lança uma IllegalArgumentException se seu parâmetro não for um tipo de entidade. TransactionRequiredException é lançada se esse método for invocado em um contexto de persistência com escopo de transação. Entretanto, se o gerenciador de entidades for um contexto de persistência estendido, é valido chamar persist() fora do escopo de uma transação; a inserção é enfileirada até o contexto de persistência interagir com uma transação.

*Localização entidades
O gerenciador de entidades fornece dois mecanismos para localizar objetos no seu banco de dados. Uma maneira é usar os métodos simples do gerenciador de entidades que localiza uma entidade de acordo com sua chave primaria. A outra é criando e executando consultas.
O EntityManager tem dois métodos diferentes que permitem localizar uma entidade de acordo com sua chave primaria.
Os dois métodos aceitam a classe da entidade como um parâmetro e também como uma instância da chave primária da entidade. Eles usam Java genérico de modo que você não precise aplicar nenhuma coerção. Como esses métodos diferem? O método find() retorna null se a entidade não for encontrada no banco de dados. Ele também inicializa o estado com base nas diretivas de carregamento sob demanda (lazy-loading) de cada propriedade.
Neste exemplo, estamos localizando um Address com um ID de chave primária 2. Como isso compila se o método find() espera um Object com seu segundo tipo de parâmetro? Bom, o Java 5 tem um recurso chamando autoboxing que converte tipos primitivos diretamente em seus tipos Object. Assim, a constante 2 é convertida em uma java.lang.Integer.
O getReference() difere de find() pelo fato de que, se a entidade não for encontrada no banco de dados, esse método lança uma javax.persistence.EntityNotFoundException e não a garantia de que o estado da entidade será inicializado.
Tanto o find() como o getReference() lançam uma IllegalArgumentException se seus parâmetros não forem um tipo de entidade. Eles podem ser invocados fora do escopo de uma transação. Nesse caso, qualquer objeto retornado é desacoplado se o EntityManager for uma transação com escopo, mas permanece gerenciado se estiver em um contexto de persistência estendido.
Objetos persistentes também podem ser localizados utilizando-se EJB QL. Diferentemente do EJB 2.1, não há métodos finder, e você precisa criar um objeto Query chamando os métodos createQuery(), createNamedQuery() ou createNativeQuery() do EntityManager.
Criar e executar uma consulta EJB QL é muito parecido com criar e executar uma PreparedStatement JDBC:
Todas as instâncias de objeto retornadas por find(), getResource(), ou por uma consulta, permanecerão gerenciadas enquanto o contexto de persistência estiver ativada. Isso significa que outras chamadas para find() (ou qualquer outra) retornarão a mesma instância do objeto de entidade.

*Atualizando entidades
Depois de localizar um bean de entidade chamando find(), chamando getReference() ou criando e executando uma consulta, a instância do bean de entidade permanece gerenciada pelo contexto de persistência até o contexto ser fechado. Durante esse período, podemos alterar o estado da instância do bean de entidade como faria com qualquer outro objeto, e as atualizações serão sincronizadas automaticamente (dependendo do modo flush) ou se você chamar o método flush() diretamente:

*Mesclando entidades

A especificação Java Persistence permite mesclar alterações de estado feitas em uma entidade desacoplada de volta para o armazenamento de persistência utilizando o método merge() do gerenciador de entidades.
O método merge() chamará uma IllegalArgumentException se seu parâmetro não for um tipo de entidade. A TransactionRequiredException é chamada se esse método for invocado em um contexto de persistência com escopo de transação. Mas se o gerenciador de entidades for um contexto de persistência estendido, será valido invocar esse método fora do escopo de uma transação e a atualização será enfileirada até o contexto de persistência interagir com uma transação.

*Removendo entidades
Uma entidade pode ser removida do banco de dados chamando o método EntityManager.remove().
Depois de remove() for chamado, a instância address não será mais gerenciada e se tornará desacoplada. Além disso, se a entidade tiver algum relacionamento com outros objetos de entidade, estes também poderão ser removidos, dependendo das regras em cascata. A operação remove() só pode ser desfeita recriando a instância de entidade com o método persist().
O método remove() chama uma IllegalArgumentException se seu parâmetro não for um tipo de entidade. A TransactionRequiredException é chamada se esse método for invocado em um contexto de persistência com escopo de transação. Entretanto, se o EntityManager for um contexto de persistência estendido, será válido invocar esse método fora do escopo de uma transação, e o remove será enfileirado até o contexto de persistência interagir com uma transação.

*refresh()
Se a preocupação for pelo fato de que uma entidade gerenciada não foi atualizada em relação ao banco de dados, poderá utilizar o método EntityManager.refresh(). Este método atualiza o estado da entidade, sobrescrevendo quaisquer alterações feitas na entidade.
Se o bean de entidade tiver entidades relacionadas, essas entidades também podem ser atualizadas, dependendo da diretiva da cascata configurada nos metadados da entidade de mapeamento.
O método refresh() chama uma IllegalArgumentException se seu parâmetro não for gerenciado pela instância atual do gerenciador de entidades. A TransactionRequiredException é chamada se esse método for invocado em um contexto de persistência com escopo de transação. Entretanto, se o gerenciador de entidades for um contexto de persistência estendido, será válido invocar esse método fora do escopo de uma transação. Se o objeto não mais estiver no banco de dados porque outra thread ou outro processo o removeram, esse método então lançará uma EntityNotFoundException.

*contains() e clear()
O método contains() recebe uma instância de entidade como um parâmetro. Se essa instância de objeto particular for gerenciada atualmente pelo contexto de persistência, ela retornará true. Ela lança uma IllegalArgumentException se o parâmetro não for uma entidade.
Se precisar desacoplar todas as instâncias de entidade gerenciadas de um contexto de persistência, podemos invocar o método clear() do EntityManager. Ao chamar clear(), todas as alterações feitas nas entidades gerenciadas serão perdidas. É prudente chamar flush() antes de clear() ser invocado, para que não seja perdida nenhuma alteração.
*flush() e FlushModeType
Ao chamar persist(), merge() ou remove(), essas alterações não são sincronizados com o banco de dados até o gerenciador de entidades decidir gravar. Você pode forçar a sincronização a qualquer momento chamando flush(). Por padrão, a atualização acontece automaticamente antes de uma consulta correlacionada ser executada (implementações ineficientes podem até mesmo atualizar antes de qualquer consulta) e em tempo de confirmação de uma transação. A exceção a essa regra padrão é find(). Uma gravação não precisa acontecer quando find() ou getReference() é chamado, porque localizar por meio de uma chave primária é algo que não seria afetado por nenhuma atualização.
Podemos controlar e alterar esse comportamento padrão usando a enumeração javax.persistence.FlushModeType:

AUTO é o comportamento padrão descrito no trecho do código anterior. COMMIT significa que alterações só são gravadas quando a transação é confirmada, não antes de nenhuma consulta.
FlushModeType.COMMIT faz sentido por razões de desempenho. A melhor maneira de ajustar um aplicativo de banco de dados é remover chamadas desnecessárias ao banco de dados. Algumas implementações de fornecedores farão todas as atualizações necessárias com uma chamada JDBC em lote. Utilizar COMMIT permite que o gerenciador de entidades execute todas as atualizações em um grande lote, limita a quantidade de tempo que a transação tem nesse bloqueio de banco de dados, mantendo-o somente até o fim da confirmação JTA.

domingo, 6 de janeiro de 2008

Obtendo um EntityManager

Obtendo um EntityManager

No Java SE, os gerenciadores de entidades são criados usando um javax.persistence.EntityManagerFactory. Embora de podermos utilizar a interface factory no Java EE, essa plataforma fornece alguns recursos adicionais que tornam mais fácil e menos prolixo gerenciar instâncias do gerenciador de entidades.

*EntityManagerFactory
O EntityManager pode ser criado ou obtido de uma EntityManager Factory. Em um aplicativo Java SE, você precisa utilizar uma EntityManagerFactory para criar instâncias de um EntityManager. Utilizar o criador de instâncias (factory) não é um requisito no Java EE.
Os métodos createEntityManager() retornam instâncias EntityManager que gerenciam um contexto de persistência estendido distinto. Você pode passar um parâmetro java.util.Map para sobrescrever ou estender quaisquer propriedades específicas de provedor no qual não esta declarado no arquivo persistence.xml. Depois de terminar de utilizar a EntityManagerFactory, você deve usar close() para fechá-la (a menos que ela seja injetada). O método isOpen() permite verificar se a referência EntityManagerFactory continua válida.

*Obtendo uma EntityManagerFactory no Java SE
No Java SE, a classe javax.persistence.Persistence é responsável pela inicialização de um EntityManagerFactory.
A classe javax.persistence.Persistence procura os descritores de implantação persistence.xml dentro de seu caminho de classe Java. O parâmetro do tipo String que deve ser passado permite que a implementação Persistence localize uma EntityManagerFactory que corresponde com o nome dado.

No Java SE, é recomendável usar close() para fechar a EntityManagerFactory. Isso libera todos os recursos mantidos pela factory.

*Obtendo uma EntityManagerFactory no Java EE
No Java EE, é um pouco mais fácil obter uma EntityManagerFactory. Ela pode ser injetada diretamente em um campo ou método setter dos seus EJBs utilizando a anotação @javax.persistence.PersistenceUnit.
O unitName() é a identidade da PersistenceUnit. Quando a PersistenceUnit é utilizada, além de injetar a EntityManagerFactory, ela também registra uma referência a si própria dentro do JNDI ENC do EJB. O contêiner EJB é responsável por avisar a anotação @PersistenceUnit e injetar a factory correta.
Diferentemente do Java SE, um EntityManagerFactory injetada é automaticamente fechada pelo contêiner EJB quando a instância é descartada. Na realidade, se você chamar close() em uma EntityManagerFactory injetada, será lançada uma IllegalStateException.

Qualquer duvida, mande um email para leurimar.lins@gmail.com

sexta-feira, 19 de outubro de 2007

Introdução JPA

Bom galera, vou iniciar uma uma série de postagens falando sobre Jpa (Java Persistence API - EJB 3.0), começando da introdução (no qual esta postagem se refere) até os niveis de relacionamentos de entidades...
Espero que seja de bom proveito a todos...e qualquer dúvida, estarei disposto a tirá-la.
...



O que é JPA ?

A Java Persistence API define uma maneira de mapear objetos java simples e comuns (plain old Java objects - POJOs) para um banco de dados. Esses objetos são chamados de beans de entidade. É como qualquer outra classe Java, exceto pelo fato de serem mapeados, utilizando metadados da JPA -@ (anotacao) - para um determinado banco de dados. Portanto, eles podem ser inseridos e carregados a partir de um banco de dados sem que o desenvolvedor escreva nenhum código de conexão JDBC. A JPA também define uma linguagem de consulta que tem recursos que fazem um paralelo com o SQL, mas são personalizados para trabalhar com objetos Java em vez de com um esquema relacional bruto.
Primeiro Passo - Desenvolvendo um bean de entidade.
Bom, vamos implementar uma entidade simples, denominada Person (Pessoa). Esta entidade encapsula os dados de uma pessoa. (exemplo simples, para ter maior entidemento...porém apartir de cada postagem iremos implementar exemplos mais complexos)
Ao desenvolver um bean de entidade, tudo que precisamos definir é a classe bean. As entidades na JPA são objetos Java simples anotados com os metadados de mapeamento. Definindo a entidade Person...

@Entity //anotacao obrigatória para qualquer entidade
@Table(name = "Person") //nome da tabela no BD
public class Person implements Serializable {
@Id // definindo um id
@Column(name = "Id") // nome da coluna no BD
@GeneratedValue(strategy = GenerationType.SEQUENCE) //id incremental (no postgre usasse SEQUENCE, no mySql usa IDENTITY)
private int id;

@Column(name = "Name") //nome da coluna no BD
private String name;

@Column(name = "Cpf") //nome da coluna no BD
private String cpf;

@Column(name = "age") //nome da coluna no BD
private int age;
...metodos getters e setters...
}
Bom pessoal, na próxima postagem, irei continuar com a introdução ao JPA,
mostrando o arquivo de configuração JPA, denominado persistence.xml.
Bons estudos...
Leurimar Lins