@Entity
public class Coisa implements Serializable {
@id
private int id:
private String descricao;
...
DaoGenerico.java
public interface DaoGenerico<T, ID extends Serializable> {
public Class<T> getObjectClass();
public T crud(T object);
}
DaoGenericoImpl.java
public class DaoGenericoImpl<T, ID extends Serializable> implements DaoGenerico<T, ID> {
@PersistenceContext
private EntityManager em;
private final Class<T> oClass;
public DaoGenericoImpl() {
oClass = (Class<T>) ( (ParameterizedType) getClass().getGenericSuperclass() ).getActualTypeArguments()[0];
}
public T crud(T object) {
em.crud();
}
SessionBean.java
Nao vou colocar a interface para nao alongar, ok?
@Stateless
public class SessionBean implements SessionRemote {
public DaoGenerico<T, ID> getDaoGenerico() {
return new DaoGenericoImpl<T, ID>();
}
Isso seria o pacote do modelo da aplicacao. A visao seria outro pacote que poderia ser swing ou web e o controle estaria nesses dois pacotes. Esse modelo é valido?
Fico grato pelos comentarios
Thiago Moreno
Por que não evitar os DAOs e injetar o EntityManager diretamente no EJB? Perceba que seus DAOs estão simplesmente delegando métodos que já existem no EntityManager; será que há necessidade de utilizá-lo?
Era justamente essa discussao que eu gostaria de ter. Pois aqui no forum existem inumeras opinioes. Por isso coloquei o topico com o modelo utilizado. No caso o DaoGenerico seria o SessionRemote e o DaoGenericoImpl seria o SessionBean. E a melhor pratica?
Exatamente, pra que utilizar o DAO sendo que o JPA iria realizar um papel muito melhor e com o mínimo de acoplamento com as camadas adjacentes.
Feiz Ano Novo.
Acredito que em algumas situações vale a pena usar o DAO para adicionar um pré-/pós-processamento, por exemplo quando você tem como requisito gravar uma tabela de histórico de operações. Agora adicionar esse nível extra porque “pode ser que apareça um requisito assim” eu já acho que não vale a pena.
Acredito que não seria função de um DAO gravar históricos de dados. :?
Na verdade, a necessidade de se gravar um histórico estaria mais relacionado ao domínio do que a camada de persistencia.
Depois que eu fiz o topico apliquei um EJB como DaoGenerico apenas acrescentando a anotacao @Stateless ao Dao. O Deploy funcionou porem ao tentar recuperar o Dao usando lookup um void static main(…) ele esta dando createexception. O mesmo codigo sem ser generico nao da problema. Alguem tem alguma ideia ou teve algum problema com implementacao parecida?
@Remote
public interface DaoGenerico<T, ID extends Serializable> {
public Class<T> getObjectClass();
public T crud(T object);
}
@Stateless
public class DaoGenericoImpl<T, ID extends Serializable> implements DaoGenerico<T, ID> {
@PersistenceContext
private EntityManager em;
private final Class<T> oClass;
public DaoGenericoImpl() {
oClass = (Class<T>) ( (ParameterizedType) getClass().getGenericSuperclass() ).getActualTypeArguments()[0];
}
public T crud(T object) {
em.crud();
}
Não, o DAO não deve ser o session bean. Um DAO cuida apenas de persistência; seu session bean pode ter que realizar outras operações além da persistência de dados.
Como exemplo, suponha que você possui um cadastro onde um e-mail deva ser enviado após a realização da operação. O session bean persistiria o objeto envolvido através do EntityManager, e logo após chamaria uma classe de infra-estrutura para enviar o e-mail. Como não é tarefa do DAO enviar o e-mail, seu session bean não deve ser um DAO.
Resumindo, a refatoração necessária consiste em trocar as chamadas a DAOs por chamadas diretas à uma instância do EntityManager, e não fazer dos DAOs session beans.
É sempre uma discussão polêmica, nos tempos de EJB3, se se deve utilizar DAO ou não. Porém, usar um método de Session Facade que retorna um DAO (genérico ou não) não é recomendável. Motivo: é de responsabilidade do Facade, ocultar certos detalhes de implementação, e retornar o meio de acesso (DAO) vai contra isso.
Caso fizesse um DAO genérico, não faça isso:
@Stateless
public class SessionBean implements SessionRemote {
public DaoGenerico<T, ID> getDaoGenerico() {
return new DaoGenericoImpl<T, ID>();
}
Faça isso direto, mais simples e com o mesmo efeito:
@Stateless
public class DaoGenericoImpl implements DaoGenericoSessionLocal {
// métodos CRUD
}
A única desvantagem é que não dá pra usar generics, mas acho aceitável.
Repare que a interface é local. Pense assim: tenho um ear com alguns façades, onde os de negócio serão expostos como interface remota (estará sendo acessível ao mundo externo). Agora os façades utilitários ou de persistência (como o nosso DAO) serão locais, para que o mundo externo não tenha conhecimento de implementação.
Não acredito que objetos da camada de persistência não possa utilizar a mesma tecnologia da camada de negócio. Portanto, usaria EJB para fazer DAOs tranquilamente.
Existem alguns casos onde o serviço de negócio é apenas a execução de uma query, onde não vejo a necessidade de se criar uma classe separada de DAO. Porém, é comum haver uma maior interação com o banco e outras entidade externas num mesmo serviço de negócio, aí separar esses pedaços em DAO faz sentido.