Solucionado (ver solução)
Solucionado
(ver solução)
21
respostas

duvida com o toMany e ManyToMany

Bom dia, fiz os cursos de jsf, e só vi a anotação OneToOne, tava estudando para minhas provas, e agora voltei a estudar aqui na alura, e tenho uma duvida, tenho um projeto que vai ter um campo OneToMany, sempre usava oneToOne, vou criar um codigo aqui, que não é a minha duvida, más ira servir como, por exemplo tenho minha classe cliente e endereço. E um cliente pode ter mais de 1 endereco ficando mais ou menos assim...

Classe Cliente


@Entity
@Table(name = "cliente")
public class Cliente implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long codio;
    private String nome;
    private String tipoDePessoa;
    private String cpf;
    private String cnpj;
    private String celular;
    private String email;
    @OneToMany(mappedBy = "cliente")
    private List<Endereco> enderecos = new ArrayList<Endereco>();

    public Long getCodio() {
        return codio;
    }
    public void setCodio(Long codio) {
        this.codio = codio;
    }
    public String getNome() {
        return nome;
    }
    public void setNome(String nome) {
        this.nome = nome;
    }
    public String getTipoDePessoa() {
        return tipoDePessoa;
    }
    public void setTipoDePessoa(String tipoDePessoa) {
        this.tipoDePessoa = tipoDePessoa;
    }
    public String getCpf() {
        return cpf;
    }
    public void setCpf(String cpf) {
        this.cpf = cpf;
    }
    public String getCnpj() {
        return cnpj;
    }
    public void setCnpj(String cnpj) {
        this.cnpj = cnpj;
    }
    public String getCelular() {
        return celular;
    }
    public void setCelular(String celular) {
        this.celular = celular;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public List<Endereco> getEnderecos() {
        return enderecos;
    }
    public void setEnderecos(List<Endereco> enderecos) {
        this.enderecos = enderecos;
    }
}

Classe Endereco

@Entity
@Table(name = "endereco")
public class Endereco implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long codigo;
    private String cidade;
    private String bairro;
    private Integer numeroCasa;

    public Long getCodigo() {
        return codigo;
    }
    public void setCodigo(Long codigo) {
        this.codigo = codigo;
    }
    public String getCidade() {
        return cidade;
    }
    public void setCidade(String cidade) {
        this.cidade = cidade;
    }
    public String getBairro() {
        return bairro;
    }
    public void setBairro(String bairro) {
        this.bairro = bairro;
    }
    public Integer getNumeroCasa() {
        return numeroCasa;
    }
    public void setNumeroCasa(Integer numeroCasa) {
        this.numeroCasa = numeroCasa;
    }
}

Está correto a minha classe assim? Depois por exemplo irei adicionar. Iria eu ter algo parecido com isso? Na hora que eu clico em adicionar me retorna um erro. minha classe java bean está assim...

@ManagedBean(name = "clienteBean")
@ViewScoped
public class ClienteBean implements Serializable{



    private static final long serialVersionUID = 1L;

    private Cliente cliente = new Cliente();
    private Endereco endereco = new Endereco();
    private List<Endereco> enderecos = new ArrayList<Endereco>();

    public void salvar() {
        enderecos.add(endereco);
        new EnderecoDAO().adicionar(endereco);
        new ClienteDAO().adicionar(cliente);
        new Mensagem().mensagemInfo("Cliente adicionado com sucesso");
        this.cliente = new Cliente();
        this.endereco = new Endereco();
    }

Oque está errado?

21 respostas

Faltou vc adicionar o atributo cliente na sua classe endereço e anotar com ManyToOne :). Aí vai estar de boa.

Alberto, porque com uma anotação OneToOne só é preciso adicionar um atributo? por exemplo o teste que eu dei encima, se fosse OneToOne não precisaria adicionar um atributo cliente na minha classe Endereco ne? porque com a OneToMany é preciso? Então na minha classe oque falta é algo parecido com isso?

