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

@PersistenceContext em classe Genérica

Criar uma classe DAO genérica com o @PersistenceContext é uma boa prática, ou o ideal é que cada classe EJB tenha o seu @PersistenceContext

Ex:

public abstract class DAO implements Serializable {

    @PersistenceContext
    private EntityManager em;

    public EntityManager getEm() {
        return em;
    }

    public <T> T carregar(Object key, Class<T> clazz) {
        return em.find(clazz, key);
    }

    public <T> void salvar(T entity) {
        em.persist(entity);
    }

    public <T> void alterar(T entity) {
        em.merge(entity);
    }

    public <T> void excluir(T entity) {
        em.remove(entity);
    }

    protected Query criarQuery(String query) {
        return em.createQuery(query);
    }

    protected Query criarQueryNativa(String query, Object key) {
        return em.createNativeQuery(query);
    }
}


public class PessoaFisicaDAO extends DAO {

    public PessoaFisica existeCPF(String cpf, Integer pessoaId) {
        String query = "SELECT p FROM PessoaFisica p WHERE p.cpf = '" + cpf + "'";
        Query q = criarQuery(query);
        List list = q.getResultList();
        if (list.size() > 0) {
            return (PessoaFisica) list.get(0);
        } else {
            return null;
        }
    }

}

@Stateless
public class PessoaFisicaService {

    @Inject
    private PessoaFisicaDAO dao;

    public void salvar(Pessoa pessoa) throws ValidacaoException {
            dao.salvar(pessoaFisica);
    }


}
5 respostas

Oi Jadir,

acho que a questão é um pouco mais complexo do que vc imagina :)

Primeiramente, o EntityManager sempre será injetado ao usar em EJB Stateless. Normalmente isso significa, quando vc chama algum método do EJB Stateless, o container já fornece um novo EntityManager. O EntityManager vive menos tempo do um EJB Statless.

Agora vc está usando EJB com CDI e aquele DAO (PessoaFisicaDAO) nem é um EJB Stateless. Eu diria que esse EntityManager injetado no DAO é administrado pelo CDI e tem o seu próprio ciclo da vida. Seria interessante testar isso, imprimindo a referencia do EntityManager nesse DAO e fazer algumas chamadas.

Além dessa questão do CDI x EJB há uma questão de design. Você está usando Herança para criar um DAO genérico. Parece interessante pois vc consegue reutilizar esses métodos genéricos em todos os filhos (carregar, salvar, excluir etc).

No entanto, imagina que no seu sistema não deveria ser possível excluir uma Pessoas que já foi cadastrada. Esse seuPessoaFisicaDAO sempre terá o método excluir, ou seja terá essa funcionalidade indesejada. Nesse caso herança não te ajuda e sim atrapalha. Aconselho usar a composição nesse caso. Ok?

abs

Então seria interessante eu não utilizar o DAO? E utilizar um Service genérico que conteria (carregar, salvar, excluir etc), que poderia ser por exemplo um AbstractFacade e os Services estendendo dessa classe conforme exemplo abaixo:

public abstract class AbstractFacade<T> {
    private Class<T> entityClass;

    @PersistenceContext
    private EntityManager entityManager;

    protected EntityManager getEntityManager() {
        return entityManager;
    }

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
      getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager()
                .getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }


@Stateless
public class PessoaFisicaService extends AbstractFacade<PessoaFisica> {

    public PessoaFisicaService() {
        super(PessoaFisica.class);
    }

public PessoaFisica existeCPF(String cpf, Integer pessoaId) {
        String query = "SELECT p FROM PessoaFisica p WHERE p.cpf = '" + cpf + "'";
        Query q = criarQuery(query);
        List list = q.getResultList();
        if (list.size() > 0) {
            return (PessoaFisica) list.get(0);
        } else {
            return null;
        }
    }

}

Poderia ser assim?

Estou em busca de uma arquitetura que fosse eficiente e que obedecesse as boas práticas. Obrigado pela paciência

Oi Jadir,

agora o EntityManager está sendo administrado pelo EJB, no entanto a classe AbstractFacade continua sendo um Dao genérico, só o nome mudou :) A ideia era não usar herança e sim composição.

Abs

Oi Nico,

Então nesse caso só existira a presença das classes services? assim:


@Stateless
public class PessoaFisicaService  {

@PersistenceContext
private EntityManager entityManager;

public void salva(PessoaFisica pessoaFisica) {
        entityManager.persist(pessoaFisica);
}

public void editar(PessoaFisica pessoaFisica) {
        entityManager.merge(pessoaFisica);
}


public PessoaFisica existeCPF(String cpf, Integer pessoaId) {
        String query = "SELECT p FROM PessoaFisica p WHERE p.cpf = '" + cpf + "'";
        Query q = entityManager.createQuery(query);
        List list = q.getResultList();
        if (list.size() > 0) {
            return (PessoaFisica) list.get(0);
        } else {
            return null;
        }
    }

}

Ou seja usaria essa estrutura em todos os meus services, sempre com composição. Desta forma como você disse, caso fosse um requisito do sistema não poder excluir pessoa, basa que o service correspondente não contemplasse o código de exclusão.

Pretendo adotar isso no meu próximo projeto utilizando EJB3 Posso seguir esse caminho?

solução!

Oi Jadir,

pode fazer dessa maneira ou continuar com a ideia do Dao:

@Stateless
public class PessoaFisicaService  {

  @PersistenceContext
  EntityManager entityManager;

  PessoaFisicaDao dao;

  @PostConstruct
  void init () {
       this.dao = new PessoaFisicaDao(entityManager);
  }

//metodos que delegam para dao

}

E o Dao:

public class PessoaFisicaDao  {

private EntityManager entityManager;

public PessoaFisicaDao(EntityManager manager) {
   this.manager = manager;
}

//método que usam o EntityManager

}

Repare que o Dao não é um EJB.

abs