Estou com problemas ao tentar alterar um objeto que tem relacionamento com outros objetos, meu código está assim:
package com.modelo.managedBean;
import com.modelo.bean.Promotor;
import com.modelo.dao.PromotorDAO;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class PromotorMB implements Serializable {
private Integer id;
private PromotorDAO promotorDAO;
private Promotor promotor = new Promotor();
private List<Promotor> promotores = new ArrayList<Promotor>();
// GETTER / SETTER
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
if (id != null) {
promotor = promotorDAO.recuperarPromotor(this.getId());
}
}
public Promotor getPromotor() {
return promotor;
}
public void setPromotor(Promotor promotor) {
this.promotor = promotor;
}
public List<Promotor> getPromotores() {
promotorDAO = new PromotorDAO();
promotores = promotorDAO.listarPromotores();
return promotores;
}
// REGRAS DE NEGÓCIO
public String salvar() {
promotor.getGrupoAcesso().setLogin(promotor.getLogin());
if (promotorDAO.inserirPromotor(promotor)) {
return "sucessoOperacao";
} else {
return "falhaOperacao";
}
}
public String excluir() {
promotor = promotorDAO.recuperarPromotor(promotor.getIdUsuario());
if (promotorDAO.excluirPromotor(promotor)) {
return "sucessoOperacao";
} else {
return "falhaOperacao";
}
}
public String atualizar() {
//promotor.getGrupoAcesso().setLogin(promotor.getLogin());
promotorDAO = new PromotorDAO();
if (promotorDAO.atualizarPromotor(promotor)) {
return "sucessoOperacao";
} else {
return "falhaOperacao";
}
}
}
Eu listo todos os registros daquele tipo na tela, escolho qual eu desejo alterar e passo ele pra outra tela de edição, quando passo ele pra tela de edição carrego o managedBean referente ao objeto, eu debuguei e ele está vindo blz, está puxando todos os objetos relacionados. Porém quando vou dar o merge no BD ocorre este erro:
Advertência: #{promotorMB.atualizar}: java.lang.IllegalStateException: Transaction not active
javax.faces.FacesException: #{promotorMB.atualizar}: java.lang.IllegalStateException: Transaction not active
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:563)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.faces.el.EvaluationException: java.lang.IllegalStateException: Transaction not active
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
... 23 more
Caused by: java.lang.IllegalStateException: Transaction not active
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:82)
at com.modelo.dao.PromotorDAO.atualizarPromotor(PromotorDAO.java:58)
at com.modelo.managedBean.PromotorMB.atualizar(PromotorMB.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.el.parser.AstValue.invoke(AstValue.java:191)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
... 24 more
Com base neste link http://blog.caelum.com.br/entidades-managed-transient-e-detached-no-hibernate-e-jpa/, eu acho que o meu objeto GrupoAcesso está detached pois quando eu faço um em.find(Promotor.class, 1); ele não está trazendo o grupoAcesso vinculado a ele.
Partindo desta conclusão, acredito ter duas opções:
1 - Posso configurar as anotações corretamente pra que o GrupoAcesso fique vinculado ao Promotor - acredito ser o correto
2 - Posso tratar o GrupoAcesso como detached, ou seja, no caso do exemplo, fazer isto:
Cliente c = new Cliente();
c.setId(1);
c = em.merge(c);
c.setNome("Cliente com nome alterado");
Este código do exemplo faz a mesma coisa que o ErickMacedo falou, certo?
trasitente = quando o objeto não tem representação no banco de dados
Ex: Produto produto = new Produto();
Manager = quando o objeto está gerenciado pelo EntityManager
Ex: Produto c = em.find(Produto.class , 1)
neste caso se agente mudar um atributo do produto por exemplo, automaticamento no momento do commit ele irá sofrer alteração
no banco de dados
Obs: aqui você temque saber se você esta usando Transação pelo Container ou pela aplicação, se estiver usando pela aplicação
cabe a você dar o commit.
Detached = quando você tem um objeto que aparentemente é igual á do banco de dados , porem o EntityManager não sabe que ele existe.
Ex:
Produto produto = new Produto();
produto.setId(0008);
Ex: Para atualizar
Produto produto = new Produto();
produto.setId(0008);
em.merge(produto );
produto.setMarca("Samsung");
No exemplo acima o merge apenas junta a possível entidade com mesmo id que se encontra no EntityManager, mais ele não retorno
o objeto no estado de Manager (gerenciado), ou seja o produto ficou gerenciado somente durante o em.merge(produto ), depois ele
continua um objeto Transitente, Então precisamos pegar o retorno do merge que este retorna um objeto no estado Manager como no
código abaixo.
Então eu vou ter que primeiro colocar o objeto no EntityManager, no meu caso usando o método recuperarPromotor(int idPromotor), uma vez que o mesmo está gerenciado, posso atualizar sem problemas com o merge, é isso?
Cara, eu acho estranho porque as outras funcionalidades estão usando o mesmo padrão de CRUD, e somente nesta ocorreu este erro "/
Quando estou mandando listar os promotores getPromotores() está entrando em looping, depois de umas 10 passadas no looping, ele sai e exibe a lista sem erros "/
Aparentemente Sim, só temque tomar cuidado se o EntityManager da onde você esta tirando esse promotor não estiver mais aberta na hora do commit o objeto mudará seu estado para detached e obviamente qualquer mudança nessa referência não surtirá efeito no banco de dados
Eu particularmente usaria esta sintaxe
em.merge(em.merge(promotor));
Assim ele pega o objeto no estado manager e atualiza.
Cara o JPA funciona assim!! eu não sou um expertise em JPA, temque dar uma analisada para saber o que esta acontecendo com o restante…
Após selecionado a opção editar, é passado o idUsuario(que seria o id do Promotor) para o PromotorMB.
Na classe PromtorMB, quando ele recebe o idUsuario, o UsuarioDAO vai no BD e traz o promotor correto. Está managed.
Agora a tela de edição:
Seguinte você NÃO pode ter código DAO no getPromotores() !!!
No ciclo de vida do JSF ele chama varias vezes o get e set de objeto!! isso causa um impasse desnecessário na aplicação
[/quote]
Então, por isso ele fica naquele looping lá…onde seria ideal eu carregar a lista então? No construtor do MB?
O primeiro código já testei, não funciona. Vou testar a segunda opção.
Eu acredito que está puxando corrtamente o Promotor pelo ID, mas vou me certificar disso e volto a postar.
Seguinte você NÃO pode ter código DAO no getPromotores() !!!
No ciclo de vida do JSF ele chama varias vezes o get e set de objeto!! isso causa um impasse desnecessário na aplicação
Nenhum desses dois códigos funciona?
em.merge(em.merge(promotor));
ou
produto = em.merge(produto );
produto.setMarca("Samsung");
editado…
cara verifica se o promotor passador nessa linha
promotorDAO.atualizarPromotor(promotor))
está sendo populado com id e dados corretamente[/quote]
Tentei fazer das duas formas e nada.
O Promotor está sendo populador corretamente, traz todos os dados gravados e todas os objetos que estão inseridos nele também.
Cara, esse erro não pode estar ocorrendo por outro motivo?
Olha minha classe Promotor:
package com.modelo.bean;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Temporal;
@Entity
public class Promotor extends Usuario {
@Column(length = 60, nullable = false)
private String razaoSocial;
@Column(length = 60, nullable = false)
private String nomeFantasia;
@Column(length = 14, nullable = false)
private String CNPJ;
private Boolean ativo = false;
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
@Column(updatable = false, nullable = false)
private Date dataCriacao;
public String getCNPJ() {
return CNPJ;
}
public void setCNPJ(String CNPJ) {
this.CNPJ = CNPJ;
}
public Boolean getAtivo() {
return ativo;
}
public void setAtivo(Boolean ativo) {
this.ativo = ativo;
}
public String getNomeFantasia() {
return nomeFantasia;
}
public void setNomeFantasia(String nomeFantasia) {
this.nomeFantasia = nomeFantasia;
}
public String getRazaoSocial() {
return razaoSocial;
}
public void setRazaoSocial(String razaoSocial) {
this.razaoSocial = razaoSocial;
}
public GrupoAcesso getGrupoAcesso() {
return grupoAcesso;
}
public void setGrupoAcesso(GrupoAcesso grupoAcesso) {
this.grupoAcesso = grupoAcesso;
}
public Date getDataCriacao() {
return dataCriacao;
}
public void setDataCriacao(Date dataCriacao) {
this.dataCriacao = dataCriacao;
}
// Regras de negócio
public void registrarDataCriacao() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
dataCriacao = new Date();
df.format(dataCriacao);
this.setDataCriacao(dataCriacao);
}
}