Do DAO ao Domain Store

Persistência

Todos os sistemas reais para empresas precisam persistir dados em algum ponto do processamento. A razão para isso é simples: segurança. ninguém quer perder as informações acumuladas nos seus sistema.Muitos – a grande maioria – utiliza tecnologias tradicionais de banco de dados para a persistência.Embora o produto final seja criado para persistir os dados num DBMS (Database Management System : Sistema de Gerenciamento de Banco de Dados) é possível que durante o desenvolvimento não se queira, ou não se possa, usar essa tecnologia. Por exemplo, durante a fase de testes os dados podem estar numa coleção pré-definida em memória ou em arquivo.Durante a vida do sistema é provável que o provedor da solução de DBMS mude obrigando o sistema a conversar com outro DBMS ou obrigando a empresa a manter o DBMS antigo. Entenda-se que esta opção pode ser financeiramente inviável já que diminuir o custo de infra-estrutura é vital.Para proteger a vida do sistema e o investimento feito a aplicação deve poder conversar com o maior numero possível de DBMS. Isso é um diferencial na hora de vender o seu sistema ( se ele for de prateleira) ou de justificar o custo na hora de fabricar o sistema. A capacidade de comunicar com diferentes DBMS de diferentes fornecedores agrega grande valor ao produto final e terá com pouco ou nenhum investimento por parte de quem compra o seu sistema.Para aquelas empresas onde a persistência não é feita em banco da dados o mesmo se aplica com a diferença que elas podem querer migrar para o uso de um banco de dados no futuro.

A solução tradicional para garantir que o sistema é independente da tecnologia de persistência é encapsular todo e qualquer acesso a essa tecnologia usando o padrão de projeto Data Access Object (DAO) .O conceito é simples: crie-se uma interface ( um contrato) que o sistema irá usar sem conhecimento de qual tecnologia de persistência está sendo realmente usada a cada momento. Adicione-se uma forma de configurar qual implementação real será usada. Adicione-se quantas implementações de persistência sejam necessárias. A longo prazo esta implementações são altamente reusáveis e pequenos ajuste apenas são feitos quando a tecnologia do DBMS mudar ( ou seja, no pior caso a cada versão do DBMS )É importante sublinhar que o DAO serve apenas para encapsular acesso a dados mas que “dados” não significa apenas o uso de DBMS. Um arquivo pode ser um suporte para dados, assim como a memória RAM (Claro que dizer que a memória RAM é persistente pode ser um exagero, mas por outro lado persistência é uma questão de tempo.)

O que é o DAO ?

O DAO é um padrão de projeto ,talvez o padrão mais famoso a par com o Singleton. Tal como o Singleton o padrão DAO é muitas vezes incompreendido e mal implementado. O objetivo do padrão é simples: isolar a aplicação java da tecnologia de acesso e localização dos dados. Contudo ele não padroniza esse acesso.O padrão DAO funciona como uma ponte entra dois sistemas: o seu e o DBMS (ou similar) .

O padrão DAO pode seguir duas filosofias de implementação: orientada a processo ou orientada a objetos.Na primeira as lógicas estão dentro do DBMS e o DAO apenas traduz comandos entre a aplicação Java e o DBMS. Esta implementação é muito importante, e só faz sentido, em sistema legados em que tudo é escrito no DBMS.Aqui o DAO é um instrumento de integração e não de isolamento. Ninguém pensa em substituir o DBMS porque isso significaria reescrever todas as regras de negocio contidas nele. O sistema em Java é apenas um cliente dessa aplicação matriz escrita dentro do DBMS. Nesta situação não se espera que o DAO seja modificado no futuro.

A segunda filosofia é seguida pela maioria dos programas novos que não contêm logica no DBMS deixando-a no servidor de aplicação e ganhando flexibilidade. Aqui o objetivo do DAO é prover isolamento e flexibilidade para mudar o DBMS subjacente.Neste tipo de aplicações o DBMS é apenas um armazém de dados e não contêm nenhuma inteligencia relativa a regras de negócio.É neste cenário que vale a pena investir num design cuidadoso pensado para durar.

Mapeamento

O problema em implementar um DAO aparece na hora de converter o objeto java para uma representação que o sistema de persistência entenda ( e o contrário quando recuperamos os dados persistidos).Esta operação é conhecida como mapeamento. Quando usamos um sistema de persistência baseado em JDBC mapear significa construir frases SQL com as instruções das operações que queremos assim como saber que coluna de que tabela corresponde a que campo de que classe. Em outros sistema de persistência será necessário um mapeamento entre a interface do DAO e a interface da API do sistema de persistência.Existem duas formas de fazer o mapeamento: explicitamente ou usando metadados.

Mapeamento explicito

Mapeamento explicito (a.k.a. mapeamento manual) significa que o mapeamento será codificado manualmente , caso a caso, para cada entidade persistente. Isto significa um trabalho pesado e muitas vezes repetitivo de programação. Como tal é sujeito a muitos erros porque cansa rapidamente o programador. Por outro lado permite um ajuste fino no mapeamento e conversão dos dados entre os sistemas.

Mapeamento com Metadados

No mapeamento com metadados todas as operações são genéricas e previamente programadas um só vez. As operações se baseiam em metadados que representam o modelo de mapeamento. Esses metadados podem ser fornecidos de diferentes formas sendo as mais usadas atualmente as baseadas em xml e em anotações no código. Esta forma exige muito pouco do programador mas não permite um ajuste fino. Todas as entidades são tratadas de forma semelhante. O mapeamento baseado em metadados é uma forma popular hoje em dia inspirada em tecnologias como o Hibernate e o JPA.

Como seria a interface de um DAO ?

A implementação do padrão DAO resume-se a criar uma interface padrão com as operações que o DAO proverá e várias implementações dessa interface, uma para cada tipo de armazém de dados.Existe um conjunto de básicas comummente referidas como operações CRUD que são: Criar (Create) , Recuperar (Retrive) , Atualizar (Update) e Apagar (Delete). Criar significa inserir o objeto pela primeira vez no contexto de persistência. Recuperar significa obter um , ou mais, objetos que já estão no contexto , normalmente baseado em algum critério de pesquisa. Atualizar significa alterar um objeto que já está no contexto com novas informações. Por fim, apagar, significa remover um ou mais objetos do contexto.Basado nisso a interface Java,usando o recurso de Generics, seria mais ou menos assim:





