Dúvidas sobre o padrão DAO

Oi pessoal,

mas uma vez pedindo ajuda, estou aqui tentando aprender usar o padrão DAO, a interface inicial ficou assim:

package br.ufrj.gpi.scf.controle;

import br.ufrj.gpi.scf.modelo.* ;
import java.io.IOException;
import java.util.Vector;

public interface AlunoDAO {

/**
* Persiste o aluno no banco de dados, levanta uma Exception
(SQLExecption),
* caso algum erro aconteça
*/
public void save(Aluno aluno) throws Exception;

public void delete(Aluno aluno) throws Exception;

/**
* Altera um aluno no banco de dados, levanta um Exception
(SQLExecption),
* caso algum erro aconteça
*/
public void update(Aluno aluno) throws Exception;

/**
* Retorna um vetor de alunos, levanta Exceptions (AlunoException,
* SQLException), caso algum erro aconteça
*/
public Vector list() throws Exception, IOException;

public Aluno find(String cpf) throws Exception;

public Aluno find(int id) throws Exception;

}

A idéia é que, assim que tiver tempo de estudar a JPA, mude de mysql para hibernate.

Bom, estou com as seguintes dúvida:

1 - Na interface estou levantando Exceptions ao invés de colocar explicitamente as exceções, SQL etc… Fiz isso pensando em quando migrar para hibernate, já que não sei se ele levantará as mesmas que o MySql por exemplo. Isso está correto?

2 - Até agora, na classe que implementa a minha interface DAO, em cada método (save, delete etc.), estou fechando a conexão com o banco (aberta no construtor da classe). Achei que o desempenho caiu um pouco. Pensei em colocar um abreConexao e um fechaConexao na interface. Esse é o caminho certo?

Desculpem-me caso essas perguntas sejam por demais “noobs”, não trabalho com desenvolvimento a pelo menos 11 anos (trabalho com segurança e redes), e algumas coisas só discutido com os amigos mesmo para maturar na cabeça.

Desde já, VALEU PELA AJUDA!

[color=red][Moderador]Por favor coloque seu código entre as tags [ code] [/code] para uma melhor visualização e organização do fórum.[/color]

Opa…

vamos com calma ae…

MySQL = banco de dados

hibernate = framework

jpa = especificação

Vc esta dizendo que vai migrar de Mysql para hibernate…sugiro que vc estude um pouco mais sobre o que exatamente é o hibernate…

e as exceções eu sugiro que vc lance apenas SQLException…afina é disso que se trata a sua interface…

[/]'s

Olá olhando a sua interface, percebo que ela está acoplada com a classe Aluno… assim sendo vejo seu sistema do seguinte modo: 10 interfaces DAO para 10 classes DAO. Sendo o objetivo da interface de promever o poliformismo, nao vejo vantagem de ter uma interface “dedicada”; ou seja, sua interface tem que ser a mais genérica possível.

O uso de um pool de conexoes seria a melhor alteranativa.

Espero ter ajudado.

pode usar SQLException (ou uma sua), mas lembro do que o Giuliano respondeu

na minha humilde opinião, não é responsabilidade do seu DAO abrir ou fechar conexões, você poderia receber a conexão no construtor do
seu DAO ou junto de cada metodo e quem injetou essa conexão é que fica responsavel por executar o procedimento de fechar essa conexão
(que tambem deve estar isolado em alguma classe)

Sei que muita gente odeia esse artigo, mas pra começar da uma boa base
de uma olhada

http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

Oi Pessoal, desculpe a demora, tenho andando EXTREMAMENTE enrolado. Vamos por partes:

  • Moderador

Desculpe, falha minha. Não acontecerá novamente.

  • nadilsons

Entendi. Estava conversando com o pessoal da RioJUG e um colega lá deu algumas dicas para implementar o mais polimórfico possível. Assim que modificar o código posto aqui.

Em tempo, estou usando o C3P0 para a parte pool.

  • Giulliano

Foi mal, falei de todos colocando no mesmo “balaio”. Entendo suas diferenças.

Agora estou lançando apenas DAOExceptions.

  • ddduran

