JPA com Hibernate - Duvidas sobre o EntityManager

5 respostas
tiagoharris

Caros amigos,

Estou dando os primeiros passos com JPA. Escrevi uma aplicação console muito simples baseada no exemplo do livro da Oreilly, EJB 3.0. Primeiramente gostaria de mostrar minhas classes, em seguida irei expor as minhas dúvidas. Há alguma forma mais “bonita” de colocar código-fonte no post?

Entity Cabin

package com.titan.domain;

import java.io.Serializable;

import javax.persistence.Column;

import javax.persistence.Entity;

import <a href="http://javax.persistence.Id">javax.persistence.Id</a>;

import javax.persistence.Table;
@Entity

@Table(name=CABIN)

public class Cabin implements Serializable {

private int id;

private String name;

private int deckLevel;

private int shipId;

private int bedCount;
@Id
@Column(name="ID")
public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

@Column(name="NAME")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Column(name="DECK_LEVEL")
public int getDeckLevel() {
    return deckLevel;
}

public void setDeckLevel(int deckLevel) {
    this.deckLevel = deckLevel;
}

@Column(name="SHIP_ID")
public int getShipId() {
    return shipId;
}

public void setShipId(int shipId) {
    this.shipId = shipId;
}

@Column(name="BED_COUNT")
public int getBedCount() {
    return bedCount;
}

public void setBedCount(int bedCount) {
    this.bedCount = bedCount;
}

}

TravelAgentRemote

package com.titan.travelagent;

import javax.ejb.Remote;
import javax.persistence.EntityManager;

import com.titan.domain.Cabin;

import com.titan.domain.CreditCard;

import com.titan.domain.Customer;

import com.titan.domain.Phone;
@Remote

public interface TravelAgentRemote {

public void createCabin(Cabin cabin);

public Cabin findCabin(int id);

}

TravelAgentBean

package com.titan.travelagent;

import javax.ejb.Stateless;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;
import com.titan.domain.Cabin;

import com.titan.domain.CreditCard;

import com.titan.domain.Customer;

import com.titan.domain.Phone;
@Stateless

public class TravelAgentBean implements TravelAgentRemote{

@PersistenceContext(unitName=titan)

private EntityManager manager;
public void createCabin(Cabin cabin) {
    manager.persist(cabin);
}

public Cabin findCabin(int id) {
    return manager.find(Cabin.class, id);
}

}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?> java:/TitanDB

Agora o código cliente:

Client

package com.titan.clients;

import java.util.Collection;
import java.util.Properties;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.rmi.PortableRemoteObject;
import com.titan.domain.Cabin;

import com.titan.domain.CreditCard;

import com.titan.domain.Customer;

import com.titan.domain.Phone;

import com.titan.travelagent.TravelAgentRemote;

public class Client {

public static void main(String[] args) {
    try {
        Context jndiContext = getInitialContext();
        Object ref = jndiContext.lookup("TravelAgentBean/remote");
        TravelAgentRemote dao = (TravelAgentRemote)PortableRemoteObject.narrow(ref, TravelAgentRemote.class);
        
        // Create cabin
        Cabin cabin1 = new Cabin();
        cabin1.setId(1);
        cabin1.setName("Master Suite");
        cabin1.setDeckLevel(1);
        cabin1.setShipId(1);
        cabin1.setBedCount(3);
        
        // Persist the cabin
        dao.createCabin(cabin1);
        
        // update the name
        cabin1.setName("Basic suite");
        
        // Search the cabin newly persisted
        Cabin cabin2 = dao.findCabin(1);
        System.out.println("=========== Cabin ===========");
        System.out.println(cabin2.getName( ));
        System.out.println(cabin2.getDeckLevel( ));
        System.out.println(cabin2.getShipId( ));
        System.out.println(cabin2.getBedCount( ));                    

    }
    catch (NamingException e) {
        e.printStackTrace();
    }
    
}

public static Context getInitialContext() throws NamingException{
    Properties env = new Properties();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
    env.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
    env.put(Context.PROVIDER_URL, "localhost");
    return new InitialContext(env);
}

}

Bom, agora vamos às dúvidas. A especificação JPA diz que uma vez que um entity bean se torna gerenciado pelo EntityManager (após chamar EntityManager.persist() ou EntityManager.find()), qualquer alteração feita no entity é rastreada e persistida automaticamente no banco de dados.

Por tanto, aqui estou persistindo o entity Cabin:

// Create cabin
        Cabin cabin1 = new Cabin();
        cabin1.setId(1);
        cabin1.setName("Master Suite");
        cabin1.setDeckLevel(1);
        cabin1.setShipId(1);
        cabin1.setBedCount(3);
        
        // Persist the cabin
        dao.createCabin(cabin1);

Isto funciona perfeitamente, chequei o banco de dados e o registro foi inserido com sucesso.

Então, como eu disse, de acordo com o que a spec diz, já que eu chamei EntityManager.persist() passando a instância do entity Cabin, esta instância se torna gerenciada, por tanto, se eu fizer isso

// update the name
        cabin1.setName("Basic suite");

o nome seria alterado de “Master suite” para “Basic suite” e já que a instância é gerenciada pelo entity manager, as alterações seriam feitas automaticamente no banco de dados. Mas isto não está acontecendo, o nome no banco de dados continua inalterado.

Alguém tem alguma idéia do por que disso? Estou fazendo algo de errado?

Utilizei estes jars:

hibernate-entitymanager.jar (do Hibernate)
ejb3-persistence.jar (do Hibernate)
jboss-ejb3x.jar (do JBoss)
jbossall-client.jar (do JBoss)

A spec diz que o elemento do arquivo persistence.xml é opcional e que se o mesmo não for informado, um valor default é assumido. Mas no meu caso, qual é o valor padrão que é assumido?

Se alguém puder me tirar estas dúvidas, agradeço!

Um grande abraço à todos.

5 Respostas

R

kra naum sei stand alone mais usando injeção de dependencia com um conteiner web, apos uma chamada ao find(), a entidade fica detached, para remover por exemplo tem que chamar merge() e depois remove(), tenta ai o merge() pra ver se funciona.

tiagoharris

De fato Rafael, é isso o que está acontecendo mesmo. O contexto de persisência, neste exemplo, é transaction scoped! Por tanto, após a chamada ao createCabin() (que interage com o entity manager chamando o método persist()), o entity se torna detached.

Agora gostaria de saber como poderia fazer para utilizar um contexto de persistência extendido neste meu exemplo, que é um cliente standalone chamando um stateless bean que interage com o Entity Manager. Ouvi dizer que contexto de persistência extendido só pode ser utilizado com beans stateful, gostaria que alguém confirmasse isso.

Obrigado pela resposta, Rafael!

T

Cara eu acredito que vc só pode utilizar esse statelessBean sem um cliente não JEE se seu container tiver o microcontainer.

K

Olá… não consegui rodar este exemplo no eclipse.

  • criei um projeto EAR
  • criei um projeto EJB e atribui a Facets do JPA

rodo o projeto EAR como “run on server” com jboss 4.2
e depois tento rodar a classe client.java com application.

mas ele dá o seguinte erro:

javax.naming.NameNotFoundException: TravelAgentBean/remote

at org.jboss.ha.jndi.TreeHead.lookup(TreeHead.java:242)

at org.jboss.ha.jndi.HAJNDI.lookup(HAJNDI.java:155)

at sun.reflect.GeneratedMethodAccessor120.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:585)

at org.jboss.ha.framework.server.HARMIServerImpl.invoke(HARMIServerImpl.java:209)

at sun.reflect.GeneratedMethodAccessor119.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:585)

at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)

at sun.rmi.transport.Transport$1.run(Transport.java:153)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.Transport.serviceCall(Transport.java:149)

at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)

at java.lang.Thread.run(Thread.java:595)

at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)

at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)

at sun.rmi.server.UnicastRef.invoke(Unknown Source)

at org.jboss.ha.framework.server.HARMIServerImpl_Stub.invoke(Unknown Source)

at org.jboss.ha.framework.interfaces.HARMIClient.invokeRemote(HARMIClient.java:219)

at org.jboss.ha.framework.interfaces.HARMIClient.invoke(HARMIClient.java:321)

at $Proxy0.lookup(Unknown Source)

at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:667)

at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)

at javax.naming.InitialContext.lookup(Unknown Source)

at com.titan.clients.Client.main(Client.java:18)

Se alguém puder me ajudar agradeço.

pierobom

Olá keithnak,

Ressucitando o post :)

Por acaso conseguiu resolver este problema e executar o exemplo? 

Parei neste ponto também. Realizo o deploy, mas quando rodo o cliente ele não encontra o bean através do JNDI.

Abraço,
Jean

Criado 18 de setembro de 2007
Ultima resposta 21 de dez. de 2009
Respostas 5
Participantes 5