Estou passando por um problema, provavelmente de design, e gostaria de alguma sugestão. Estou implementando um sistema utilizando JPA e EJB3, até aí tudo bem, vou ter diversas classes que serão persistidas em banco através do uso de JPA. Abaixo seguem duas dessas classes, que é onde está o foco do meu problema:
Campanha
package org.it4services.contactprovider.to;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.OneToMany;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import static javax.persistence.FetchType.EAGER;
import static javax.persistence.CascadeType.ALL;
@Entity
public class Campanha implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Integer id;
private String nome;
@OneToMany(mappedBy = "campanha", cascade = ALL)
private List<Tabulacao> tabulacaoList = new ArrayList<Tabulacao>();
@ManyToMany(fetch=EAGER)
@JoinTable(inverseJoinColumns = @JoinColumn(name="id_usuario", referencedColumnName = "id"), joinColumns = @JoinColumn(name="id_campanha", referencedColumnName = "id"))
private List<Usuario> usuarioList = new ArrayList<Usuario>();
private Boolean ativo;
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;
}
public List<Tabulacao> getTabulacaoList() {
return tabulacaoList;
}
public void setTabulacaoList(List<Tabulacao> tabulacaoList) {
this.tabulacaoList = tabulacaoList;
}
public List<Usuario> getUsuarioList() {
return usuarioList;
}
public void setUsuarioList(List<Usuario> usuarioList) {
this.usuarioList = usuarioList;
}
public Boolean getAtivo() {
return ativo;
}
public void setAtivo(Boolean ativo) {
this.ativo = ativo;
}
public String toString() {
return nome;
}
}
Tabulação
package org.it4services.contactprovider.to;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import org.it4services.contactprovider.type.TipoTabulacao;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
@Entity
public class Tabulacao implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Integer id;
@ManyToOne
@JoinColumn(name="id_campanha", referencedColumnName = "id")
private Campanha campanha = new Campanha();
@ManyToOne
@JoinColumn(name="id_status", referencedColumnName = "id")
private Status status = new Status();
@Column(name="tipo_tabulacao")
private TipoTabulacao tipoTabulacao = TipoTabulacao.COMUM;
@Column(name="tempo_agendamento_automatico")
private Integer tempoAgendamentoAutomatico;
private Boolean visivel;
private Boolean ativo;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setCampanha(Campanha campanha) {
this.campanha = campanha;
}
public Campanha getCampanha() {
return campanha;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public TipoTabulacao getTipoTabulacao() {
return tipoTabulacao;
}
public void setTipoTabulacao(TipoTabulacao tipoTabulacao) {
this.tipoTabulacao = tipoTabulacao;
}
public Integer getTempoAgendamentoAutomatico() {
return tempoAgendamentoAutomatico;
}
public void setTempoAgendamentoAutomatico(Integer tempoAgendamentoAutomatico) {
this.tempoAgendamentoAutomatico = tempoAgendamentoAutomatico;
}
public Boolean getVisivel() {
return visivel;
}
public void setVisivel(Boolean visivel) {
this.visivel = visivel;
}
public Boolean getAtivo() {
return ativo;
}
public void setAtivo(Boolean ativo) {
this.ativo = ativo;
}
}
Uma campanha possui N tabulações.
Para a implementação dos EJB’s, eu criei uma interface base:
BaseSessionFacade
package org.it4services.contactprovider.service.facade;
import java.util.List;
public interface BaseSessionFacade <E, I> {
public List<E> getAll();
public E getByID(I id);
public void save(E entity);
public void delete(E entity);
}
… e uma interfece para tratar de cada uma das minhas entidades persistentes:
CampanhaSessionFacade
package org.it4services.contactprovider.service.facade;
import javax.ejb.Local;
import org.it4services.contactprovider.to.Campanha;
@Local
public interface CampanhaSessionFacade extends BaseSessionFacade<Campanha, Integer> {
}
TabulacaoSessionFacade
package org.it4services.contactprovider.service.facade;
import javax.ejb.Local;
import org.it4services.contactprovider.to.Tabulacao;
@Local
public interface TabulacaoSessionFacade extends BaseSessionFacade<Tabulacao, Integer> {
}
… seguem as implementações dessas duas interfaces:
CampanhaSessionFacadeImpl
package org.it4services.contactprovider.service;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.it4services.contactprovider.service.facade.CampanhaSessionFacade;
import org.it4services.contactprovider.to.Campanha;
@Stateless
public class CampanhaSessionFacadeImpl implements CampanhaSessionFacade {
@PersistenceContext(unitName = "ContactProviderJPA")
private EntityManager entityManager;
@SuppressWarnings("unchecked")
public List<Campanha> getAll() {
return entityManager.createQuery("from Campanha c").getResultList();
}
public Campanha getByID(Integer id) {
return null;
}
public void save(Campanha campanha) {
entityManager.persist(campanha);
}
public void delete(Campanha campanha) {
entityManager.remove(campanha);
}
}
TabulacaoSessionFacadeImpl
package org.it4services.contactprovider.service;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.it4services.contactprovider.service.facade.TabulacaoSessionFacade;
import org.it4services.contactprovider.to.Tabulacao;
@Stateless
public class TabulacaoSessionFacadeImpl implements TabulacaoSessionFacade {
@PersistenceContext(unitName = "ContactProviderJPA")
private EntityManager entityManager;
@SuppressWarnings("unchecked")
public List<Tabulacao> getAll() {
return entityManager.createQuery("from Campanha c").getResultList();
}
public Tabulacao getByID(Integer id) {
return null;
}
public void save(Tabulacao tabulacao) {
entityManager.persist(tabulacao);
}
public void delete(Tabulacao tabulacao) {
entityManager.remove(tabulacao);
}
}
… o meu grande problema está sendo o seguinde, quando executo o método getAll() através de um ManagedBean para listar as campanhas na minha página, é disparada a seguinte exceção:
javax.servlet.ServletException: failed to lazily initialize a collection of role: org.it4services.contactprovider.to.Campanha.tabulacaoList, no session or session was closed
Minha dúvida é a seguinte:
Isso ocorre porque meu EJB que cuida da persistência da Campanha não é o mesmo que cuida da persistência da Tabulação? Eu teria que colocar todos os métodos das entidades que possuem um forte relacionamento entre si num mesmo EJB para que “compartilhem a mesma sessão”, isso se o q estou dizendo tem alguma procedência… como poderia resolver isso?
Como vocês podem ver estou meio perdido e confuso. Por favor me ajudem.
Valeu!!!