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:/TitanDBAgora 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.