DAO genérico em classes que precisam tambem de métodos "especializados" ? Melhor abordagem?

Bom dia pessoal,

Faz um certo tempo que leio em vários lugares para sempre programar orientado a interfaces, evitar replicação de código, sempre que possível usar composição/herança (adequadamente é claro).

Enfim após ler todas essas discussões sobre boas práticas e tentar aplicar durante minha codificação, sempre fiquei com uma dúvida, explico.

Digamos que eu tenha uma Classe DaoGenerica que tem as operações básicas de um CRUD.
Isto posto, possuo tambem uma classe DaoPessoa que extende a classe DaoGenerica entretanto alem das operações básicas de CRUD eu desejo realizar outras operações que fogem do CRUD, por exemplo, eu desejo realizar uma consulta que me retornara um relatório X, mas tambem quero realizar uma consulta que me retorna um relatório Y e outra por sua vez retorne um relatório Z. Além disso eu gostaria de poder buscar a Pessoa por apenas por código ou nome, ou sobrenome. Gostaria de buscar todas as pessoas com mais de 50 anos ou com menos de 20.

Ou seja, quando as operações que eu desejo realizar no banco fogem das oferecidas por uma DAO tão generica ao ponto de poder ser herdadas por várias DAO especificadas qual é a abordagem mais adequada ?

  • Extender a DAO genérica e implementar uma interface X com meus métodos especificos declarados ? Mas nesse caso eu perco a flexibilidade de programação orientada a interface
  • Utilizar de composição dentro da minha Dao especifica ? Ainda assim perco a vantagem do polimorfismo e programação orientada a interface

Enfim, gostaria de saber a opinião de vocês.

Agradeço a todos que contribuirem para o tópico.

Criar uma classe “DAOGenerica” é uma aberração.

Hoje você tem EntityManager. Para listas personalizadas voce pode criar repositorios.

Normalmente, mesmo o DAO generico possui uma interface.
Então teriamos algo assim:

[code]public interface GenericDAO <T, PK> {
// crud
}

public abstract class GenericDAOImpl <T, PK> {
// crud
}

public interface PersonDAO <PersonVO, Long> extends GenericDAO {
// new methods, if any
}

public class PersonDAOImpl <PersonVO, Long> extends GenericDAOImpl implements PersonDAO {
// new methods, if any
}[/code]

[quote]Criar uma classe “DAOGenerica” é uma aberração.

Hoje você tem EntityManager. Para listas personalizadas voce pode criar repositorios.[/quote]

LPorFavor:
Seja mais claro , oque isso traz de beneficios? , e como funciona ?
… tbm fiquei interessado …

Att
Mauricio Carvalho

[quote=mausexdd][quote]Criar uma classe “DAOGenerica” é uma aberração.

Hoje você tem EntityManager. Para listas personalizadas voce pode criar repositorios.[/quote]

LPorFavor:
Seja mais claro , oque isso traz de beneficios? , e como funciona ?
… tbm fiquei interessado …

Att
Mauricio Carvalho[/quote]

Voce não precisa mais criar “DAOs”, isso cheira legado. Pra que criar um DAO Generico?? EntityManager nao faz isso.


//Basta injetar
@PersistenceContext
EntityManager em;

//----

em.persist(SuaClasse.class, objeto);
em.find(SuaClasse.class, 12);
em.merge(SuaClasse.class, objeto);
em.remove(objeto);

Para metodos especificos geralmente utiliza Repositorios:


public class ClienteRepository


public Collection clientesPorIdade//...
public Collection clientesPorNome//...

Voce pode injetar EntityManager no seu repositorio e fazer query usando JPQL ou Criteria(eu prefiro).

Eu junto tudo em Stateless Session Bean como serviço:


@LocalBean //ou implemente interface Local X Remota
public class ClienteServiceBean{

   @PersistenceContext
   private EntityMangaer em;
   @Inject
   private ClienteRepository repository // Voce pode injetar o seu repositorio (tornado-o Container-Managed,claro)


   //Aqui voce pode por uma seria de metodos genericos ou especificos, oriundo do EntityManager ou Repositorio

}

agora voce pode usar os seus serviços oferecidos por EJB onde quiser basta injetar o EJB com @EJB em Servlet ou ManagedBean do JSF (Não é recomendado utilizar o lixo de JSF):


@EJB private ClienteServiceBean service;

Caso voce utilize componentes não gerenciado pelo container pode buscar o seu EJB com simples Lookup JNDI. Lembrando que dessa forma, voce trabalha boas praticas como Injeção, Pool de Conexao gerenciado pelo container, Pool de Beans gerenciado, Segurança, tudo por conta do container.

Ou seja, voce nao precisa ficar codificando e reinventando a roda. Voce codifica menos e fica menos suscetível a bugs.

Caramba , muito legal , nem sabia que dava para fazer assim…
voce sabe algum tutorial? que cria um crud por exemplo desta maneira , para que fique mais clara a implementação destes repositorios e etc…