public interface DAO {
public void create(Object obj);
public void update(Object obj);public void delete(Object obj);
public <T> T retriveOne(Class<T> objClass, Criteria criteria);public <T> Collection<T> retriveMany(Class<T> objClass, Criteria criteria);

}


Código 1:

Esta seria a interface de um DAO genérico capaz de manipular qualquer tipo de objeto já que T não tem restrições.A classe Criteria representa um objeto que encapsula um conjunto de instruções para filtrar e ordenar os objetos de uma certa classe. Esta classe atua como um critério de filtro para os dados gerenciados pelo DAO.

Existem recomendações de que cada tipo de objeto persistente tenha o seu DAO criando uma miríade de objetos como ClienteDAO, PedidoDAO, EndereçoDAO, etc.. Isso é necessário quando trabalhamos com mapeamento explicito porque é a única forma de podermos implementar regras com base na entidade em causa.Mas em sistema de mapeamento por metadados é um trabalho desnecessário e uma profusão inútil de classes que no fim fazem todas a mesma coisa.Contudo, muitos advogam que é necessário um DAO diferente para cada objeto porque cada objeto tem regras especiais. Pensar num DAO deste tipo implica automaticamente em anexar ao DAO regras que dependem do significado dos objetos e isso significa sem dúvida usar mapeamento explicito.Num mapeamento guiado por metadados um DAO que passa a depender da semântica dos objetos que manipula -as famosas regras de negócio – fere o objetivo principal do DAO que é poder ser mudado a qualquer momento.

Portanto, se você está desenhando um DAO com mapeamento explicito use e abuse do conhecimento das regras de negocio. Afinal esse tipo de DAO está fortemente dependente do DBMS subjacente e não é provável que mude no futuro.O seu objetivo nunca foi ser flexível, apenas uma ponte entre duas linguagens diferentes.Mas se você está desenhando um DAO com mapeamento implícito está proibido de incluir regras de negocio dentro do DAO.Se não respeitar esta proibição terá grandes problemas quando tentar implementar o DAO para outro sistema de persistência.

Configuração da Implementação

Já que temos uma interface desenhada e um conjunto de implementações possiveis temos que ter alguma forma de configurar qual dessas implementações será usada. O padrão de projeto ideal para isso é padrão o Factory. Precisamos apenas desenhar um objecto seguindo o padrão Factory e prover alguma forma de o configurar para que produza o DAO correto.





public interface DAOFactory {
public DAO getInstance();
public void setConfiguration(Properties configuration);}


Código 2:

Poderíamos ter escolhido outras formas de configuração em vez de usar Properties mas o importante é que exista uma forma de configurar a fábrica.

Simplificação da Interface e Gerenciamento de Estado

Poderíamos facilmente simplificar a interface do DAO se pensarmos que criar e atualizar são operações correlacionadas. Afinal não nos importa muito se os dados serão criados no contexto de persistência ou simplesmente atualizados. Só queremos persistir e apagar os dados. Por outro lado é comum termos que persistir um conjunto de objetos e não apenas um. Uma operação como esta pode aumentar a eficiência do uso do DAO.A nova interface seria algo como:





public interface DAO {
public void persist(Object obj); // create ou update
public void persist(Collection<?> collection);public void delete(Object obj);
public void delete(Collection<?> collection);public void delete(Criteria criteria); / /delete sem retrive
public <T> T retriveOne(Class<T> objClass, Criteria criteria);public <T> Collection<T> retriveMany(Class<T> objClass, Criteria criteria);}


Código 3:

Podemos ser mais arrojados e pensar que cada objeto pode conter informação sobre o seu estado de persistência no contexto e esse estado será gerenciado pelo DAO. Com isso podemos ainda simplificar mais a interface, mas ao custo de vincularmos os objectos com o gerenciamento de estado feito pelo DAO.





public interface DAO {
public void persist(Object obj); // create , update ou delete
public void persist(Collection<?> collection);public void delete(Criteria criteria); // delete sem retrive
public <T> T retriveOne(Class<T> objClass, Criteria criteria);public <T> Collection<T> retriveMany(Class<T> objClass, Criteria criteria);}


Código 4:

Com isso criámos um tipo de objeto que não é mais um DAO. Ele não se limita a ser uma ponte entre sistemas.Ele tem agora capacidades próprias que teremos que replicar em cada implementação do DAO que fizermos.

DAO que sabe demais

Uma das utilidades do DAO é que isola o seu programa de ter que tratar com os detalhes da persistência de forma que o sistema real de persistência possa ser acoplado e desacoplado a gosto. Se colocamos estado dentro do DAO , ou mesmo um gerenciador de estado, ou qualquer outra regra especial dentro do DAOele passa automaticamente a não ser flexível e todo o objetivo de construir um DAO vai pelo cano.

Felizmente podemos aplicar o Principio de Separação de Responsabilidades e entender que; se o DAO não pode conter gerenciamento de estado, podemos criar outro objeto que contenha esse gerenciamento.Se a aplicação se comunicar com o gerenciador para pedir as operações de persistência, o gerenciador pode otimizar o trabalho e usar o DAO internamente para executar as acções reais no sistema de persistência.Assim mantemos o DAO sabendo pouco e flexível e ganhamos mais facilidade ao persistir nossos objetos.

Este é o conceito por detrás de um outro padrão de projeto o Domain Store.

O Domain Store

A ideia por detrás do do Domain Store é aquela que vimos: somar funcionalidades ao DAO sem interferir com a flexibilidade e a capacidade de escolher a implementação do DAO que mais nos satisfizer. Analisemos com mais detalhes como funcionaria umDomain Store.

A aplicação pode requisitar ações ao Domain Store por meio de uma interface de gerenciamento de persistência.Essa interface é igual à que desenhámos para o DAO. Essa é a razão da confusão entre os dois padrões. Ao ser pedido que um objeto seja persistido o gerenciador de persistência pede ao gerenciador de estado que teste o estado do objeto. Esse estado é injetado no objeto sem conhecimento da aplicação. Conforme o estado do objeto, será dada uma instrução ao DAO para que adicione, altere ou remova o objeto do armazém de dados. DAO realizará a tarefa invocando a operação no DBMS real.Quando a instrução recebida pelo Gerenciador de Persistência não depende do estado do objeto o DAO será chamado directamente sem a ajuda do gerenciado de estado.

