Criterio em DAO

Definitivamnete, sim. Dizem que a versão em Português é ruim, tente a original :wink:

Eu acho que os DAO para serem bem aproveitados devem ser totalmente type-safe, ou seja, DAO com intrefaces genericas somente internamente para automatizar operações, mas a interface externa deve ser toda tipada, sem queries genericas.

Mas em contra-partida eu acho que ele deve ser o mais generico possivel em relacao a suas operacoes.
Acho que o desafio dos DAO é tentar representar as funcionalidades da SQL na linguagem OO aproveitando os recursos type-safe.
Agora colocar métodos relacionados com regras de negócio com DAO é muito estranho.
Já vi exemplos de DAO com métodos gerarFatura, registrarVenda.
Para mim são métodos de lógica de negócio não lógica de dados.

Um modo de interesante de ver os dados é ve-los como repositório de dados, ou melhor, repositório de objetos. Alias já vi autores que preferem esta denominação (Repositorio).

Como vocês geralmente implementam isto ?
A separação da lógica de dados da lógica de negócios.

Gostaria da opinião de vocês.

Eu acho que DAOs são tediosos e não são nenhum desafio.

Costumo agrupar os daos por use cases e entidades, dai é só colocar os métodos que atendam os cenarios que surgir.

jprogrammer, sem lazy loading e com métodos genéricos, você vai ter alguns problemas em aplicações grandes.

Por exemplo, imagina que eu tenho um método

public Usuario buscar(int id)

Que faz o que aprece fazer, traz objetos da base de dados.

Agora imagina que você precisa de uma lista de usuários para o administrador. Se você usar esse me´todo genérico, vai ter que chamá-lo várias vezes. Se o método retornar uma lsita de usuários, você vai ter que retornar toda a lista e filtrar o resultado baseado nos parâmetros que o administrador passar.

Isso pode ser resolvido com um método especializado em recuperar objetos segundo um critério X.

Imagine que o adminsitrador vai poder ver uma ficha resumida dos usuários. Se seu método genérico trouxer todo o grafo de objetos, você vai ter centenas de objetos inúteis em memória.

Se seu método genérico não trouxer os relacionamentos, você vai rpecisar de algo do tipo:

Usuario a = daoUsuarios.buscar(codigo);
GrupodeUsuarios g = daoGrupos.buscar(a.getCodigoGrupo());
...

E acabar piorando.

Sem lazy-loading, fica difícil trabalhar com relacionamentos de maneira genérica.

DAOs devem ser usados em aplicações simples, para casos complexos, tente um framework de verdade, onde você não rpecisa se preocupar com a profundidade ou inutilidade do seu grafo de objetos.

Quanto aos métodos “de negócio”, acredito que esses DAOs citados não estão no que falei sobre métodos específicos. Métodos de pesquisa especializados e não genéricos não processam nada (até podem, por conveniência, mas sem abusos), eles apenas fazem pesquisas no SGBD de acordo com um processo específico.

Estamos lidando com a limitação do modelo relacional e principalmente com o impedance mismatch aqui, não encotnrei até hoje uma solução simples para relacionamentos complexos passados para um SGBD que não envolvesse frameworks, métodos especializados em um DAO, código chamando DAOs o tempo todo ou implementações grosseiras de proxies :frowning:

Se tiver que usar DAO com SQL puro, uso métodos especializados. Se o seu número de objetos for muito simples, você pode se virar com DAOs CRUD, mas quando você tem coisas muito complexas, não vai adiantar muito…

Não seria melhor ver os aobjetos de maneira agrupada do que ver uma relacionamento de objetos em uma consulta especifica.
ex:


class Funcionario
{
    private int codigo;
    private String nome;
    private Departamento departemento;
    // getter and setters
}

class Departamento
{
    private int codigo;
    private String nome;
}

// para deixa type-safe
// no 1.5 pode ser generics
// lazy load numa boa
class FuncionarioColecao
{
    public Funcionario getFuncionario() {}
}

class FuncionarioDAO
{
    public FuncionarioColecao consultar()
    {
       // retorna funcionarios;
    }    
}

FuncionarioColecao funcionarios = FuncionarioDAO.consultar();
while (funcionarios.proximo())
{
    Funcionario funcionario = funcionarios.getFuncionario();
 
   imprima(funcionario.getDepartamento().getNome());
}

Você não precisa de um relacionamento explicito.
Voce parte do prncipio que está fazendo uma consulta de funcionarios, departamento esta agregado.
Então a consulta parte do FuncionarioDAO.
Agora internamente podema usar o framework.

[quote=jprogrammer]Não seria melhor ver os aobjetos de maneira agrupada do que ver uma relacionamento de objetos em uma consulta especifica.

