EJB3 SessionBean e EntityManager.merge()

8 respostas
D

Salve, Salve GUJ,

Estou percebendo uma característica do EJB3 SessionBean, e gostaria de enteder se é um erro ou não.

Tenho esse SessionBean e suas interfaces como manda a regra.

@Stateless 
public class FinanceSession implements IFinanceLocal, IFinanceRemote { 
            @PersistenceContext 
            EntityManager em;

            public void updateAccount(Account account) {
                        //TEM QUE FAZER O MERGE AQUI SE NAO DAH EXCEPTION !!!!
                        em.persist(em.merge(account)); 
            }

            public Account getAccount(Integer id) { 
                        Query query = em.createQuery("SELECT a from Account a where id = " + id); 
                        return (Account) query.getSingleResult(); 
            } 

            // mais codigo aqui...
}

Quando realizado um lookup em um Servlet no próprio contexto, ex:

IFinanceLocal local = (IFinanceLocal) context.lookup("jboss-dev/FinanceSession/local");
Account account = local.getAccount(1);
account.setDescription("Nova descricao");
local.updateAccount(account);

Sou forçado a usar no SessionBean o merge(), para reintegrar na seção de persistência a Entity.

Estou fazendo algo errado ou é isso mesmo? Toda vez que eu enviar via interface Local/Remota uma Entity, e mesmo que eu mantenha a instancia da interface (o SessionBean) existente, lá dentro, quando devolver a Entity para o Session, preciso realizar o merge(). Seria problema se eu criar no SessionBean um getPersistenceManager() e usar o PersistenceManager no Servlet? (eca!)

Valew, forte abraço,

Davi.

8 Respostas

Jair_Rillo_Junior

É isso mesmo!!
Lembre-se que JPA trabalha com estados e para persistir uma entidade, ela deve estar com o estado de MANAGED (o merge() faz isso).
Como você está trabalhando com Stateless, ele não mantém o estado, portanto o estado da entidade não é mantido (e isso é normal).

D

E se o SessionBean fosse Statefull, eu ainda precisaria do merge ou fico livre dele? Existiria vantagens do uso do Statefull neste caso ou é overhead a mais?

L

O estado “gerenciado” é feito pra durar pouco tempo. Normalmente dura no espaço de uma transação, se houver uma; ou imediatamente ao retorno da query, se não houver uma transação.

É normal você dar merge dos elementos que vem como parâmetros antes de fazer qualquer coisa com eles. Usar Stateful pode garantir que um objeto esteja gerenciado por mais tempo, ms não impede que você ponha um objeto não-gerenciado como parâmetro (que faz com que dê erro do mesmo jeito de antes).

Não se preocupe com o merge(), é normal e é recomendado.

Jair_Rillo_Junior

Como o Leonardo disse, se você receber uma entidade por parametro (detached) você ainda vai precisar do merge
E usar statefull só para esse caso, é realmente overhead.

diegosantiviago

Só como dúvida…

o correto nao seria usar um find(Account.class, account.getId()) e logo em seguida realizar as alterações?

Estou lendo este livro: Pro EJB 3 Java Persistence API e na página 28 possui este codigo:

public Employee raiseEmployeeSalary(int id, long raise) { Employee emp = em.find(Employee.class, id); if (emp != null) { emp.setSalary(emp.getSalary() + raise); } return emp; }

Ou o merge é utilizado quando se passa um Objeto como parâmetro?

L

diegosantiviago:
Só como dúvida…

o correto nao seria usar um find(Account.class, account.getId()) e logo em seguida realizar as alterações?

Estou lendo este livro: Pro EJB 3 Java Persistence API e na página 28 possui este codigo:

public Employee raiseEmployeeSalary(int id, long raise) { Employee emp = em.find(Employee.class, id); if (emp != null) { emp.setSalary(emp.getSalary() + raise); } return emp; }

Ou o merge é utilizado quando se passa um Objeto como parâmetro?

Tanto faz. Pode-se tanto usar atributos primitivos como parâmetro ou o objeto inteiro. Vai do gosto do freguês. É que antigamente, devido às várias falhas do J2EE, preferia-se usar o que você sugeriu, mas hoje isso não faz mais sentido e os programadores são mais livres para escolher o que acharem melhor.

E acredite: tem muito programador tarimbado por aí, dando palestra e tudo mais, que sofreu uma lavagem cerebral tão intensa, por causa das versões antigas do EJB, que não consegue acreditar como é possível fazer algo no “novo jeito”.

Bom, o merge() é utilizado quando se recebe uma entity como parâmetro, dentro de um contexto transacional (como métodos de um Session Bean). A razão é que não há nenhuma garantia que a entity recebida esteja sincronizada (attached) com o provedor de persistência (JPA). E o merge() faz essa sincronia.

diegosantiviago

Mas se eu usar o find, ele entra no contexto, nao é?

A operação de merge permite que os entities sejam alterados em modo “offline”, e então tenham essas alterações incorporadas ao contexto de persistência mais tarde.

Eu entendi que deve ser usado quando é um objeto novo, ou ele saiu do contexto.

Talvez tenha entendido errado…

diegosantiviago

Leonardo3001:
Não confia em merge não. E eu te digo uma coisa: MERGE não é UPDATE!

Quando você quer atualizar algo é só pegar um objeto gerenciado pelo container JPA, e alterar suas propriedades com os setters. Quando der um commit, as alterações terão sido enviadas à base de dados.

em : http://www.guj.com.br/posts/list/75585.java

Criado 14 de outubro de 2008
Ultima resposta 17 de mar. de 2009
Respostas 8
Participantes 4