O DAO ainda precisará de um mapeamento para executar as operações, mas ele será guiado por metadados. Esses metadados serão compartilhados com o gerenciador de estado para que ele reconheça as diferenças entre os objetos de domínio e possa decidir como e quanto injetar e consultar o estado dos objetos.

Or critérios de filtro continuarão a ser usados mas precisamos rever o seu uso e design.

Critérios e Consultas

Uma das razões principais de querer um DAO com mapeamento explicito é pode escrever frases SQL complexas ou parametrizada. Se não deixamos o DAO ter esses métodos especiais onde escrever então essas frases SQL ?A resposta a isso é simples: não iremos escrever essas frases, o DAO irá.

As instruções SQL são apenas válidas para sistemas baseados em SQL. Claro que, como disse antes, esse o sistema de persistência mais usado, mas também como já disse, não é o único. Logo o uso de SQL vai depender do DBMS real com que o DAO se comunica e a tecnologia que ele usa. Um DAO baseado em JDBC concerteza precisa de frases SQL, mas um DAO baseado em XML , por exemplo, não terá nenhuma utilidade para elas.Restamos então prover formas de escrever consultas de dados sem estar amarrado ao conceito de SQL.

Consultas

As consultas são então objetos que dependem da tecnologia final usada pelo DAO e podemos pensar que eles são definidos de duas formas: genericamente e nativamente. Definir abstractamente significa construir um objeto com todos os parâmetros necessários à consulta e pedir ao gerenciador de persistência que transforme isso numa pesquisa que o DAO possa entender. Na realidade, o gerenciador de persistência pedirá ao DAO que crie essa consulta por ele.

A consulta será criada e encapsulada num objeto Query que poderemos usar para executar a consulta quantas vezes quisermos. Ele é uma implementação do padrão Command. Os parâmetros em si podem ser encapsulados num objeto que implemente o padrão Query Object

Critérios

Os Critérios são grafos que encapsulam a instrução que queremos passar ao sistema de persistência. Eles não contêm SQL algum, ou qualquer outra tecnologia que dependa do DBMS real, desta forma garantindo independência. Um DAO que não se comunica com SQL poderá interpretar a mesma instrução, obtendo o mesmo resultado, mas sem escrever SQL. Os critérios podem conter instruções de filtro, ordenação e até mesmo cálculos simples sobre um conjunto para ganhar performance e nos aproveitarmos das tecnologias modernas de DBMS.

As interfaces dos nosso objetos principais de um Domain Store seriam mais ou menos assim:





public interface PersistenceManager {
Query createQuery(Criteria criteria);
public void persist(Object obj); // create , update or delete public void persist(Collection<T> collection);
public void delete(Object obj); // força delete public void delete(Collection<T> collection); // força delete
}
public interface StateManager { public void setState(PersistenteState state, Object obj);
public PersistenteState getState(Object obj);}
public interface Query {
public <T> Collection<T> list();
public <T> T find();

public long count();
public void deleteAll(); // delete sem retrive
}

public interface DAO {
Query createQuery(Criteria criteria);
public void persist(Collection<?> collection);

public void delete(Collection<?> collection);
public <T> Collection<T> retrive(Class<T> objClass, Criteria criteria);

}


Código 5:

DAO, Domain Store , Hibernate e JPA

A solução do padrão Domain Store é genérica , flexível e isola a aplicação do trabalho de persistir e recuperar dados de um contexto persistente. Como a maioria das empresas usa DBMS baseados em SQL não é de admirar que tenha nascido uma forma de Domain Store especifica para esse tipo de contexto. O Hibernate é essa ferramenta que galvanizou e alterou a forma de pensar em persistência nos últimos anos.

Por outro lado, a industria ligada ao Java tornou o Domain Store um padrão integrado e essencial a toda a linguagem ao introduzir o Java Persistence API (JPA) no EJB 3. A JPA  é uma especificação para um Domain Store genérico que conversa com banco de dados.

O padrão DAO quase morreu no advento do JPA e a única razão para ele ainda existir é quando o uso de mapeamento explicito se faz necessário,i.e. quando queremos um objeto que traduza tabelas para objetos de uma forma muito especifica. Com cada vez menos sistemas legados, menos necessária é essa tradução especifica e menos necesário será o uso do padrão DAO como um mapeador especifico. O único problema é que a especificação JPA é ainda muito recente e ingénua. Não conta, por exemplo com o mecanismo de Critérios que o Hibernate já suporta e que é vital para o desacoplamento total do banco. A próxima expecificação do JPA irá resolver esse problema.

Se você não pode, ou não quer, esperar tanto, espero que o tenha ajudado a entender como implementar seu proprio Domain Store.

Referências

[1] Core J2EE Patterns – Data Access Object
Sun Microsystems, Inc.
URL:http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
[2] Diagrama de Classes para um Domain Store
CoreJ2EEPatterns.com
URL:http://www.corej2eepatterns.com/Patterns2ndEd/images/DSMainClass1.gif
[3] HibernateURL:http://www.hibernate.org/
[4] Java Persistence API FAQ
Sun Microsystems, Inc.
URL:http://java.sun.com/javaee/overview/faq/persistence.jsp
Creative Commons License 2007-12-17 Sérgio Manuel Marcos Taborda
Este trabalho é licenciado sob a
Licença Creative Commons Atribuição-Uso Não-Comercial-Não a obras derivadas 3.0 Genérica .