@Entity
@Table(name = "endereco")
public class Endereco implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long codigo;
    private String cidade;
    private String bairro;
    private Integer numeroCasa;
   @ManyToOne(mappedBy = "endereco")
private Cliente = new Cliente();    // algo assim?

Eh uma boa pergunta.. vc não precisa.. se vc colocar um OneToMany, sem mappedBy, o hibernate vai dar.um jeito de ter essa relação no banco.. No caso ele vai criar uma tabela associativa... Como, geralmente, não eh isso que o sistema quer, adicionamos o relacionamento real na outra ponta... Um endereço eh de um cliente, esse eh o relacionamento. Agora, pra ficar fácil de navegar, fazemos o OneToMany, só pra nao fazer a query.

Alberto então quando tiver uma anotaçao manyToMany a mesma coisa então? ira ser preciso criar um atributo em cada classe? E quando não colocamos as anotações sem o mappedBy, o hibernate cria automaticamente uma associativa? Então é sempre uma boa escolha em usar o mapped?

O ManyToMany vai depender, ele vai criar associativa de todo jeito... Vc pode, ou não, ter o bidirecional.. Mesma coisa vale pra OneToMany. Só que nessa última, quase sempre, vc quer o ManyToOne.

Alberto entendi perfeitamente, muito obrigado... Só que na hora de adicionar, esta ocorreundo um erro de transient...

ADVERTÊNCIA: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
javax.el.ELException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
    at org.apache.el.parser.AstValue.invoke(AstValue.java:292)
    at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:273)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:814)
    at javax.faces.component.UICommand.broadcast(UICommand.java:300)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    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:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:871)
    at br.com.bercalini.oficina.dao.EnderecoDAO.adicionar(EnderecoDAO.java:14)
    at br.com.bercalini.oficina.bean.ClienteBean.salvar(ClienteBean.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.el.parser.AstValue.invoke(AstValue.java:279)
    ... 31 more
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:818)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:822)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865)
    ... 38 more

dez 05, 2016 12:24:50 PM com.sun.faces.context.AjaxExceptionHandlerImpl handlePartialResponseError
GRAVE: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:871)
    at br.com.bercalini.oficina.dao.EnderecoDAO.adicionar(EnderecoDAO.java:14)
    at br.com.bercalini.oficina.bean.ClienteBean.salvar(ClienteBean.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.el.parser.AstValue.invoke(AstValue.java:279)
    at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:273)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:814)
    at javax.faces.component.UICommand.broadcast(UICommand.java:300)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    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:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Endereco
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:818)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:822)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865)
    ... 38 more

classe bean


    private static final long serialVersionUID = 1L;

    private Cliente cliente = new Cliente();
    private Endereco endereco = new Endereco();
    private List<Endereco> enderecos = new ArrayList<Endereco>();

    public void salvar() {
        enderecos.add(endereco);
        new EnderecoDAO().adicionar(endereco);
        new ClienteDAO().adicionar(cliente);
        new Mensagem().mensagemInfo("Cliente adicionado com sucesso");
        this.cliente = new Cliente();
        this.endereco = new Endereco();
    }

Consegui colocando a anotação assim...

@ManyToOne(cascade = CascadeType.PERSIST)
    private Cliente cliente = new Cliente();

Mas está adicionando um cliente em branco e um com os campos que digitei... olha o select que ele retorna, não queria adicionar esse cliente e branco, como fazer para tirar? Olha o hibernate

Hibernate: insert into cliente (celular, cnpj, cpf, email, nome, tipoDePessoa) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into endereco (bairro, cidade, cliente_codio, numeroCasa) values (?, ?, ?, ?)
Hibernate: insert into cliente (celular, cnpj, cpf, email, nome, tipoDePessoa) values (?, ?, ?, ?, ?, ?)

Vc primeiro precisa adicionar o cliente... Aí vc adiciona cada endereço associado com ele. Nem.precisa adicionar na lista de endereços do cliente.