se tiver manda o link ai … flw :smiley:

[quote=mausexdd][quote]Criar uma classe “DAOGenerica” é uma aberração.

Hoje você tem EntityManager. Para listas personalizadas voce pode criar repositorios.[/quote]

LPorFavor:
Seja mais claro , oque isso traz de beneficios? , e como funciona ?
… tbm fiquei interessado …

Att
Mauricio Carvalho[/quote]

numa boa… dao ou repository… é praticamente a mesma coisa, por isso inclusive tem gente (e aparentemente não sou poucos) que vão implementar isso e criam uma interface como “ClienteRepository”, por exemplo e na implementação implementam isso em um “ClienteDao” por exemplo…

não vejo nada de aberração em um dao genérico, poderiamos ter alguns exemplos com criteria do que se poderia colocar num generic dao, um exemplo que eu acho o mais válido ao menos dentro desse grupo da api criteria seria para usar a a interface Example do hibernate:

[code]public static List getAllByExample(Session s, Object example, boolean enableLike){
	
	Criteria c = s.createCriteria(example.getClass());
	if (enableLike)
		return c.add(Example.create(example).enableLike(MatchMode.ANYWHERE)).list();
	else
		return c.add(Example.create(example)).list();
	
}[/code]

alias também quando se fica colocando repository, dao, ao o cara ainda fica criando um monte de interface/classes com sufixo<escolha seu padrão aqui>, n camadas… a maioria das aplicações não tem um nível de complexidade que que te faça ganhar tempo em fazer isso tudo (alias me arrisco a dizer que na maioria dos casos você vai é perder montando um canhão se você só precisa matar uma formiga, e essa formiga normalmente precisa estar morta pra ontem).

não vejo nada de errado em abordagens assim, será que alguém poderia explicar o por que disso ser errado desse jeito?

Realmente, é uma questão de opção.
E não existe muitos prós e contras entre uma implementação e outra.

Boa noite a todos.

Também não vejo nada de aberração ou errado em você montar um DAO genérico.

Pra dizer a verdade, estou montando um DAO genérico aqui, e creio eu que não precisará nem criar classes de entidade de dados, entity managers, beans e tudo mais, o que apenas fiz é criar uma instrução SQL que só me retorne o MetaData da tabela do banco para dentro do ResultSet, depois e só preencher Map com o nome do campo e o seu valor, e isto, é claro, dependendo do banco de dados que voce está usando, a sintaxe SQL varia de banco para banco.

Como eu uso Postgres, a sintaxe pode ser de duas formas:

    SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'usuario';

    // ou
    SELECT * FROM usuario WHERE 1=0

A primeira opção ler uma tabela de configuração do schema (Esquema), onde armazena todas as estruturas de todas as tabelas do banco, já a segunda opção tenta apanhar os registros diretamente da tabela, onde um select com um critério de condição false, não trará nenhum registro, porém, carregará o metadata da tabela no objeto ResultSet, toda vez que voce realizar qualquer pesquisa com a sintaxe select esta sempre carregará o metadata da tabela no ResultSet.

A partir dai, eu construo as instruções SQLs com os nomes dos campos provenientes do metadata que acabou de ser carregado.

Para que esse sistema funcione, estou construindo quatro classes, a saber:

1º) A classe Formatter é responsável pela formatação de alguns valores de campos.

2º) A classe Query é responsável por apanhar dados do ResultSet e enviar dados a banco, também possui uma padronização pessoal para parâmetros que utilizam os caracteres "<" e ">" com os valores entre eles.

3º) A classe de conexão com o banco.

4º) E a classe DAOFactory responsável pela criação das sintaxes SQL através do metadata da tabela.

Funcionará mais ou menos assim:

    ......
    DAOFactory daousu = new DAOFactory(&quot;usuario&quot;);
    // Mapeando valores e passando ao DAOFactory.
    daousu.getValuesMap().put(&quot;login&quot;, txtLogin.getText());
    daousu.select();

O método getValusMap() do DAOFactory é implementado desta maneira:

   private Map&lt;String,Object&gt; valuesmap;
   .....
   .....
   .....
   public Map&lt;String,Object&gt; getValuesMap() {
        if (valuesmap == null) valuesmap = new HashMap&lt;String,Object&gt;();
        return valuesmap;
    }

O sistema está ainda em fase de testes, e espero que funcione, pois assim que implementá-lo, em uma aplicação desktop e também web, com certeza, não vai precisar criar tantos beans, daos e entity manages da vida, e o framework já fica prontinho.

Cara, Dao se encaixa melhor se for seguido como padrão de classe Abstrata do que Interface, tendo em vista que existem muitas particularidades de Dao para Dao.
A não ser que seja Dao de crud só com insert/update/delete.
Vá por mim, você não vai querer escrever todos os tipos de métodos para consultar passando args[] como parâmetros (é dor de cabeça na certa). Cansei de fazer isso. Hoje eu utilizo abstract class pra Dao.