Já tinha esbarrado nesse artigo, vou tomar vergonha na cara e lê-lo (e tentar entendê-lo hehe)

Bom, obrigado a todos!

Não. Vc deve criar uma DAOException que será lançada pelo DAO. Faça-a RuntimeException.
Quando internamente acontecer um erro encapsule nessa nova Exception.

Não. Abra e feche a conexão sempre no método usando um try.

Outra coisa, não retorne Vector , retorne List (interface). E chame de listAll() em vez de list(); É mais claro.

De resto ok. Não é problema vc ter 10 DAO para 10 classes , é apenas chato.

Depois de ler um pouco, principalmente o post DAO’s nas classes de negócio (alias, posto incrível, ainda estou ralando para pegar toda a teoria ali citada) e de, infelizmente, ainda ter algumas dúvida, estou ressuscitando este tópico para pedir a ajuda dos gurus aqui do GUJ.

Enfim, agora meus modelos sabem que existe um repositório de dados, apesar de não saberem como ele é na verdade. O controle virou apenas um conjunto de ações que “decidem” o que fazer com os estímulos da vista (não vou nem colocá-los aqui).

Bom ficou mais ou menos assim:

Modelo

package modelo;

import modelo.dao.ContatoRepository;
import modelo.excecoes.RepositoryException;

public class Contato {
    
    private ContatoRepository repositorio;
            
    private int id;
    private String nome;
    private String telefone;    

    public Contato(String nome, String telefone) throws RepositoryException{
        
        this.setNome(nome);
        this.setTelefone(telefone);
        
        int id = repositorio.save(this);
        
        this.setId(id);
        
    }

    public void setNome(String nome) throws RepositoryException{
        
        if(nome.equals(""))
            throw new IllegalArgumentException("Nome em branco");
        
        Contato contato = repositorio.getContatoPorNome(nome);
        
        /* Verifica se o contato já existe no banco e se o que está no banco
         não é este contato */        
        if(( contato != null) &&
                (contato.id != this.getId()))
            throw new IllegalArgumentException("Contato já cadastrado");
        
        this.nome = nome;
        
    }


    // Os outros métodos gets/sets
    
    public void update() throws RepositoryException{
        repositorio.update(this);
    }

    public void delete() throws RepositoryException{
        repositorio.delete(this);
    }

}

Interface para o repositório

package modelo.dao;

import java.util.ArrayList;
import modelo.Contato;
import modelo.excecoes.RepositoryException;

public interface ContatoRepository {
    
    // Retorna o ID do contato no repositório
    public int save(Contato contato) throws RepositoryException;
    
    public void update(Contato contato) throws RepositoryException;
    
    public void delete(Contato contato) throws RepositoryException;
    
    public ArrayList getAll() throws RepositoryException;
    
    public Contato getContatoPorNome(String nome) throws RepositoryException;
    
    public ArrayList getContatosPorNome(String nome) throws RepositoryException;
    
}

Dúvidas:

1 - Quando eu tinha uma classe de controle que falava com o DAO/Repositório e fazia o CRUD, a consulta de dados ficava nela, agora eu devo passar para o modelo, correto? Mas como posso precisar consultar dados antes que qualquer instância do modelo exista, preciso de métodos estáticos, algo assim:

[code]
private static ContatoRepository repositorio;

//  . . . 

public static Contato getContatoPorNome(String nome) throws RepositoryException {
    return repositorio.getContatoPorNome(nome);
}[/code]

Isto está correto? Ou deveria criar outra classe, também do “pacote” modelo, para estes “finds” estáticos?

2 - Ao mover para o modelo outro problema que esbarrei é que alguns outros objetos observavam (padrão observer) o controle e, sempre que algo mudava (adição, exclusão etc. de objetos) o controle notificava os observadores.

Ou seja, novamente o problema de que preciso “acessar” a classe Contato mesmo antes de existir um objeto. Ou seja, preciso de um addObserver estático, o que não é disponibilizado pelo Observer do Java (ok, eu poderia criar o meu, mas estou primeiro tentando entender se é o caminho correto)

Desde já, obrigado pela ajuda.

