Ejb + jsf

Olá, estou começando a desenvolvedor com EJB. Eu criei uma entidade, um ManagedBean e um EJB. Consigo inserir e listar dados do banco, mas o meu método de deletar não dá erro, porém não deleta os dados do banco.

Entidade:

package br.com.teste.entidade;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity	
public class Cliente {
	
	@Id	
	@GeneratedValue(strategy=GenerationType.IDENTITY)	
	private Integer id;
	
	@Column
	private String nome;

	public Integer getId() {
		return id;
	}

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

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
	
}

ManagedBean:

package br.com.teste.managedbean;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.naming.InitialContext;
import javax.naming.NamingException;


import br.com.teste.ejb.ClienteBean;
import br.com.teste.entidade.Cliente;

@ManagedBean
@ViewScoped
public class ClienteMB {

	private Cliente cliente = new Cliente();
	private List<Cliente> lstCliente =  new ArrayList<Cliente>();
	
	public String incluirCliente(){
		InitialContext ini;
		try {
			ini = new InitialContext();
		
			ClienteBean clienteBean = (ClienteBean)ini.lookup("java:module/ClienteBean");
			
			clienteBean.salvar(cliente);
			cliente = new Cliente();
			lstCliente = clienteBean.buscarCliente();
			
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	public String deletarCliente(){
		InitialContext ini;
		
		try {
			ini = new InitialContext();
			
			ClienteBean clienteBean = (ClienteBean)ini.lookup("java:module/ClienteBean");
			clienteBean.deletar(cliente);
			
			cliente = new Cliente();
			lstCliente = clienteBean.buscarCliente();
		} catch (NamingException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	public Cliente getCliente() {
		return cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	public List<Cliente> getLstCliente() {
		return lstCliente;
	}

	public void setLstCliente(List<Cliente> lstCliente) {
		this.lstCliente = lstCliente;
	}
	
}

EJB:

package br.com.teste.ejb;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import br.com.teste.entidade.Cliente;

@Stateless
public class ClienteBean {
	
	@PersistenceContext
	EntityManager em;
	
	public void salvar(Cliente cliente) {
		em.persist(cliente);
	}
	
	public void deletar(Cliente cliente) {
		em.remove(cliente);
	}
	
	public List<Cliente> buscarCliente(){
		return em.createQuery("FROM Cliente").getResultList();
	}
}

Página:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
      
      <h:head><title>Minha Aplicação</title></h:head>
      <h:body>
      
      	<h:form>
      		<h:outputLabel value="Nome: " for="nome" />
      		<h:inputText id="nome" value="#{clienteMB.cliente.nome}" 
      			required="true" requiredMessage="Campo obrigatório"
      			maxlength="200"/>
      		<h:commandButton value="Salvar" action="#{clienteMB.incluirCliente()}" />
      	</h:form>
      	
      	<h:dataTable id="tabela" value="#{clienteMB.lstCliente}" var="item">
      		<h:column>
      			<f:facet name="header">
      				<h:outputText value="ID" />
      			</f:facet>
      			<h:outputText value="#{item.id}"/>
      		</h:column>
      		<h:column>
      			<f:facet name="header">
      				<h:outputText value="Nome" />
      			</f:facet>
      			<h:outputText value="#{item.nome}"/>
      		</h:column>
      		<h:column>
      			<h:commandButton value="Deletar" 
                                action="#{clienteMB.deletarCliente()}" />
      		</h:column>
      	</h:dataTable>
      
      </h:body>
</html>

Já debugou para ver o que está acontecendo? Aparentemente você não está passando um cliente para ser deletado. O que está sendo enviado para o EJB é um cliente novo, instanciado na linha 19 do seu ClienteMB sem nenhum atributo preenchido.

Tente assim:

<h:column> <h:commandButton value="Deletar" action="#{clienteMB.deletarCliente(item)}" /> </h:column>

E altere o método do seu MB para:

[code] public String deletarCliente(Cliente cliente){
InitialContext ini;

    try {  
        ini = new InitialContext();  
          
        ClienteBean clienteBean = (ClienteBean)ini.lookup("java:module/ClienteBean");  
        clienteBean.deletar(cliente);  
          
        cliente = new Cliente();  
        lstCliente = clienteBean.buscarCliente();  
    } catch (NamingException e) {  
        e.printStackTrace();  
    }  
      
    return null;  
}  [/code]

ps: sem ter ligação com o erro, está usando EJB remoto ou local?

Poste a implementação do seu método deletar do EJB. Eu acho que o problema é que a entidade não é gerenciada na hora que você manda remover.

É a classe ClienteBean que ele postou. Mas acho que se fosse isso daria algum erro na hora que tentasse deletar.

Depende se a entidade é nova ou se ela está como DETACHED. Segue o que diz a especificação:[quote]A managed entity instance becomes removed by invoking the remove method on it or by cascading the
remove operation.
The semantics of the remove operation, applied to an entity X are as follows:

  • If X is a new entity, it is ignored by the remove operation. However, the remove operation is
    cascaded to entities referenced by X, if the relationship from X to these other entities is annotated with the cascade=REMOVE or cascade=ALL annotation element value.
  • If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities
    is annotated with the cascade=REMOVE or cascade=ALL annotation element value.
  • If X is a detached entity, an IllegalArgumentException will be thrown by the remove
    operation (or the transaction commit will fail)
    .
  • If X is a removed entity, it is ignored by the remove operation.
  • A removed entity X will be removed from the database at or before transaction commit or as a
    result of the flush operation[/quote]

[quote=fredericomaia10]Já debugou para ver o que está acontecendo? Aparentemente você não está passando um cliente para ser deletado. O que está sendo enviado para o EJB é um cliente novo, instanciado na linha 19 do seu ClienteMB sem nenhum atributo preenchido.

Tente assim:

<h:column> <h:commandButton value="Deletar" action="#{clienteMB.deletarCliente(item)}" /> </h:column>

E altere o método do seu MB para:

[code] public String deletarCliente(Cliente cliente){
InitialContext ini;

    try {  
        ini = new InitialContext();  
          
        ClienteBean clienteBean = (ClienteBean)ini.lookup("java:module/ClienteBean");  
        clienteBean.deletar(cliente);  
          
        cliente = new Cliente();  
        lstCliente = clienteBean.buscarCliente();  
    } catch (NamingException e) {  
        e.printStackTrace();  
    }  
      
    return null;  
}  [/code]

ps: sem ter ligação com o erro, está usando EJB remoto ou local?[/quote]

Eu tentei fazer o que você falou, mas não adiantou. Debugando, nem entra no método deletarCliente parece que o botão deletar está sem ação.
Estou usando EJB local.
Como eu disse, estou aprendendo sobre EJB, não sei se a forma que estou implementando está certo.

Valeu!

Ah, seu botão com a action para deletar está fora do <h:form> :slight_smile:

A sim.
Testei aqui, agora está entrando em exceção.

exception

javax.servlet.ServletException: javax.ejb.EJBException: java.lang.IllegalArgumentException: Removing a detached instance br.com.teste.entidade.Cliente#7
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)

root cause

javax.faces.el.EvaluationException: javax.ejb.EJBException: java.lang.IllegalArgumentException: Removing a detached instance br.com.teste.entidade.Cliente#7
	javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
	com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	javax.faces.component.UICommand.broadcast(UICommand.java:315)
	javax.faces.component.UIData.broadcast(UIData.java:1093)
	javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)

Não está conseguindo remover a instância?

Agora sim, você precisa buscar a entidade antes de persistir. use o getReference ou o find do EntityManager

Agora entra o que o Rodrigo falou anteriormente. Sua entidade está detached.

Tente usar assim o método de deletar:

public void deletar(Cliente cliente) { em.remove(em.find(cliente.getId()); }

[quote=fredericomaia10]Agora entra o que o Rodrigo falou anteriormente. Sua entidade está detached.

Tente usar assim o método de deletar:

public void deletar(Cliente cliente) { em.remove(em.find(cliente.getId()); }[/quote]

Obrigado. Funcionou!
Mais tarde, vou tentar fazer o método atualizar.

public void deletar(Cliente cliente) {
		em.remove(em.find(Cliente.class, cliente.getId()));
	}

[quote=Viciado][quote=fredericomaia10]Agora entra o que o Rodrigo falou anteriormente. Sua entidade está detached.

Tente usar assim o método de deletar:

public void deletar(Cliente cliente) { em.remove(em.find(cliente.getId()); }[/quote]

Obrigado. Funcionou!
Mais tarde, vou tentar fazer o método atualizar.

public void deletar(Cliente cliente) { em.remove(em.find(Cliente.class, cliente.getId())); } [/quote]Troque o find por getReference. Ele melhora a performance, se quiser mais detalhes: http://uaihebert.com/?p=1622

[quote=Hebert Coelho][quote=Viciado][quote=fredericomaia10]Agora entra o que o Rodrigo falou anteriormente. Sua entidade está detached.

Tente usar assim o método de deletar:

public void deletar(Cliente cliente) { em.remove(em.find(cliente.getId()); }[/quote]

Obrigado. Funcionou!
Mais tarde, vou tentar fazer o método atualizar.

public void deletar(Cliente cliente) { em.remove(em.find(Cliente.class, cliente.getId())); } [/quote]Troque o find por getReference. Ele melhora a performance, se quiser mais detalhes: http://uaihebert.com/?p=1622[/quote]

OK. Valeu!
Para cada entidade que eu criar, vou ter que criar também um ManagedBean e um EJB ou posso ter genérico e ao ser chamado informar o nome da entidade?