Você não precisa de um relacionamento explicito.
Voce parte do prncipio que está fazendo uma consulta de funcionarios, departamento esta agregado.
Então a consulta parte do FuncionarioDAO.
Agora internamente podema usar o framework.
[/quote]

Duas coisas aí.

Primeiro, sem lazy-loading, você pdoe ter problemas em trazer a estrutura, como eu já disse.

Imagina um banco coorporativo grande, onde um usuário tem um perfil, um grupo, dezenas de operações…tudo registrado.

Se eu trouxer a árvore toda, vou ter vários OutOfMemory e um sistema muito lento sem necessidade. Se eu trouxer aos poucos sem lazy-loading vou ter várias chamadas a DAOs diversos o tempo todo, se eu usar lazy-loading, posso usar um framework :wink:

Note que estamso falando em DAOs que acessam um banco de dados direamtnente, não um DAo para Hibernate, por exemplo.

Mas posso ter a arvore de objetos somente como estrutura e instanciar somente os campos que preciso.
Tem algum problema.


class Funcionario
 {
     private int codigo;
     private String nome;
     private Departamento departemento = null;
     // getter and setters
 }
 
 class Departamento
 {
     private int codigo;
     private String nome;
 }
 
 // para deixa type-safe
 // no 1.5 pode ser generics
 // lazy load numa boa
 class FuncionarioColecao
 {
     ResultSet result;
    boolean retornaDepartamento;

     FuncionarioColecao(ResultSet result,boolean retornaDepartamento)
     {
         this.result = result;
         this.retornaDepartamento = retornaDepartamento
;
     }

     public boolean proximo()
     {
          return result.next();
     }

     public Funcionario getFuncionario()
     {
          funcionario = new Funcionario();
          funcionario.setCodigo(rs.getLong("CODIGO"));
          funcionario.setNome(rs.getLong("NOME"));
          if (retornaDepartamento)
          {
             departamento = new Departamento();
             departamento.setNome(rs.getString("DESC_DEPARTAMENTO"))
             funcionario.setDepartamento(departamento);
          } 

          return funcionario;
     }
 }
 
 class FuncionarioDAO
 {
     public FuncionarioColecao consultar(boolean retornarDepartamento)
     {
         if (retornarDepartamento)
          // faco join com departamento

         return new  FuncionarioColecao(result,retornarDepartamento);

     }    
 }
 
 FuncionarioColecao funcionarios = FuncionarioDAO.consultar(true);
 while (funcionarios.proximo())
 {
     Funcionario funcionario = funcionarios.getFuncionario();
  
    imprima(funcionario.getDepartamento().getNome());
 }

Acoplamento.

Para estruturas simples, pdoe ser bem prático. Para grafos complicados (Usuário tem um perfil, pertence à um Grupo, á numa Rede, pode se comunicar com n outros Usuários…) você vai ter mais variáveis de controle do que or estante do código no sistema :wink:

Mas quando se tem uma variável do tipo de uma classe determinada, mas ela não tem referencia isso não afetaria a performance ?
Ou afetaria ?
ex:

Departamento dep = null; // não tem instancia, só se eu precisar;

Mas em uma estrutrura altamente “cascateada” como você falou, tirando incomodo de ter variaveis de controle, o existiria o problema de performance ?

Já fiz uma teste serializando uma classe.
E só por ela ter variavel sem instancia (null) o tamanho dos bytes aumentaram.
Agora não sei se meu tipo de medição tem alguma coerencia.

Teoricamente, sua medição não tem muito sentido, creio. Objetos em memória e Serializados possuem diferenças.

O problema de performance não é relativo ao uso de memoria por 1 field a mais, mas sim por buscar muito mais informação que o necessario no banco de dados.

Entendi.
O problema não é a estrutura de objetos em si (desde que não instanciamos todos os objetos agregados!), mas a recuperação dessas informações do banco de dados.

E a separação de lógica de dados e de negocios, alguma opiniao.
Como voces fazem, o que acham que deve ser feito.
É valido ter uma classe apenas para delegar para o DAO.
ex:


class FuncionariosRegras
{
   public void cadastrar(Funcionario funcionario)
   {
       if (funcionario.getCodigo() == 0)
         throw new BusinessException("Código com valor inválido");

      // demais validacoes e verificacoes

     FuncionarioDAO.inserir(funconario) // faz persistencia
   }
}

Pelo que sei devemos seperar dados de negócios.

Que eu saiba, temos que separar a camada de acesso aos dados do negocio. Dados e negocio quanto mais junto melhor.

Voce pode ter um método cadastrar em Funcionario que valida tudo e termina mandando o dao salvar ele.

Podemos trocar o nome da classe por:
Funcionarios (no plural).