OK, calma…
Independente de criar observers ser a opção adequaqda, veja java.util.Observer e java.util.Observable.

Agora, ao seu problema:

O ideal seria que o seu modelo ficasse independente do banco e desacoplado do DAO.
Tente fazer um DAO usando Generics. Há vários exemplos por aí.

A independência de banco vc consegue usando um framework que te permita isso. Existem frameworks de mapeamento objeto-relacional que trazem esta vantagem. Em particular, há aqueles que implementam a JPA, a especificação para mapeamento O-R.
Um destes, o mais conhecido, é o Hibernate. Pesquise sobre o Hibernate Annotations e a JPA que as coisas começarão a fazer mais sentido pra vc, eu acho.

Em parte. Vc deve isolar a exceções SQL, mas não com Exception.
Vc deve criar uma exceção especial (por exemplo DAOException) e encapsular a SQLException.
Mais sobre práticas relativas asexceções aqui

Não. O DAO deve encapsular isso. É correto não deixar isso na interface. O detalhes é que ele também deve prover meios de manter a transação aberta entre chamadas ao métodos. Vc faz issocriando uma interface Transacation para comunicar como “miolo” do DAO. Quando vc usa transaction os métodos são vinculados a ela.
Quando vc não usa, cada método é uma transação.
Outra prespetiva sobre isso é que no hibernate não existe conexão. Logo abreConexão seria inutil nesse DAO.
por outro lado o hibernate tem que abrir Session. Obviamente não vai criar um “abreSession” tb … né ?

Uma coisa que é ruim é criar um DAO para cada classe do dominio. Tente não fazer isso seguindo um outro padrão mais moderno o DomainStore.
Mais sobre DAO aqui

Oi Sérgio,

essa parte já implementei, seguindo as suas dicas lá das primeiros mensagens deste post. Queria uma ajuda nos passos seguintes, relacionados à mensagem que postei hoje (04/04/2008).

:wink:

Mas, desde já, VALEUZÃO PELA FORÇA!

[quote=pplupo]OK, calma…
Independente de criar observers ser a opção adequaqda, veja java.util.Observer e java.util.Observable.
[/quote]

Sim, eu já os tenho usado em outras aplicações.

Meu problema agora é que gostaria que um model para o jtable que construi “ouvisse” as mudança, basicamente CRUD (com exceção do retrieve), nos dados de um determinado objeto.

O update e delete, é até fácil de resolver, basta que todas vez que buscar dados no BD eu adicone o model do jtable como observer. Mas e o create? Ele ainda não existe, como posso fazer o model ser notificado da criação? Fazer ele ouvir o DAO?

Preciso estudar generics! URGENTE!

[quote=pplupo]
A independência de banco vc consegue usando um framework que te permita isso. Existem frameworks de mapeamento objeto-relacional que trazem esta vantagem. Em particular, há aqueles que implementam a JPA, a especificação para mapeamento O-R.
Um destes, o mais conhecido, é o Hibernate. Pesquise sobre o Hibernate Annotations e a JPA que as coisas começarão a fazer mais sentido pra vc, eu acho.[/quote]

Sim, conheço o hibernate.

Mas sempre tive duas preocupações com frameworks, principalmente os de ORM:

1 - Se depois quiser usar a base de dados do sistema como, por exemplo, fonte de dados para um BI ou DW, o banco gerado por eles sempre me pareceu confuso (Ok, andei lendo e parece que posso normalizar a base e fazer os ORM trabalhar com elas, correto?)

2 - Com relação aos frameworks em geral, fico preocupado em apostar minhas fichas em um e depois ele ser descontinuado. Assim tento sempre entender como eles funcionam para me virar sem eles. (Ok, meio maluco, talvez, totalmente uahuahua)

Vamos por partes, como diria o prof. de cálculo ao integrar… rs

[quote=Renato.Pinheiro][quote=pplupo]OK, calma…
Independente de criar observers ser a opção adequaqda, veja java.util.Observer e java.util.Observable.
[/quote]

Sim, eu já os tenho usado em outras aplicações.

Meu problema agora é que gostaria que um model para o jtable que construi “ouvisse” as mudança, basicamente CRUD (com exceção do retrieve), nos dados de um determinado objeto.