35 opiniões sobre “Do DAO ao Domain Store”

  1. Sérgio, muito bom o artigo.

    Mas não entendi a parte final, na qual você afirma o seguinte:

    “O padrão DAO quase morreu no advento do JPA e a única razão para ele ainda existir é quando o uso de mapeamento explicito se faz necessário.”

    Uso Hibernate mas nunca deixei de usar DAOs. Não entendo como uma coisa exclui a outra. Poderia explicar melhor?

    Abraços

  2. Tarso, obrigado pela pergunta.

    O Hibernate faz mapemaneto por metadados. Vc não pode usar uma instrução SQL ad doc nem usar o Hibernate para escrever em XML , por exemplo.
    O DAO só é relevante quando vc tem métodos especiais que usam instruções ultrasofisticadas que se aproveitam ao máximo das capacidades do banco. Para o insert/delete/select feijão-com-arroz não ha necessidade de tais instruções e um mecanismo padronizado como o Hibernate funciona sem problemas.

    O Hibernate é mais um DomainStore que um DAO. O DomainStore é algo mais poderoso que um DAO porque ele tem capacidades de gerenciamento. Usar DAO com Hibernate não faz sentido é como ter um Ferrari e colocar uma casca de Ford T4.

    Investigue a API do Hibernate e verá não ha nenhum objeto que vc tenha que implementar ou reimplementar para cada classe do seu dominio. O Hibernate funciona com qualquer classe. Isso é ser generico. Se esconde esse poder num DAO e ainda por cima necessita de várias implementações ( ClienteDAO, ProdutoDAO , etc…) é dar um passo atraz. Não acha ?

    O DAO só é bom quando vc precisa de instruções ultrasofisticadas. Sistemas modernos não fazem uso dessas instruções. Apenas sistemas legados. Por isso a utilidade do DAO é limitada e à medida que mais frameworks como JPA são introduzidos menos é necessário o DAO.
    O DAO quase morreu porque a necessidade de instruções ultrasofisticadas quase morreu.

  3. Muito bom. Esse seu artigo (principalmente essa sua resposta) me chamou a atenção de que às vezes fazemos algo sem nem mesmo refletir a respeito. Realmente, se utilizamos mapeamento via annotations ou XML, o Hibernate tem tudo o que precisa para persistir seus dados, bastando utilizar o Session ou o EntityManager.

    Mas se eu não quiser que minhas classes de negócio fiquem cheias daquelas anotações, e se eu não gostar de XML? Aí um DAO cairia bem não?

  4. Se vc não quiser suas classes annotadas ou usar XML vc realmente precisa de um DAO por entidade. Esse DAO seria responsável por fornececer os metadados que a tecnologia subjacente precisa (nem que seja apenas o nome e tipo de campo). O problema com isso é que é chato, demorado e pouco reutilizável. É melhor ter um mecanismo padrão que funcione com qualquer entidade e obter os metadados de uma forma padrão (algo como getMetadata(entidade.class) ) que pode ser implementada lendo de arquivo, anotações, ou implementada manualmente. Assim, não seria o DAO que vc tem que criar para cada entidade e sim o objeto que controi os metadados.

    Lembre-se sempre que o DAO serve para abstrair a tencologia de acesso ao banco. Apenas isso. Nada mais do que isso. Contudo, em termos modernos, isso não é mais suficiente. Queremos controle de estado, cache, distribuição, critérios de procurar independentes de SQL , configurar pouco e fazer muito , etc… Tudo isto são coisas que apenas o DomainStore dá.

  5. Obrigado por suas respostas, Sérgio.

    Acho que minha cabeça já tá muito alienada a ponto de não conseguir me livrar do DAO. Sempre que inicio um novo projeto, fico com a mania de ficar prevendo coisas do tipo “ah, vou usar DAO porque um dia pode ser que eu precise de uma outra forma de persistência que não seja um banco relacional”. Daí olho pra trás e vejo que isso é mais utopia do que realidade.

    Falando sobre o Hibernate, particularmente eu não gosto de annotations. Prefiro usar o mapeamento XML. Se for pra colocar annotations em minhas entidades, é melhor meter o EntityManager dentro delas e implementar ActiveRecord.

    Qual sua opinião a respeito disso?

  6. Tudo bem que coloque o DAO em todos os projetos. Afinal mais vale prevenir … Mas o seu DAO é realmente genérico ao ponto de poder ser subtituido mais tarde ? O seu DAO faz coisas como gerenciar estado ? Consultar metadados ? Será que vc conseguiria replicar isso para outra tecnologia de persistencia ? Afinal DAO não é só para mudar de banco de dados é para mudar de sistema de persistencia. Se no futuro o sistema de persistencia da moda for um outro o seu DAO pode ser modificado para trabalhar com isso ? O seu DAO foi constuido para durar quanto ?

    Eu particularmente acho ruim o ActiveRecord. Ele embute na entidade um conhecimento que não é dela. Tlv seja prático, mas na minha experiencia acho que está mais para anti-pattern. Tlv seja bom num sistema muito minusculo, tão minusculo que é irreal ou irrelevante. Se gosta dele use.
    Afinal programar e desenhar programas tb é uma arte. Eu não usaria.
    Eu tb prefiro um objeto que esconda a persistencia. Só que eu acho chato criar um objeto desses para cada entidade. Por isso o esquema de ter apenas uma interface para todas as entidades me agrada mais. E isso que o DomainStore faz.

  7. Fala sérgio, muito bom o artigo agora o seguinte neste cenário aqui por exemplo:

    class Action
    public UsuarioDao usuarioDao//É uma interface injetado via IOC(Inversao de Controle)

    class UsuariDaoImpl implements UsuarioDao
    private EntityManager entityManager;

    public Usuario getByLogin(String login) {
    Query query=createQuery(“Select * from usuario where login=?”);
    query.setParameter(1,login;
    return query.getSingleResult();
    }

    Eu trabalho deste jeito. Agora qual é a vantagem de se receber um QueryObject no lugar de login??

    E neste caso, o EntityManager seria o gerenciador de persistencia, ou seja agregaria funcionalidades ao DAO sem perder a flexibilidade, agora quem seria o gerenciador de estado??

    Obrigado!

  8. Isso que você usa é um DAO que sabe demais. Ele não apenas faz as pesquisas ele ainda sabe como as criar. Deste ponto de vista ele não precisa receber um query objet porque é ele mesmo que determina que pesquisas fazer. Ele apenas precisa dos parâmetros para a pesquisa. No seu caso a vantagem de usar QueryObject não existe.
    Este seu DAO é na realidade um Repositório e não um DAO. Você não tem DAO nessa estrutura. Você tem um Repositorio e um DomainStore que é o EntityManager do JPA. Se trocar a nomenclatura para repositório estará 100%.

  9. Olá sérgio obrigado pelas respostas; O que eu não entendi e o seguinte então o que caracteriza o Dao, olhe este modelo e diga o que acha:

    public interface Dao {
    public T getById(Serializable id) throws DAOException;
    public Object getByCampo(Object campo, Object value) throws DAOException;
    public void save(T entidade) throws DAOException;
    public void update(T entidade) throws DAOException;
    public void delete(Serializable id) throws DAOException;
    public List findAll() throws DAOException;
    public List find(final Integer primeiro, final Integer maxino) throws DAOException;
    }
    public abstract class AbstractDao implements Dao{
    private EntityManager em;

    public void save(T entidade) throws DAOException, EntityExistsException {
    try{
    getEm().persist(entidade);
    getEm().flush();
    }catch (EntityExistsException e) {
    throw new ConstraintViolationDAOException(e.getMessage(),e);
    }catch (Exception e) {
    throw new DAOException(e.getMessage(),e);
    }
    }

    public void update(T entidade) throws DAOException {
    try{
    getEm().merge(entidade);
    getEm().flush();
    }catch (Exception e) {
    throw new DAOException(e.getMessage(),e);
    }
    }

    Ai quado quero criar um Dao faço assim:

    interface UsuarioDao extends Dao;

    //aqui defino metodos exclusivos de usuario
    //como este

    public Usuario getByLogin(String login) throws DaoException;{}

    E depois a implementacao

    public UsuarioDaoImpl extends AbstractDao implements UsuarioDao {

    Query query=createQuery(”Select * from usuario where login=?”);
    query.setParameter(1,login;
    return query.getSingleResult();

    }

    Quais seriam os erros neste jeito de trabalhar, e isso não seria um DAo seria um repositório???

    Obrigado novamente

  10. O que caracteriza o DAO é a sua responsabilidade não a sua interface. A interface decorre da responsabilidade. Lá porque um objeto tem um save ou um find isso não faz dele um DAO. O que faz dele um DAO é ser capaza de mapear objetos para API de perssistencia. O que faz dele um DAO corretamente implementado é que os objetos que ele recebe não podem depender da API de persistencia de nenhuma forma. Esse código que mostrou está realmente mais para Repositorio mutável do que para DAO. (veja o artigo sobre o padrão Repositorio) Entenda que se vc usa EntityManager o objeto que o encapsula nunca será um DAO, já que o EntityManager é um DomainStore ( que é maior que um DAO).

  11. Bem relevantes as questões levantadas. Gostaria de levantar outras questões também.
    O que o Martin Fowler chama de Repository, no meu entender é uma forma bem sofisticada de nomear um Data Access Object (a grosso modo), porque está levando em consideração uma camada existente, complexa, que sabe fazer acesso a DBMS (e muitas outras tarefas bem sofisticadas, como sabemos) – essencialmente, é um acesso indireto.
    Na prática, temos que fazer uma consulta nessa camada, que tem sua linguagem específica, e quando penso em DAO, prefiro não pensar no quem tem abaixo, se é uma camada ultra-sofisticada, arquivo sequencial, DMBS, ou o resultado de uma transação de baixa plataforma.
    Somando a isso, que na prática, em muitos casos bem particulares, que ocorrem com frequência, acabamos preferindo não utilizar o Hibernate – por questão de performance e produtividade – sobretudo para a construção de relatórios. Por exemplo, gastamos 4 horas para construir uma consulta SQL, ANSI. Se o programador for traduzir para o HQL, vai levar mais um bom tempo, se conseguir traaduzir, e ainda assim o desempenho do relatório vai ficar horrível. Eu não vejo a necessidade de separar o feijão com arroz do Hibernate com uma consulta dessa, por exemplo, pois a responsabilidade de recuperar a informação, não muda, parece ser somente uma questão de nomenclatura, sendo que essa classe está no mesmo domínio do negócio no que se refere a recuperação de informação (tipo “Transações de Transfência”). O que você acha disso? As responsabilidades são diferentes? Deveriam ficar em classes separadas?
    Um abraço.

  12. O fato de usar um SQL manual para otimizar o processo significa, para começo de conversa, que você precisa separar “pesquisa” de “edição”. O Repositório tem por objetivo fornecer métodos de pesquisa. A edição é irrelevante numa primeira aproximação. O Repositório contém pesquisas, contém formas especiais, otimizadas, particulares de pesquisa que só podem ser escritas com base no conhecimento do domínio. Por isso o Repositório é um objeto do domínio enquanto o DAO e o Domain Store não são. Não há como dizer que os três são a mesma coisa. Cada uma é diferente do outro.
    Se você tem uma Repositório usando Hibernate por baixo dos panos mas têm uma pesquisas particular escrita à mão que não usa o Hibernate onde você escreve esse SQL ? Em um DAO ? Não. Em um Repositório. O DAO não é um objeto do domínio e portanto não tem conhecimento para criar uma pesquisas especial. Lembre-se : o DAO é apenas um burro de carga. “burro” significa que ele não sabe o que carrega. Ele apenas carrega.
    Com o repositório você cria um método de pesquisas otimizado facilmente. Basta criar um método e comunicar o seu SQL especial via JDBC ou qualquer outra técnica que usar apropriada. Enfim, o Repositório pode usar mais do que um método de acesso a dados. Você pode isolar a comunicação JDBC em outra classe separada do repositório, se quiser, mas isso não é vital a menos que pense em reaproveitar o código. Sendo que é um SQL especifico é quase impossível que o reaproveite, mas podem existir outras razões técnicas para isso como por exemplo o controle de transação.

  13. Olá ressucitando um tópico antigo, como você já me disse em posts anteriorres no GUJ, o EntityManager é um DomainStore por isso não posso encapsula-lo em um DAO, já que ele tem funções que o DAO.
    A session do hibernate tbm seria um DomainStore já que ele possui até mais funcionalidades que o EntityManager.

    Então em um bean que precisa de CRUD simples, eu posso colocar a Session diretamente na action e persistir no Banco certo.

    Agora se eu precisar de um metodo mais especifico coloco ele no repositorio correto, agora a minha dúvida eh o seguinte o que entao ira implementar o repositório?, Já que o mesmo eh uma interface, ou no máximo uma classe abstsrata.

    Obrigado

  14. O Domain Store é um elemento entre a camada de persistencia e a de dominio. Ele é um componente persistente com informações das relações do modelo de dominio. (veja Arquitetura Orientada a Dominio para uma ilustração). Portanto, o domainstore deve ser acessado pelo dominio, não pela action. É o repositório, que é um elemento do domínio, que media a action e o domainstore. Sem ele vc teria uma “violação de camada” em que a camada superior acessa a inferior sem passar pela do meio. Métodos de crud podem ser adicionados ao repositorio tornando-o um repositorio editável (veja Repositorio para detalhes).
    Todos os repositório editável compatilham uma interface para guardar as instancias das entidades (save) e outros métodos como findByID , por exemplo.
    Vc pode ter um repositório agnóstico – que não depende da entidade – (implementação de Template Method) que vc usa com todas as entidades já que o DomainStore subjacente também é genérico por natureza. Uma peça importante é um objeto implementando o padrão Registry onde vc registra os repositorios ( no inicio da aplicação) e os chama conforme necessário. Desta forma vc pode começar por usar o repositorio agnostico para os métodos crud básicos ( que se limitam a save() e delete()). Se precisa de alguam coisa especial (por exemplo, findAllActiveProducts) vc implementa um repositorio especifico para a entidade ( Product) com os métodos que quer mas herda do repositório agnostico para aproveitar os métodos crud ( que pode sobreescrever se necessário)
    Moral da historia: sempre use o repositorio. Sempre faça o action acessar um repositorio (para leitura) ou um serviço. (leitura/edição). Nunca atropele as camadas. Se precisar atropelar as camadas por questões de eficiencia use o padrão Fastlane.

  15. Olá Sérgio obrigado pelas respostas, então neste caso sempre usarei o Repository para leitura e Service p leitura/edição embora na maioria das vezes ele atue como um delegador de camadas, é interessante nao atropelar as camadas permitindo escabilidade ao sistema.
    Mas ai surge outra dúvida no Repository estaria encapsulado o que? Uma session/EntityManager deste jeito:


    class Repository{
    private Session session;
    private Class persistece;

    public add(T object){
    session.save(object);
    }
    public List findAll() {
    return session.createCriteria(perssistenceClass).list();
    }
    }
    }

    É correta esta abordagem, ou o Repository seria uma interface que seria implementado por um Dao??

    Além disso achei interessante o padrão FastLane, mas como eu poderia utilizá-lo com o Hibernate??

    Obrigado

  16. O Repositório não é uma interface porque ele não é um mero contrato. Ele tem responsabilidades bem definidas e como tal deve ser uma classe. Você pode ter um repositorio abstrato pai de todos os outros (padrão LayerSuperType e/ou Template Method) mas não faz sentido um repositório ser uma simples interface. Classes definem o que o objeto é, enquanto interfaces definem como o objeto se comporta. A razão mais forte para que o respositorio seja uma classe é que vc está definindo um elemento do domínio, vc está definindo que ele é um repositório, não apenas que ele se comporta como um.
    Por outro lado, não faz sentido ter um interface porque a classe não irá mudar. Isso faz sentido por exemplo para um serviço, em que se espera que a implementação mude com o tempo ( por exemplo, de POJO para EJB) mas um repositório tem uma responsabilidade tão sua que se alguma coisa mudar o repositorio como um todo mudaria. Ou seja, vc mudaria a interface e a implementação. Isso mostra que não ha um real desacoplamento. Entenda que isto é bem diferente do DAO comum. O DAO é um objeto de serviço , os seus métodos são serviços e por isso ele é definido como uma interface porque é esperado que a sua implementação mude. A implementação mudará sem mudar a interface (i.e. o contrato do serviço).
    Ou seja, o repositório não é um serviço ( tal como uma entidade não é) ao contrário do DAO que é um serviço ( da camada de persistencia). Simplesmente não faz sentido um Repositorio ser uma interface implementada em um DAO. Isso é o mesmo que dizer que você está chamando “Repositorio” à interface do DAO e “DAO” à implementação do DAO. Simplesmente confuso e contrário ao objetivo dos dois padrões.
    (por outra palavras: um reposiotório nunca será um DAO e vice-versa. Um repositório tem 1 DAO. É uma relação de composição, não de herança ou implementação)

    Internamente o Repositório usa o sistema de preservação de dados que ele bem entender. Usar um EntityManager ou um Session? claro. Sem problema. Só ha uma regra: O repositório não pode controlar a transação. Isso é porque em uma transação mais do que um repositório pode estar envolvido e se cada uma fizer a sua própria transação não existirá transação global.

    O padrão Fastlane serve para fazer um atalho entre as camadas sem ferir a separação de camadas. Vc poderia usar com o hibernate mas não faz muito sentido já que o hibernate sempre cria os objetos por si. Vc não tem controle sobre quando e onde criar o objeto. O Fastlane é tipicamente usado em coisas read-only como reports onde muitos objetos são necessários (mais do que o hibernate aguentaria) Ele normalmente usar o ResultSet diretamente para não ter um hoverhead de copia e criação de objetos. Ele cria o objeto (um só) quando precisa (just-in-time).

  17. E no meu caso que preciso persistir um tipo imagem, por exemplo? Um jpg? Digamos que tenha um objeto Pessoa qualquer que tem um atributo chamado foto do tipo File. Como que um produto qualquer de persistência que implementaria o DAO poderia perceber que estaria lidando com um arquivo?

    1. Para começar é uma má ideia persistir imagens em banco de dados , normalmente guarda-se uma caminho relativo.
      Mas se vc quiser mesmo fazer isso vc vai usar um Blob do JDBC ou a API especificado driver que estiver usando para enviar a foto.
      O DAO faz esse meio de campo. Ele recebe o File e traduz para o Blob, por exemplo. É exactamente para esse tipo de coisas que o DAO serve. Ah! e ele não vai perceber que é uma arquivo, vc vai lhe dizer isso. Ou seja, vc vai programar essa logica dentro do DAO.

      1. Entendi. Então o que posso fazer tbém é não encaminhar esse arquivo para o DAO e gravar ele em um caminho relativo na camada de negócio mesmo, certo?

      2. Sim. Você deve criar um objecto que contém esse tipo de logica de negocio. Normalmente este objecto é chamado de Serviço. Em EJB é chamado de Session Bean.
        A caracteristica principal do serviço é que ele sabe fazer coisas que apenas são relevantes para o negocio ou para a aplicação. Ele é normalmente composto de uma interface ( o contrato do serviço) e uma ou mais implementações. Embora esta arquitetura seja semelhante à do DAO a responsabiidade é bem diferente. U mserviço pode chamar outro serviço, por exemplo.

      3. Sérgio,

        acho muito interessante seus artigos, mas gostaria de questionar 2 pontos:

        1) Faz até sentido o que você disse que os repositórios não são uma interface, mas uma classe, já que eles não se restrigem apenas em definir a interface de um contrato. Entretanto, sendo o repositório um objeto do domínio, achei um tanto quanto estranha o seu exemplo de código de um Repositorio (do seu artigo sobre esse assunto) com tanta dependencia de código de infraestrutura (DAO, ResultSets e código SQL).

        Você pode me dizer, como vi você mencionar em um post do GUJ, que o fato de uma entidade ter um atributo do tipo Map ou HashMap, por exemplo, também seria um exemplo de uma entidade do dominio dependendo de código infraestrutura.

        Acredito que não dá para comparar esses 2 exemplos já que eles estão em níveis de abstração muito diferentes.

        Mas enfim, se os repositórios deveriam ser uma classe como você preconiza, então porque na aplicação que está no site domaindrivendesign.com (ddd-sample) os repositórios são definidos como INTERFACES ?

        2) Em uma das respostas você diz que: “Moral da historia: sempre use o repositorio. Sempre faça o action acessar um repositorio (para leitura) ou um serviço. (leitura/edição).”

        Na verdade, a razão de ser e de existir um serviço (nos moldes de DDD) não seria para realizar a implementação de uma regra de negócio que envolva mais de 1 entidade, as quais por si só não conseguiriam executar/implementar a regra sem uma orquestração ?

        Se você concorda com o que eu disse, então por que motivo eu preciso criar um serviço para leitura/edição de uma entidade?

        []s,
        Marcos Urata

      4. Primeiro é preciso deixar claro que o uso das palavras “dominio” e “repositório” não significa que estou usando DDD. Logo, não importa para a discussão o que os mentores do DDD têm a dizer sobre o assunto em causa. Repositório é um padrão de projeto muito bem definido que visa encapsular a criação de critérios de pesquisa. O nome “Repositorio” advém do nome dado a esse padrão pelo Martin Fowler. Historicamente esse padrão foi identificado em separado do advento do DDD. O padrão Service também não foi inventado pelo DDD. O padrão de ter um contrato (interface) e uma implementação ou mais é comum. Jini , JMX, EJB são exemplo de tecnologias que usam esse padrão ha anos.
        O termo “dominio” também é de uso geral embora popularizado pelo DDD. Mas se você ler com atenção o material do DDD você vai descobrir que é uma extensão do MDD em que o modelo é o mais importante. O modelo é o resultado da abstração e modelagem do quê ? Alguns dirão que “do negocio” mas isso não é correto. A resposta é “do dominio”. O dominio é subconjunto das regras de negocio que podem ser escritas em codigo e embutidas no software. São a parte “mecanica” do negocio e ao mesmo tempo a parte mais abstrata.

        Dito isto, é preciso compreender o papel o Repositorio no dominio. O seu papel é simples : encontrar instancias de entidades com base em critérios especifios. Temos o classico findById que é mais uma pesquisa de sistema do que de negocio, mas temos outro classico melhor findAllActive(). A classe que invoca estes métodos no repositorio não sabe e não precisa saber como a pesquisa é feita nem onde as instancias estão. Até onde ela sabe nada impede que as instancias sejam todas criadas on demand e na memoria.
        Assim o repositorio representa o isolamento da aplicação e do dominio em particular em relação ao local onde as instancias estão e dos mecanismos que permitem encontrá-las dado um certo critério.
        Por outro lado, todas as classes têm que ter uma implementação. Para a implementação do Repositorio não existem regras especiais e o programador é livre de invocar as camadas que quiser desde que sejam inferiores o no mesmo nivel (um repositorio pode invocar outros repositorios) Então, aqui vc usa o que mais gostar. O uso de SQL direto com JDBC seria a forma mais direta. É claro que é a forma menos flexivel a longo prazo mas isso é uma escolha – um trade off – e não uma diretiva ou um padrão. Se vc quiser usar JPA , JDO, Hibernate, Google BigTable é com você e depende das necessidades e requisitos da sua aplicação ( aplicação, não do dominio em si)
        Portanto, não ha estranheza nenhuma em usar SQL. É apenas um exemplo do que é possivel fazer.

        O repositorio serve para encontrar instancias de entidades. Normalmente que precisa fazer isso são outras entidades , serviços e outras classes da aplicação como os actions. Uma operação readonly não precisa passar por um serviço (embora possa se assim vc quiser, se por exemplo, vc precisa de fazer a leitura transacionalmente). Por isso vc pode chamar o repositorio diretamente da action. Caso contrário o seu serviço será apenas um decorador do repositorio sem qualquer outro proposito.

        O serviço (no sentido generico) pode fazer qualquer coisa. Desde de implementar regras de negocio, até orquestrar (no caso é um Façade) até simplesmente garantir consistência transacional e validação de segurança.
        Porque os serviços podem ser compostos (padrão Composite) ou como se diz hoje “orquestrados” é possivel montar um serviço complexo a partir de serviços mais simples.
        Contudo, repare que tudo isso só faz sentido para operação de escrita (ou leitura transacional). Para leitura “bulk” isso é pesado e sem significado. Claro, tb aqui é uma questão de trade-off. Se você quiser que todas as invocações do action passem por um serviço, ok, vc pode fazer isso. O ponto da conversa é que : um action não manipula entidades. Ele sempre delega para outros objetos. E esses objetos só podem ser de dois tipos : serviços e repositorios.

        De você de distanciar do DDD e olhar os padrões e conceitos por si próprio você vai entende melhor. Leia este post onde eu falo sobre isso.

      5. Sérgio,

        li o seu outro artigo e pra mim ficou bem claro que o objetivo de um Repositorio tanto no contexto de DDD quanto fora dele, o objetivo é abstrair do cliente “como” e “onde” os dados são acessados e estão armazenados – como você mesmo diz, tudo isso se resume nos conceitos básicos de OO, que no caso é encapsulamento.

        Logo, se o objetivo de um Repositorio é esse (abstração), novamente na minha opinião, não faz sentido o repositorio ser uma classe concreta, como você demonstrou no seu código de exemplo.

        Você mesmo menciona que a idéia de um repositório é ser uma abstração no seu post “existe vida fora de DDD”:
        “Mas sem o repositório, como eu isolo o domínio de, por exemplo, a infraestrutura? A resposta é: não isolo. Se fosse possível, o Repositório não seria mencionado na literatura (dah!). E eu quero isolar? sim”

        Acho que na verdade, todo aquele código JDBC não tem que ficar no Repositório, mas ser injetado como uma possivel implementação da interface do Repositório, seja via padrão Strategy (como mencionado no livro do Fowler, neste caso o Repositório seria uma classe, mas abstrata), seja definindo o Repositório como uma interface, sendo JDBC uma possível implementação desta interface.

        []s,
        Marcos Urata

      6. O como o Repositorio processa a invocação do método não faz parte do dominio e desse ponto de vista parece pertencer a infra, contudo, as regras utilizadas enquanto se processa a invocação sim são dependentes do dominio, e assim, não parece mais pertencer à infra.

        O ponto é que um repositorio só tem uma forma. Se vc tiver o repositorio como interface vc está dizendo que podem haver várias implementações simultaneas e intercambeáveis. Isso não faz sentido porque isso significaria que as regras do dominio mudaram. Mas se mudaram, elas substituiram as antigas que não mais serão usadas. Agora, isso me impede ter uma interface Repositorio ? tecnicamente não, já que vc poder um framework onde essa é a abstração principal e depois vc escreve um ClienteRepositorio. Quando eu falo que o repositorio não pode ser uma interface estou-me referinfo a este clienteReposiotorio, porque é este que contém regras de negocio e não a interface Repositorio. Ou seja, o que é errado é vc definir um ClienteRepositorio como uma interface. ( mesmo assim ainda seria duvidoso definir o repositorio abstrato como interface por isso permite implementação por algo que não seja um repositorio. Então, no máximo da abstração um Repositório é apenas uma classe abstrata. Nunca uma interface.)

        Você tb não pode usar o argumento de acesso a banco como desculpa para ter uma interface porque se vc está pensando em ter vários bancos o que tem que ser uma interface é o acesso ao banco e não o seu repositorio. Ai vc usa um DAO ( que se define por uma interface) ou algum tipo de strategy de repositorio que pode ou não delegar a um DAO. Ou vc usa um domain store como o Hibernate ou o JPA ou algum outro mecanismo que isole o banco de forma plugável.
        Ou seja, é a camada abaixo do repositorio que terá “chaveada” através de uma interface e não o repositorio ele mesmo. Para conseguir isso existem outro padrões que têm que se utilizados como o Repositorio que são o QueryObject e o Interpreter. O que vc faz, na realidade, é definir uma API de QueryObject e uma interface de interpreter. O repositorio escreve as pesquisas nessa linguagem/API (genérica e agnostica) e passa ao intepretador. O intepretador traduz isso para alguma tecnologia , invoca, e retorna o resultado da pesquisa de forma genérica e agnostica (inependente do dominio e dos seus objetos e classes). O reposiotrio então traduz esse resultado para os objetos do dominio que ele conhece. Esta é a mecanica de um repositorio. Contudo, na realidade, ninguem quer ter esse trabalho de criar uma API de QueryObject e intrepretador e usa uma já existente como o Hibernate ou JPA.

        No projeto MiddleHeaven estou exactamente desenvolvendo essa API de QueryObject e interpretador para que a tecnologia de persisencia/pesquisa seja totamente isolada e o Repositório não depende em nada, disso.

  18. sergiotaborda

    olá…
    o post é antigo…
    ainda hj usa-se domainstore ?!

    tenho algumas dúvidas quanto ao uso…
    domainstore faz parte da infra ou do dominio?!

    e realmente não consigo entender, qual o papel do domainstore?!

    no forum guj vc disse:
    “…DomainStore : objecto responsável por toda a persistencia do dominio (o nome diz tudo). Ele utiliza DAO por baixo dos panos mas o cliente não os vê.
    É um domainstore por dominio. …”

    fazer a persistencia não é função do dao?!

    uaaaau… minha cabeça deu um nó!

    1. O domainstore faz parte da infra pois é o mesmo em todas as aplicacoes.o hibernate é uma implementacao deste padrao, o entiymanager do jee é outra. Então, sim, ainda se usa. O domainstore funciona pelo uso de um domain model (Metamodel pattern) que é normalmente derivado de annotations. a comunicao ao banco de dados é feita internamente à implementacão e normalmente não se ve, mas se se visse seria parecido com o padrao dao. Se vc ainda usa DAO, é melhor correr para aprender o o que é um Repositorio e um DomainStore 🙂

      1. Pode mas muito melhor usar o domainstore. O dao é um padrão do passado. Esqueça-o.

  19. mas como fazer o domainstore “pegar” o mapeamento da classe?!
    o domainstore vai ter que conhecer todas as classes que possuem mapeamento?!
    ou eu passo para o domainstore?!

    nossa… está tao confuso que acho que nem a pergunta ficou ok!

    valeu!

    abrs

    1. O domainstore nao conhece as classes. Ele usa um objecto chamado domain model. Este objeto é criado previamente e passado ao domainstore no seu construtor. O domain model por sua vez é um conjunto de metadados das entidades. Nomes. Tipos, etc. Estes objetos sao criados como vc quiser. Apartir de anotacoes, Xml ou ate na mao.nao importa.

  20. o domainstore fará somente a persistencia?!
    o domain model, é criado onde?! num service ou num repository?!

    posso entender o domainstore como sendo um dao genérico?!

    valeu

    1. Sim, o domainStore só faz a persistência (Store) o domain model é criado onde vc quiser. normalmente apenas uma vez no inicio do sistema e depois injetado onde necessário.
      Não faz muito sentido criá-lo num serviço ou nem repositorio pois tem que ser ciado apenas 1 para todo o sistema.

      O Domain Store não é um DAO genérico.

      Veja http://www.corej2eepatterns.com/DomainStore.htm e compara com http://www.oracle.com/technetwork/java/dataaccessobject-138824.html
      É bem diferente. O DAO é algo que vc cria manualmente para cada aplicação. O DomainStore é uma tecnologia que vc reaproveita em diferentes sistemas, pois ele não muda.

      dê uma olhada neste outro artigo para ver se ajuda.

      1. sergiotaborda,
        obrigado pelas respostas.

        public interface DomainStore {

        public E save(E instance);
        public void delete(E instance);
        public QueryResult query(Criteria criteria);
        }

        o domainstore acima peguei do site que vc mencionou…
        o save seria algo como

        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
        session.saveOrUpdate(instance);
        session.getTransaction().commit();
        session.close();

        obrigado…

        abrs

Deixe um comentário