Veja que aqui eu tenho.

  • cadastre um funcionario
    é diferente de
  • funcionario.cadastra-se

Mas ai vamos entrar um discussao antiga.

E o que eu quero saber mesmo é:
Fica embassado colocar a validaçao no DAO.

O problema é se em outra regra de negocio eu quiser inserir um funcionario também.
Eu faco pelo DAO ou pela regra de negocio ?
Para mim tem que ser pela regra.

O DAO não vai ter regra alguma, nunca jamais, senão você vai diminuir o reuso dele em muito.

Que tal o seguinte exemplo:

void cadastraViaWeb() {
  Funcionario f =  new Funcionario();
  ....
  f.save(); //valida se pode ser salvo e chama o dado para "dar o insert"
}

void migraCadastroDeSistemaAntigo() {
  Functionario f =  new Funcionario();
  ....

  f.save(); //valida se pode ser salvo e chama o dado para "dar o insert"
}

Pronto, o DAO só faz oque precisa, funcionario só faz oque precisa e teus use cases não furam os layers da aplicação.

De uma maneira geral, eu estabeleço no meu DAO um contrato de que a ivnariante do objeto vai estar cumprida, ou seja: todas as associações obrigatórias são satisfeitas e os atributos estão dentro do válido.

O DAO coloca no SGBD (com ajuda de outros, quase sempre) esses relacionamentos e (dependendo do caso), checa se os outros estão preenchidos (quando é só um valor, null basta, quando é uma relação com outra tabela, tem que checar qual registro apontar).

Pera. Outra regra de negócio não, você processa TODAS as regras de negócio no seu POJO e depois manda o DAO pegar aquele objeto e enfiar no SGBD. Acho que você está confundindo esse passo, não :roll: ?

O que pode acontecer é a criação de alguns métodos de conveniência. Se, por exemplo, você vai atualizar quinze mil objetos em banco, se puxar um a um, atualizar e persistir vai gastar tempo e memória a toa. Você pdoe criar um método no DAO que faça isso via SQL, te poupando muito tempo e esforço :wink:

Entretanto, você deve ter essa função na sua camada de negócios. por exemplo, eu teria um método num objeto de negócios como qualquer outro, mas na verdade ele chama o DAO :wink:

Então eu poderia ter os métodos relacionados a uma funcionario no proprio pojo e poderia ter uma classe para metódo de negocios coletivos para vários funcionarios.
ex:


// esta no singular
class Funcionario
{
   private int salario;

    public void promover()
    {
     // faco validacoes

       salario += 800.00;
       // depois eu persisto
    }

}

// esta no plural
class Funcionarios
{
   public void promover(int codigoDepartamento)
   {
     // faco validacoes

      FuncionarioDAO.atualizarSalarios(codigoDepartamento,800.00);
   }
}

Sim, mas é claro que com cuidado. Você estará jogando fora a segurança de um modelo de objetos por performance, e cabe julgar o custo/benefício.

O maior deles é que você deveria ter um meio de avisar às instâncias já existentes de funcionário que elas estão defasadas, e isso pode ser bem complicado (mais um motivo para usar DAOs em sistemas simples, não necessariamente pequenos, mas simples).

Sim, existe até um padrão para isso, que é o Table Data Gateway. Que é tratar uma coleção de objetos como uma entidade só.

No caso do teu sistema realizar muita atualização em massa, vale a pena usar isso e criar um POJO que representa um conjunto de entidades de maior granulosidade.


FuncionariosDoDepartamento f = new FuncionariosDoDepartamento("TI");
f.mandaPraRua();

Mas em que caso uma classe defasada pode atrapalhar.
Eu busco os objetos e trabalho com o que estiver na memoria.
Se outro usuario atualizou ai cabe a implementacao de mecanismos no sistema. Mas acredito que isso é feito em nivel de GUI.
Pensar isso na estrutura é ficar louco.

Outra duvida, vamos imaginar uma sistema de ponto eletronico
ex:


class Apontamentos
{
   public void processarApontamento(int diaIni,  init diaFim)
   {
       // preciso pegar uma colecao de funcionarios, pois o processo é complexo e só update nao serve
      
     // faco iteracao pela colecao e faço apontamento para cada funcionario
   
   }
}

Isso é adequado.
Esse método depende de varios funconarios.
Agora é melhor eu ter essa classe ou criar um metodo.
funcionario.apontar();

É um processo complexo que depende de inumeras entidades.
Não é melhor deixar com o funcionario apenas os metodos ligados diretamente a ele.

outro exemplo


class Funcionario
{
   public void tranferirdeFilial()
   {
      // é um metodo muito complexo 
    }
}

É adequado ou não colocar no pojo um método que acessa dados persistidos.