O update e delete, é até fácil de resolver, basta que todas vez que buscar dados no BD eu adicone o model do jtable como observer. Mas e o create? Ele ainda não existe, como posso fazer o model ser notificado da criação? Fazer ele ouvir o DAO?
[/quote]

Pode parecer um pouco gambiárrico, mas vc pode adicionar o observer na classe, com método estático. E as instâncias avisam à classe ao serem criadas, se passando como parâmetro. Resolve o problema, mas não sei se seria adequado. Até pq a criação da instância não implica em sua persistência no banco. Tem que ter atenção ao evento que vc quer observar.
AOP talvez seja mais elegante.

No big deal.

[quote=Renato.Pinheiro]

Não faz isso não!!! O DW tem um motivo pra ser modelado daquela forma. Se vc normalizar, vai detonar o desempenho do DW. É preciso distingüir se a sua aplicação é OLAP ou OLTP. Se for OLAP, não normalize não!!! Mantenha seus modelos estrela, seus cubos e snow flakes do jeito que são.

[quote=Renato.Pinheiro]
2 - Com relação aos frameworks em geral, fico preocupado em apostar minhas fichas em um e depois ele ser descontinuado. Assim tento sempre entender como eles funcionam para me virar sem eles. (Ok, meio maluco, talvez, totalmente uahuahua)[/quote]
Por isso mesmo vc deve usar a JPA. Além de especificação ela funciona como uma interface. Quando vc utilizar o hibernate como persistence provider da JPA, vc vai usar na verdade javax.persistence.*, interfaces e anotações. O hibernate vai apenas prover as implementações. Assim vc pode trocar para o OpenJPA, EclipseLink ou qualquer outra implementação trocando apenas as libs no classpath e o persistence.xml.

Ou como diria Jack, o estripador uhauahua

[quote=pplupo]Pode parecer um pouco gambiárrico, mas vc pode adicionar o observer na classe, com método estático. E as instâncias avisam à classe ao serem criadas, se passando como parâmetro. Resolve o problema, mas não sei se seria adequado. Até pq a criação da instância não implica em sua persistência no banco. Tem que ter atenção ao evento que vc quer observar.
[/quote]

Mas minha questão é, tenho uma VIEW que exibe todos os objetos (no exemplo, todos os contato) e que observa o modelo para atualizar essa exibição sempre que um objeto é criado, atualizado ou deletado.

Bom, com objetos antigos (oriundos da persistência) alterados ou deletados é simples, basta que na carga para view ela se adicione como observadora de cada um destes objetos. (Isso tb me parece meu gambiárrico hehe)

Meu problema é com os objetos recém persistidos, ou seja, que entraram no banco depois da carga inicial do dados para VIEW.

A primeira solução em que pensei foi criar um método estático como esse:


public class Contato extends Observable {

     public static void addObservador(Observer o) {

          this.addObserver(o);

     }

}

o problema é que não posso referenciar um método de instância a partir de um método de classe.

Pensei em criar meus próprios Observer/Observable, mas fiquei preocupado de ser a mãe de todas as gambiarras :slight_smile:

Aspectos . . . afff, ainda não, já dei uma olhada em alguma coisa, mas preciso primeiro consolidar algumas coisas sobre OO :wink:

Usei um exemplo ruim, o queria dizer é que, no meu primeiro contato com o JPA, me pareceu que o banco de dados resultante não seria fácil de utilizado para fins fora da aplicação. (aquele tabelão de herança por exemplo). Mas a pouco tempo, lendo um pouco mais, vi que é possível modelar o banco de maneira relacional e “anotá-lo” no java.

Enfim, preciso estudar o JPA. Recomenda algum livro? Esses dias quase peguei o do pessoal do hibernate, mas depois acabei ficando de olho em um da O´Really sobre J2EE que parece falar bastante da JPA.

Entendi.

Ou como diria Jack, o estripador uhauahua

[/quote]

Essa do Jack tá batida já… ;¬) além do mais, não amedronta tanto quanto certos professores… rs