Alberto fiz conforme você falo ficando assim.

    public void salvar() {
        new ClienteDAO().adicionar(cliente);
        new EnderecoDAO().adicionar(endereco);
        new Mensagem().mensagemInfo("Cliente adicionado com sucesso");
        this.cliente = new Cliente();
        this.endereco = new Endereco();
    }

mais ocorre, o mesmo problema, o problema ta na minha anotação.

@ManyToOne(cascade = CascadeType.ALL)
    private Cliente cliente = new Cliente();

Oque poderia usar pra sumir esse "erro"

Vc tem que passar o cliente salvo para o endereço.

Alberto poderia me dar o exemplo? ;( porque passei o meu cliente para o endereço e me da outro erro... poderia me mostrar como fazer essa parte de adicionar? porque não consegui...

pega o cliente que foi passado para o dao e faz endereço.setCliente(cliente); Não precisa manipular a lista de endereços do cliente.

pois é alberto fiz isso e me retorno o seguinte erro ;(

    public void salvar() {
        new ClienteDAO().adicionar(cliente);
        endereco.setCliente(cliente);
        new EnderecoDAO().adicionar(endereco);
        new Mensagem().mensagemInfo("Cliente adicionado com sucesso");
        this.cliente = new Cliente();
        this.endereco = new Endereco();
    }

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bercalini.oficina.modelo.Cliente at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:834) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:827) at org.hibernate.engine.spi.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:52) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:383) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:126) at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:818) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:822) at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865) ... 38 more

O seu dao abre e fecha uma transação? Se for, tem.boas chances de ser isso. Os dois precisam estar dentro da mesma transação.

meus daos...

public class ClienteDAO {

    private EntityManager em = new JPAUtil().geEntityManager();

    public void adicionar(Cliente cliente) {
        em.getTransaction().begin();
        em.persist(cliente);
        em.getTransaction().commit();
        em.close();
    }
    public void adicionar(Endereco endereco) {
        EntityManager em = new JPAUtil().geEntityManager();
        em.getTransaction().begin();
        em.persist(endereco);
        em.getTransaction().commit();
        em.close();
    }

Foi o que eu falei.. a operação precisa estar numa transação só.

Alberto acho que to comecando a enteder... pois quando a anotação é oneToOne do jeito que eu fiz ali encima funcionava...

Alberto teria outra forma de fazer isso sem ser dessa maneira?

    public void adicionar(Cliente cliente, Endereco endereco) {
        em.getTransaction().begin();
        em.persist(cliente);
        em.persist(endereco);
        em.getTransaction().commit();
        em.close();
    }

Ficou assim, você acha que esta em um caminho certo?...

    public void salvar() {
        endereco.setCliente(cliente);

        new ClienteDAO().adicionar(cliente,endereco);
        new Mensagem().mensagemInfo("Cliente adicionado com sucesso");
        this.cliente = new Cliente();
        this.endereco = new Endereco();
    }

e meu dao fico bom assim? é dessa forma mesmo que adiciona?

public class ClienteDAO {

    private EntityManager em = new JPAUtil().geEntityManager();

    public void adicionar(Cliente cliente, Endereco endereco) {
        em.getTransaction().begin();
        em.persist(cliente);
        em.persist(endereco);
        em.getTransaction().commit();
        em.close();
    }

}

desde ja obrigado mano pela sua paciencia e ajuda!! Estou começando ainda e tenho varias duvidas... Espero que nao ligue pra essas duvidas e erros de principiantes :(

solução!

Opa, fique a vontade para perguntar tudo que tiver dúvida :). Acho que vc seguiu um caminho ok sim, para este momento :). O seu próximo passo é tirar o controle transacional de dentro dos seus daos... pq este tipo de situação vai acontecer com frequência nos seus projetos :).

De todo jeito, é isso aí! Tem que ir tentando, porque dessa forma vc vai consolidando o que está aprendendo :).

Obrigado alberto. mais uma vez vou marcar como resolvido.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software