Mas minha questão é, tenho uma VIEW que exibe todos os objetos (no exemplo, todos os contato) e que observa o modelo para atualizar essa exibição sempre que um objeto é criado, atualizado ou deletado.

Bom, com objetos antigos (oriundos da persistência) alterados ou deletados é simples, basta que na carga para view ela se adicione como observadora de cada um destes objetos. (Isso tb me parece meu gambiárrico hehe)

Meu problema é com os objetos recém persistidos, ou seja, que entraram no banco depois da carga inicial do dados para VIEW.

A primeira solução em que pensei foi criar um método estático como esse:


public class Contato extends Observable {

     public static void addObservador(Observer o) {

          this.addObserver(o);

     }

}

o problema é que não posso referenciar um método de instância a partir de um método de classe.

Pensei em criar meus próprios Observer/Observable, mas fiquei preocupado de ser a mãe de todas as gambiarras :slight_smile:
[/quote]

Veja… se vc quiser adicionar um observer, adicione-o a uma classe. Toda instância ao ser criada, notifica a classe também, se passando como parâmetro. E a classe poderá notificar os observadores.

De qualquer forma, não te aconselho a fazer uma coisa nem outra. Vc está usando arquitetura naked objects ou mvc? Pq se for mvc, vc pode fazer com que seu controller notifique a view da mudança que ocorreu e a view vai atrás das informações atualizadas (ou se atualiza inteira, se for o caso).
Se for naked objects, vc pode fazer a view se atualizar inteira, simplesmente.
[/quote]

Há outros tipos de herança além do Single Table. Procura o Joined Subclasses ou o Table per Concrete Class (que eu desaconselho). Não há pq fazer um ER desnormalizado se vc está preocupado com isso. Como na prática, em 90% das vezes eu nem vou olhar pra cara do banco, não me importo mto (a não ser q o desempenho caia. Aí vou atrás de criar índices, remodelar… até ter um desempenho ruim, não tem pq vc se preocupar.) Se a sua preocupação for integridade mas vc está trabalhando com OO, uma falha na integridade dos dados é um problema na sua aplicação e não no seu banco.

Olha, eu li o tutorial da sun e o guia do hibernate, ambos disponíveis gratuitamente. Então não sei te recomendar nenhum livro pq nunca os li e nunca recebi recomendação de nenhum também.

Nem me fale!

Você diz uma classe “externa”, ou seja, não classe contato (do meu exemplo) mas observar uma outra classe, a qual seria notificada das ações na classe contato.

[Stupid mode]
Pq no observer do java não é possível observar as classes, mas apenas às instâncias.
[/Stupid mode]

MVC em SWING :slight_smile: Ou pelo menos tentando . . .

[quote=pplupo]
Há outros tipos de herança além do Single Table. Procura o Joined Subclasses ou o Table per Concrete Class (que eu desaconselho). Não há pq fazer um ER desnormalizado se vc está preocupado com isso. Como na prática, em 90% das vezes eu nem vou olhar pra cara do banco, não me importo mto (a não ser q o desempenho caia. Aí vou atrás de criar índices, remodelar… até ter um desempenho ruim, não tem pq vc se preocupar.) Se a sua preocupação for integridade mas vc está trabalhando com OO, uma falha na integridade dos dados é um problema na sua aplicação e não no seu banco.

Olha, eu li o tutorial da sun e o guia do hibernate, ambos disponíveis gratuitamente. Então não sei te recomendar nenhum livro pq nunca os li e nunca recebi recomendação de nenhum também.[/quote]

Vou catar esses ai, qualquer coisa pertubo mais um pouco :wink:

Pode ser a mesma classe sim.

Implemente na mão, ué… é simples! :¬) Mas, novamente, use alguma das outras abordagens que citei. ;¬) Vai deixar tudo mais simples e menos obscuro.

[quote=pplupo]
Implemente na mão, ué… é simples! :¬) Mas, novamente, use alguma das outras abordagens que citei. ;¬) Vai deixar tudo mais simples e menos obscuro.[/quote]

Já implementei, depois do papo já estava achando que seria o caminho . . .

Mais uma vez, VALEU A FORÇA!