Repository

Repository

Este texto foi atualizado e doado ao projeto Code Design World

Repository(Repositório) é um padrão de projeto que visa mediar a pesquisa de objetos de dominio entre a camada de dominio e a camada de mapeamento de dados usando uma interface semelhante à de uma coleção[1].

Para a camada de dominio parece que estamos filtrando uma coleção em memoria. Para a camada de mapeamento estamos fornecendo uma frase de pesquisa que ela entende. No meio libertamos a camada de dominio de saber como fazer pesquisas na camada de mapeamento e ganhamos um local centralizado para modificar a tradução entre as duas camadas.

O problema

É comum em um sistema de complexidade média ou grande utilizar algum mecanismo de mapeamento de dados. Este mecanismo visa minimizar a impedância que existe entre o modelo de dados traduzido num conjunto de objetos Java e o mesmo modelo de dados traduzido numa forma inerante ao mecanismo de persistencia usado pela aplicação (normalmente um banco de dados). Uma das operações mais comumns neste cenário é necessitar consultar os dados com base em algum critério. Essa pesquisa é normalmente descrita numa linguagem própria ao mecanismo de mapeamento. 1 Neste cenário é interessante isolar a criação das consultas criando uma camada extra e deixando o resto da aplicação especificar as consultas de forma genérica e sem associação ao mecanismo de mapeamento.

A solução

O padrão propõe que se utilize um objecto como intermediário entre a camada de dominio e a camada de mapeamento de dados. Este objeto recebe especificações das pesquisas, na forma de objetos e as traduz para a camada de mapeamento na forma prescrita por pelo mecanismo de mapeamento. A vantagem é que o dominio especifica essas pesquisas como se os dados estivessem em memoria numa coleção gigante isolando o dominio de saber exactamente onde estãos os dados e como a pesquisa se processa.

Como funciona

O objeto Repository tem uma interface simples. Ele recebe um objeto com a especificação da pesquisa e retorna uma coleção com os objetos de dominio que satisfazem essa pesquisa. A especificação é um objeto. Qualquer objeto pode ser usado, mas o ideal é utilizar o padrão Query Object. (Do ponto de vista do padrão Query Object o Repository atua como um intrepretador da especifiação.

O objeto Repository pode ainda ser mais inteligente preocupando-se menos com a camada de mapeamento com quem conversa ao fazer uso do padrão Strategy. Cada estratégia representa uma forma diferente de mapeamento com que o repositorio pode conversar. Por exemplo, podemos pensar num mecanismo realmente presente em memoria (ideal para fases de teste), ou num mecanismo presente num banco de dados (para a fase de produção).

Neste momento poderá estar pensando que essa estratégia é equivalente a uma implementação do padrão Data Access Object (DAO). Para ficar mais claro imaginemos que o mapeamento é entre objetos java e um banco de dados que suporta SQL. Enquanto o DAO apresenta métodos simplificados para inserir , apagar e atualizar dados ele ainda receberia instruções em SQL para retornar os registros no banco de dados. O Repository tem então duas funções:

  • Traduzir a especificação de pesquisa enviada pela camada de dominio para uma frase SQL e passar essa frase ao DAO
  • Converter os dados retornados pela pesquisa em objetos de dominio

Estes objetivos parecem simples o suficiente para serem deixados a cargo da camada de aplicação mas sua complexidade pode aumentar rápidamente conforme o modelo de dominio evolui. Por outro lado quando o mecanismo de mapeamento não for com um banco de dados, a linguagem SQL será inutil. Podemos pensar, por exemplo que o DAO usa a linguagem EQL ou HQL para fazer as pesquisas, ou sequer usa uma linguagem; apenas um objeto especifico (como o Criteria do Hibernate).
Quando existir a necessidade de comunicar com uma camada de mapemanento diferente que usa uma linguagem diferente teriamos que construir um outro repositorio para responder às mesmas especificações de pesquisa do dominio. É aqui que o padrão Strategy brilha mantendo um único objeto com quem o dominio tem que conversar mas ampliando os tipos de camadas de mapeamento com quem o repositorio pode se entender.

Repositório’ Editável

O papel principal de um Repository é ser um tradutor de pesquisas , mas podemos aumentar a sua responsabilidade um pouco mais. Na presenta de uma camada de mapeamento pesquisar não é a única tarefa delegada a ela pela camada de dominio. Tarefas como inserir e apagar também são importantes. Por outro lado, se o repositorio é visto pela camada de dominio como uma coleção em memoria como essa coleção é alterada ?

Se a camada de dominio utiliza directamente a camada de mapeamento para operações de edição dos dados e o repositorio para operações de pesquisa existem dois pesos e duas medidas. Ou bem que tratamos todas as operações CRUD directamente com a camada de mapeamento, ou bem que não. Fazer isso algumas vezes e não outras introduz uma incoerencia na dependencia das camadas que rápidamente se torna o tendão de Aquiles quando o modelo de dominio aumentar , se tornar mais complexo, ou simplesmente mudar.

Baseado nisto o Repository deve também concentrar a interface para edição da coleção de dados que ele representa. Na realidade ele apenas delegará ao mecanismo na camada de mapeamento para os casos mais simples, mas promove um ponto de entrada para traduzir os dados do dominio para a camada de mapemaneto se for necessário. (Veja o padrão Money para um exemplo onde isso pode ser necessário)

Relação com outros padrões

Já vimos que o Repository se relaciona com outros padrões como Query Object e Specification. E que ele pode ainda ser visto como uma especialização de Interpreter. No caso do repositorio mutável ele pode ainda ser visto como uma especilização do padrão Façade já que isola totalmente as camadas superiores das inferiores.

Referências

[1] Patterns of Entreprise Application Architecture
Martin Fowler et al.
URL: http://www.martinfowler.com
[2] Design Patterns: Elements of Reusable Object-Oriented Software
Gamma et al.
URL:
[3] Repository
JabaBuilding
URL: http://www.javabuilding.com/academy/patterns/repository.html

Licença

Creative Commons License Sérgio 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 .

34 opiniões sobre “Repository”

  1. Olá Sérgio

    Antes de mais nada, parabéns pelo excelente artigo.

    Segundo o texto, originalmente não é responsabilidade do repositório cuidar da persistência dos dados, e sim, apenas de sua recuperação. Vamos supor que eu esteja usando Hibernate em minha aplicação, persistindo as entidades através de um objeto Session.

    Conceitualmente falando, há algum problema em persistir os objetos usando o Session diretamente da camada de aplicação? Caso haja, como remediar essa situação: criando um Service para fazer isso ou migrando a lógica de persistência para dentro do repositório (o qual chamaria o Session diretamente, e seria acessado pela camada de aplicação)?

    Abraços

  2. Conceptualmente falando,depende do que vc considerar que o Hibernate é.

    Eu considero que ele é parte da infraestrutura. Desse ponto de vista o session pode ser chamado da aplicação diretamente. Se considerar o Hibernate como umas das possiveis estratégias de persistencia, vc precisa de outro objeto para mediar a estratégia, logo, desse ponto de vista não é correto chamar o hibernate diretamente da aplicação.

    Caso você necessite desse novo objeto do qual o Hibernate é apenas uma estratégia possivel esse objeto pertence também na infra. Desse ponto de vista ele não é um repositorio já que repositorios pertencem no dominio.

    Na realidade esse objeto que media com o hibernate é uma instancia do padrão Bridge ( o mesmo usando pelo JDBC) em que vc tem interfaces dos objetos que quer manipular mas não as suas implementação. No JDBC temos o driver que implementa a logica que executamos usando Connection e ResultSet que são apenas contratos que o driver entender.

    Para isolar completamente o sistema do uso do Hibernate vc precisa de:
    Centralizador de Persistencia: qualquer nome serve. PersistenceManager, ou PersistenceService, etc.. ele é na realidade uma implementação do padrão Bridge ( o mesmo que o JDBC usa).
    Mecanismo de query independente do hibernate: aqui vc pode usar o Repository (com ou sem QueryObject de dominio) + QueryObject compativel com o seu padrão Bridge acima.
    Mecanismo de transação: aqui vc pode usar o padrão UnitOfWork (uma classe que contém todas a logica que executa na transação. A transação é aberta antes e fechada depois) Com isto vc passa um POJO com a logica que quer executar para o PersistenceManager. A aplicação não tem que saber nada sobre a persistencia. Implementar UnitOfWork não é tão simples quanto parece. Vc precisa criar o conceito de contexto de trabalho ( semelhante a contexto de transação) programaticamente. É complexo, mas isola vc do Session do hibernate por completo.

  3. Opa sergio, ja tinha falando com vc via PM pelo forum do GUJ tentei fazer aquela implementação de Repositorio da forma que vc disse, porém tem algumas peculiaridades, e o processo não deu muito certo não…

    Vamo aos fatos…
    Ps.: essa mesmo texto eu te enviei por PM via o forum.

    ……..

    Tentei fazer como vc colocou, mais houve alguns problemas no código

    1° não, meu retorno é sempre o repositorio mais generico, eu nunca fico com os métodos da classe que eu extendi quando uso
    //...
    public static Repositorio getRepositorio(Class type){
    return repositories.get(type.getName());
    }
    //...

    tentei escrever um código generico como vc escreveu abaixo, o compilador ou o eclipse não aceitou
    //...
    public static Repository repositoryFor(Class type){
    return repositories.get(type.getName());
    }
    //..

    Como ficou minhas calsses

    Repositorio Abastrato => Repositorio
    public abstract class Repositorio {
    private Class type;
    public Repositorio (Class type){
    this.type = type;
    }

    protected Class getEntityType(){
    return type;
    }
    }

    Ps.: Não implementei os saves abstratos pq kero tratar as exceções aqui, mas vamo adiante

    Classe Repositorio para Cidades => RepositorioCidade
    public class RepositorioCidade extends Repositorio {

    public RepositorioCidade() {
    super(Cidade.class);
    }

    //O Nome esta saveCidade de proposito, é para ver c enxergaria ele mais a frente, o que não aconteceu
    public void saveCidade(Cidade cidade) throws Exception {
    CidadeHibernate.saveCidade(cidade);
    }
    }

    Ps.: Eu sei que é pra tirar o exception, li ate seu artigo sobre boas praticas com Excpetion, mas nesse momento quero resolver o problema do repositorio.

    Classe Repositorios (plurarl) => Repositorios
    public class Repositorios {
    private final static Map repositories = new TreeMap();

    static { // registra as classes certas
    repositories.put(Pessoa.class.getName(), new RepositorioPessoa());
    repositories.put(Cidade.class.getName(), new RepositorioCidade());
    }

    //Quero reinteirar que não foi possivel fazer => public static Repository repositoryFor(Class type)
    public static Repositorio getRepositorio(Class type){
    return repositories.get(type.getName());
    }
    }

    Enfim, na pratica quando faço
    Repositorio rep = (RepositorioCidade)Repositorios.getRepositorio(Cidade.class);
    //Aqui esta o problema
    rep.saveCidade(cidade); //simplismente não existe saveCidade(Cidade cidade) no repositorio enviado =/ .... o q faço ????

    ……….

    Enfim, não estou conseguindo chamar os métodos do repositorio, o q esta errado ?? …. pq não consigo fazer um método geral ?? com ?? por favor me ajude … desde já agradeço

  4. tentei escrever um código generico como vc escreveu abaixo, o compilador ou o eclipse não aceitou

    Verifique a versão do java que está usando suporta generics (1.5 ou 1.6) e que o projeto do eclipse está setado para usar essa versão (veja as propriedades do projeto em Java Compiler)

    A assinatura dos repositorios particulares fica assim

    public class RepositorioCidade extends Repositorio
    Os métodos não têm o nome da entidade proque são comuns a todas as entidades

    Por alguam razão estranha o wordpress barra o uso de sinais de menor e maior nos comentários então vou usar [] em vez

    public abstract class Repositorio[T] {
    private Class[T] type;
    public Repositorio (Class[T] type){
    this.type = type;
    }

    protected Class[T] getEntityType(){
    return type;
    }
    }

    public abstract save(T obj);
    public abstract delete(T obj);

    Enfim, na pratica quando faço
    Repositorio rep = (RepositorioCidade)Repositorios.getRepositorio(Cidade.class);
    //Aqui esta o problema
    rep.saveCidade(cidade); //simplismente não existe saveCidade(Cidade cidade) no repositorio enviado =/ …. o q faço ????

    Pois claro que não ha. Vc não definiu esse método na classe Repositorio.
    Vc tem que definir o método save(T) na classe repositorio.

    Depois vc implementa um HibernateRepository usando hibernate directamente e não chamando o DAO. e depois faz RepositorioCidade herdar de HibernateRepository.

    HibernateRepository implementa todos os métodos de Repositorio como save, delete, findByID , etc… os que são comuns a todas as entidades. Os métodos que são particulades da entidade ficam no repositorio dessa entidade. Por exemplo ,
    encontraTodasPorEstado(Estado estado) retorna as cidades de um determinado estado. Esta pesquisa é particular da entidade cidade e deve ser definida no repositório da cidade.

    Parece-me que o problema é mais com o uso de generics de com o repositorio em si.

  5. Opa sergio, obrigado pela resposta

    Obs.: apenas comentando, o worpress não libera o sinal de menor e maior pois eles delimitam tags HTML, e portanto são discartados pelos filstro das unicas tags abilitadas…

    Sobre o caso que te falei, o metodo encontraTodasPorEstado(Estado estado)que é particular de cidades não vai existir em Repositorio generico, e portanto não vai ter como invocalo sem converter Repositorio em um tipo (RepositorioCidade) ou estou enganado ??

    estou unsando o Eclipse com Java mias atual, ele aceito os tipos genericos sim, boa parte dos códigos enviado por vc foram aceitas, apenas aquele pequeno trecho não funcionou…

    quando subistitui T por ? , que vi em outro exemplo de um artigo seu, o compilador aceitou …

    mais meu problema mesmo vai estar em

    public encontrarTodasDoEstado(Estado estado)

    Método de RepositorioCidade que não esta definido em Repositorio generico… sendo assim

    Repositorio rep = Repositorios.getRepositorio(Cidade.class);
    rep.encontrarTodasDoEstado(goias);

    esse código acima não vai ser possivel, e vou ter q fazer referencia de RepositorioCidae diretamente…. sera que tem solução pra isso ?? … foi por isso que mandei no exemplo saveCidade() justamente pra exemplificar um caso particular, onde não vai esta definido no Repositorio Abstrato…

    agradeço a ajuda abraços

    Tomaz Lavieri

  6. Vc está certo que tem que ter acesso ao RepositorioCidade para poder usar o método encontraTodasDoEstado. Isso pode ser feito via casting, mas isso é “perigoso”
    Uma melhor forma é adicionar um método no seu Repositories assim:

    public static <E,T extends Repository> T repository(Class repositoryType){

    //o objeto real está no mapa class entidade->repositorio. Vc pode fazer outro mapa class_repositorio -> repositorio (mais rápido) ou vc pode iterar mapa.values() e procurar o objeto que implementa a class passada (mais lento)

    // assumindo que vc tem outro mapa repos Map<String, Repository> em que o string é o nome da classe do repositorio

    return repositoryType.cast(repos.get(repositoryType.getName()));
    }

    uso

    RepositorioCidade rep = Repositorios.repositorio(RepositorioCidade.class);
    rep.encontraTodasDoEstado(estado);

    é equivalente (mas mais seguro que)

    RepositorioCidade rep = (RepositorioCidade )Repositorios.repositoryFor(Cidade.class);
    rep.encontraTodasDoEstado(estado);

    Use a chamada ao repositorio padrão quando fizer operações padrão (save, delete, findByID, etc)… use a chamada directamente pelo repositorio dentro de serviços que necessitam usar a pesquisa especial.

  7. é não sei se entendi bem, mais pelo que entendi, no fim eu rodo rodo, e caio no mesmo problema, de ter q saber o Que se refere a cada coizinha =/ …

    pq entre fazer

    RepositorioCidade rep = Repositorios.repositorio(RepositorioCidade.class);

    e fazer … RepositorioCidade.encontraTodasDoEstado(estado);

    ou vc fala dessa RepositorioCidade ser uma interface ??

    pq meu problema é por ai…

    Eu acho qu deveria ser assim, vamo la…

    …………….

    Tenho uma entidade => “Estado”
    Tenho uma interface => “EstadoControle”
    Tenho uma realização => “EstadoControleHibernate”

    Como usar é o meu ponto… quando eu kero salva uma cidade tenho q fazer


    Estado saoPaulo = new Estado();
    cidade.setNome("São Paulo");
    cidade.setPais(brasil); //vamos abstrair com Brasil foi criado.

    controle.save(saoPaulo); //Aqui é o ponto

    Como invocar o controle ??? de preferencia com metodos estaticos ??

    fazer ControleEstado.save(saoPaulo) seria o ideal, porem isso é apenas uma interface, não tem como ser feito

    fazer ControleEstadoHiberante.save(saoPaulo) é pessimo, amarra de mais

    quero poder usar tb


    controle.getFromPais(brasil); // sendo este um método especifico

    …….

    Pelo que vc falou ali, eu ia recair sobre a implementação da interface, queria invocar através da interface direto, talvez eu não tenha intendido bem e ali esteja a solução… mais a forma facil pra mim seria algo como


    Controle<Estado> controle = RepositorioControles.get(Estado.class);
    controle.getFromPais(brasil);
    controle.getFromId(id);

    Enfim, pelo que vi, apenas com <Estado> não consigo acessar funções especificar de controle de 1 tipo de interface

    assim teria q fazer ControleEstado e saber o nome da interface para cada tipo de objeto, correto ??

    1. Quem raios é esse Controle ? Estamos falando de repositorios.

      RepositorioEstado rep= Repositorios.repositorio(RepositorioEstado.class);

      Estado minas = new Estado();
      minas.setNome(“Minas Gerais”);
      minas.setPais(brasil);

      rep.save(minas);

      List estados = rep.findAllForCountry(brasil);

      assertTrue(estados.contains(minas));

      Vc está usando os métodos estáticos de Repositorios para encontrar os repositorios certos.
      Lembre-se que dentro de Reposiotorios existe um codigo assim

      static {
      mapa.put(Estado.class.getName(), new RepositorioEstado());

      }

      Sem isto não funciona.

      Agora, é claro que vc pode obter o repositorio certo de outras formas usando um injetor de dependencia automático ou
      algo assim. Estou apenas lhe mostrando como usa os repositorios.

  8. Bom, posso estar errado, mais pra mim, existem um micro MVC na minha entidade…

    1° View … Interface que o usuario vai usar pra manipular as entidades

    2° Controle … Realização dessa interface, que implementa a conversa com o banco de dados e as entidades, para levar as informacoes através da interface para fora da micro MVC.

    3° Modelo … as entidades e o banco de dados.

    Posso estar engando, mais vejo assim… sendo assim, fiz os repositorios pra desacoplar melhor a VIEW (minhas interface com o acesso externo ao meu modelo, pra manipular as entidades e o banco de dados) do meu controle que sabe como receber as menssagens do usuario e passar elas pro modelo.

    …………

    Para exemplificar, ficou assim:

    View: package br.com.entidade
    Realizacoes (Gerente de realizações é um repositorio que contem os controles)
    Interfaces<T extends IPersistente> (Padrao para interfaces, onde o tipo precisa ser uma Entidade)
    InterfaceCidade (extends Interfaces)
    InterfaceEstado (extends Interfaces)
    InterfacePais (extends Interfaces)

    Controle: package br.com.entidade.control.hibernate
    HibernateControle<T> (implementa Interfaces<T>)
    HibernateControlePais (implementa IterfacePais)
    HibernateControleEstado (Implemeta InterfaceEstado)
    HibernateControleCidade (implementa InterfaceCidade)
    HibernateHelper (regras do hibernate)

    Modelo: package br.com.entidade.modelo
    IPersistente (Interface generico, apenas para garantir que é uma enteidade, sem métodos)
    Pais (Implementa IPersistente)
    Estado (Implementa IPersistente)
    Cidade (Implementa IPersistente)

    …..

    Exemplo de usu:

    InterfaceCidade iCidade = Realizacoes.getRealizacao(Cidade.class);
    List lista = iCidade.findAll();

    InterfaceEstado iEstado = Realizacoes.getRealizacao(Estado.class);
    Estado saoPaulo = iEstado.getFromNome("São Paulo");

    Cidade santos = iCidade.getNew("Santos", saoPaulo);
    Cidade campinas = iCidade.getNew();
    campinas.setNome("Campinas");
    campinas.setEstado(saoPaulo);

    iCidade.beginTransaction();
    iCidade.save(santos);
    iCidade.save(campinas);
    iCidade.commitTransaction();

    List lista2 = iCidade.findFrom(saoPaulo);

    Note que não há uso de nada que esta em “C” (controle) do meu micro MVC … assim acredito que ficou bom.

    aguardo opiniões

  9. MVC é um padrão para camadas. Veja o link no blog. O padrão conta com 4 coisas : view, modelo, controlador e sistema de eventos.

    O que vc criou não é um MVC. É sopercomplicar as coisas.
    A menos que tudo isso tenha um objectivo claro, vc está exagerando no nivel de separação e criando responsabilidades que não existem.
    Por outro lado parece-me que está tentando usar algo tipo um ActiveRecord e tlv por isso vc acha que a entidade é um view. Simplesmente desista dessa ideia. Use objetos de entidade simples. Classes simples com get/set para os atributos e pronto. O repositorio para guardar e recuperar esses objetos. E classes de serviço para as opeações que o sistema deve fazer.

  10. Eu vi tudo isso sergio… aos poucos os conceitos estão se encaixando cada vez melhor… acho que finalmente absorvi …. repositorio é como se fosse 1 lista, uma coleção … algo totalmente orientado a objeto, os nomes não estavam legais, e eu troquei tudo, abstrai mais…

    so ficou 1 coisa de Banco de dados no meio, e não sei como resolver (Commit, Rollback)… fiz assim agora….

    ………

    /**
    * Repositorio especifico de uma entidade T, que precisa ter a assinatura
    * de IEntidade (Interface vazia, que só garante que se trata de uma entidade).
    * @author Tomaz Lavieri
    * @param <T>T<T> uma Entidade, que contém a assinatura da interface IEntidade
    * @see IEntidade
    */
    public interface RepositorioEntidades<T extends IEntidade> {
    public void add(T entidade);
    public void remove(T entidade);
    public void remove(Integer id);
    public void remove(Long id);
    public void remove(BigInteger id);
    public void replace(T entidade);
    public void retrive(T entidade);
    public T get(Integer id);
    public T get(Long id);
    public T get(BigInteger id);
    public List<T> list();
    }

    essa é minha a interface base para os repositorios de entidades… abaixo segue um repositorio especifico

    /**
    * Repositorio da entidade Cidade, que herda os métodos de RepositorioEntidade,
    * e é resposavel por guardar e recuperar as entidades do tipo Cidade, além de
    * conter métodos mais especificos
    * @author Tomaz Lavieri
    * @see RepositorioEntidade
    * @see Cidade
    * @see IEntidade
    */
    public interface RepositorioCidade extends RepositorioEntidade<Cidade>{
    public Cidade get(String nomeDaCidade);
    public List<Cidade> list(Estado estado);
    public List<Cidade> list(Pais pais);
    }

    ………..

    O meu problema esta no uso abaixo… quando preciso fazer tranzações…

    Pais pais = new Pais("Brasil");
    Estado estado = new Estado("Paraíba",pais);
    Cidade cidade = new Cidade("João Pessoa",estado);

    RepositorioPais repPais = Repositorios.getRepositorioDeEntidade(Pais.class);
    RepositorioEstado repEstado = Repositorios.getRepositorioDeEntidade(Estado.class);
    RepositorioCidade repCidade = Repositorios.getRepositorioDeEntidade(Cidade.class);

    //agora eu preciso fazer uma tranzação... qual a melhor forma de fazer ???

    //ta com muita cara de banco de dados a linha abaixo, tenho que mudar
    Repositorios.beginTransaction();
    try {
    repPais.add(pais);
    repEstado.add(estado);
    repCidade.add(cidade);
    Repositorios.commitTransaction();
    } catch (RepositorioRuntimeException rre) {
    Repositorios.rollbackTransaction();
    }

    Enfim, acredito que agora abstrai melhor o q seria o repositorio, e que ele é a fronteira de persistencia e o negocio, sendo assim, não deve saber das coisas de persistencia, e ter uma cara mais parecida com uma coleção ^^

    Obrigado de + sergio pelas dicas, foi num post de 2007 (do forum do guj) de varias paginas e justamente num comentario seu, que enxerguei melhor as coisa ^^
    post

    so preciso de mais essa informação, qual a melhor forma pra fazer a tranzação… agora estou fazendo um repositorio generico tipo isso

    public interface RepositoriosEntidades {
    public void add(IEntidade entidade);
    public <E extends IEntidade> E get(Class<E> entidade, Integer index);
    public <E extends IEntidade> E get(Class<E> entidade, Long index);
    public <E extends IEntidade> E get(Class<E> entidade, BigInteger index);
    public void remove(IEntidade entidade);
    public void replace(IEntidade entidade);
    public void retrive(IEntidade entidade);
    /**
    * recupera a lista ({@link List}) com todos as entidades com as entidades da classe E
    * enviada como parametro, Exemplo de uso, list({@link Cidade}.class) onde
    * {@link Cidade} tem que assinar a interface {@link IEntidade}
    * @param <E> uma entidade com a assinatura de {@link IEntidade}
    * @param entidade a classe da entidade E ao qual se deseja recupar a lista
    * @return {@link List}<{@link IEntidade}> uma lista de tipo igual ao da classe entidade
    * passada no parametro "entidade".
    */
    public <E extends IEntidade> List<E> list(Class<E> entidade);
    }

    Acredito que so falta o commit e rollback agora ^^

    muito obrigado pela ajuda sergio

    Abraços
    Tomaz Lavieri

    1. Bom quanto à interface :
      1) Repositorios não são interfaces são classes. A definição de um repositorio é no máximo uma classe abstracta.
      2) os métodos public void remove(Integer id); public void remove(Long id); public void remove(BigInteger id); não devem exisitr
      ( amenos que o seu repositorio seja de Long, Integer ou BigDecimal … ) O métodos devem ter como parametro sempre o objecto
      public void remove(T entidade); está ok.
      3) Os métodos get devem se chamar find. isto porque o “get” dá a impressão que se trata de uma propriedade. o que não é verdade.
      public T get(Integer id);public T get(Long id); public T get(BigInteger id); => findById(Number id);

      4) não existe um método public void retrive(T entidade);

      5) os métodos add e replace podem ser unidos em um método save(T entidade)

      6) o método list() é na realdiade um find mas que retorna todos
      public List list(); => findAll();

      Faça os nomes dos métodos serem explicitos e significarem exactamente o tipo de pesquisa que fazem.

      Para os repositorios especificos não use interfaces. Declare os métodos directamente na classe. Não precisa de abstração neste nivel.

      quanto às transações vc deve criar uma interface Transaction (begin, commit, roolback) e uma classe TransactionManager de onde obter a transação corrente. A implementação do manager e da transação depende do ambiente onde vc está correndo o sistema e da tecnologia de persistencia. Em um Appliation Server o objeto Trasnaction já existe na API JTA e pode ser obtido explicitamente. Contudo em um AS a transação é controlada melhor pelo proprio AS e portanto não ha nada a escrever no programa (a não ser algum anotação ou configuração)
      Se está rodando fora do AS vc precisa que escrever o codigo do transaction manager para o controle da transação.
      Para JDBC é simples. vc obtem um conection setAutocommit para false. e depois usa os commit e rollback do ppr connetion.
      Paa hibernate usa o objeto transaction do ppr hibernate. O ponto é que a interface Trasnaction que vc criou encapsule qualquer um destes mecanismos. normalmente vc precisa manter a transação em escopo de thread (veja ThreadLocal ).

      O uso é assim

      Transaction transaction = TransactionManager.getTransaction();
      try {
      transaction.begin();

      repPais.add(pais);
      repEstado.add(estado);
      repCidade.add(cidade);

      transaction.commit();

      } catch (Exception rre) {
      transaction.rollback();
      }

      Lembre-se que a transação está controlando um nivel abaixo do repositorio e pode controlar mais coisas como envio de email, por exemplo.

  11. 1) Repositorios não são interfaces são classes. A definição de um repositorio é no máximo uma classe abstracta.

    R: eu sei disso, e tenho 1 classe para os repositorios, so tenho interface, pq no futuro, tenho itenção de poder trocar o modo depersistencia do hiberante para outro… e quando preciso, é so implementar as interfaces para o outro modo, e trocar o apontamento duma classe de configuração que tenho, que aponta pro repositorio do hibernate.

    -> ISso é errado. Se a implementação de persistencia mudar, vc muda o repositorio. Se vc quiser manter várias opções crie DAOs. DAOS é que têm interfaces e podem ter várias implementações conforme a tecnologia subjacente. Repositorios não. Mas só introduza os DAOs quando realmente necessitar.

    ……………………….

    2) os métodos public void remove(Integer id); public void remove(Long id); public void remove(BigInteger id); não devem exisitr
    ( amenos que o seu repositorio seja de Long, Integer ou BigDecimal … ) O métodos devem ter como parametro sempre o objecto
    public void remove(T entidade); está ok.

    R: Eu fiz varias formas de remove pq toda entidade minha tem 1 código (isso é algo q eu defini, esse código pode ser grande ou pekeno, e na entidade existe, o tipo do código pode ser variavel… porem quero aceitar que alguem me envie um tipo BIGINTEGER … eu vejo c ele ta no range, c tiver, converto pra long ou integer c preciso… ai faço a busca… c tiver fora do range, exceção para fora…

    Só ha varios modos de remover, pq esse método serve pra qualquer entidade, pq toda entidade tem 1 código… então não kiz reescrever, e fazer a conversao do numero é facil e rapido.

    -> Bigdecimal é muito grande. Acho que vc não tem noção do valor máximo de um long. Além disso bancos de dados não aceitam nada maior que long como chave primária. Se vc quer ter a escolha entre Long e Integer crie uma interface( ou classe abstrata) Key e implementações LongKey e IntegerKey. No codigo vc usa Key e durante a persistencia vc decide se usa LongKey ou IntegerKey (por exemplo baseando-se no tipo de dados da coluna , ou em algum modelo ou anotação). O seu método do repositorio é apenas um : findByKey(Key key) e a sua interface de entidade pode ter um get/setKey() para facilitar as coisas. Ter apenas um método é mais facil de manter. Se vc quiser muito usar BigDecimal , é só implementar BigDecimalKey.

    4) não existe um método public void retrive(T entidade); esse método eu fiz com o seguinte entuito … vc esta acessando 1 objeto… e faz alterações… nele, ai decide que quer descartar tudo e resetar parao original… com esse retrive ele faz isso… ele recupera o dado ao estado original… Não posso fazer isso ??

    exemplo: Cidade c = repoistorio.get(3);
    c.setNome(“Novo nome”);

    ai degamos que eu não tenho mandado pro repositorio ainda, e kera voltar o dado…

    repositorio.retrive(c);
    c.getNome(); //vai mostar o nome original e não “novo nome”

    -> Nop. Não existe “resetar”. Se vc não quer os dados vc descarta-os e lê de novo. Ou vc cria copias de trabalho

    [le de novo]
    Cidade c = repoistorio.get(3);
    c.setNome(“Novo nome”);
    c = repoistorio.get(3);

    [copia]

    Cidade original = repoistorio.get(3);
    Cidade c = new Cidade(original);
    c.setNome(“Novo nome”);

    Cidade c = new Cidade(original); // reset de c

    …………

    Transaction transaction = TransactionManager.getTransaction();
    try {
    transaction.begin();

    /** Ps.: agora não precisa mais de 1 repositorio para cada classe
    * possoadcionar direto, todos em 1 repositorio generico que acha
    * sozinho o repositorio daquela classe
    */
    rep.add(pais);
    rep.add(estado);
    rep.add(cidade);

    transaction.commit();

    } catch (Exception rre) {
    transaction.rollback();
    }

    -> Vc gosta de arranjar lenha para se queimar hein? … use o repositorio certo.
    Isso que vc fez é POG. Vc está violando o principio básico de porque criou o repositorio. É um repositório por entidade e não um repositório por sistema. Fazer desta forma vai lhe trazer problemas de manutenção porque não é claro qual repositorio está realmente gravando a entidade.

    É raro vc ter que salva mais do que uma entidade ao mesmo tempo. Além de vc pode salvar em cadeia (em grafo)

    Pais brasil = new Pais(“Brasil”);
    Estado minas= new Estado (“Minas Gerais”);
    Cidade beloHorizonte = new Cidade(“Belo Horizonte”);

    estado.setPais(brasil);
    beloHorizonte.setEstado(estado);

    Repositorio rep = ..
    rep.save(beloHorizonte);

    O repositorio de cidade pode verificar se o estado da cidade está salvo e se não , chama o repositorio de estado e salva-o.
    O repositorio de estado por sua vez faz o mesmo com pais. Esta é uma forma mais natural de trabalhar. ( mas tem os seus riscos porque e´mais complexo no caso geral). Enfim, faça facil primeiro. Use os repositorios explicitamente 1 a 1.

    1. De certa forma é, e isso não é uma coincidência. O texto que passou confunde DAO com Repositório e contribui ha anos para alimentar esse equivoco. O próprio texto refere que DAO é um tipo de DataMapper citando o catálogo de padrões do Martin Fowler. Repositorio tb é um padrão desse mesmo catálogo. Quanto a mim não faz nenhum sentido que dois padrões sejam a mesma coisa ou encarnações um do outro.
      Esta confusão entre DAO e Repositorio só atrapalha e hoje é chamada de Sindroma de DAO

  12. Olá!

    Tira uma dúvida?

    Qual é a forma correta de persisitir os dados de uma entidade no banco de dados ?

    O repositório recebe uma entidade e depois converte ela para um objeto de transporte e envia para a camada de infra ?

    seria isso ?

    1. Basicamente sim. Abaixo do repositório existe a camada de persistência ( o repositório está na camada de domínio). A camada de persistência pode ser desde um jdbc puro até um hibernate da vida.
      Hoje em dia, vc teria um DomainStore que encapsula a chamada a um hibernate ou EntityManager, mas pode usar um DAO também. Para um exemplo mais completo veja o workshop no javabuilding

  13. Olá!

    Quando um processo de persistência envolver mais de uma entidade seria correto a criação de um serviço ?

    Ex.
    -Cadastro de produto + Cadastro de estoque(produto, cor, tamanho, aroma, preco, imagem)
    -Cadastro de Fornecedor + Imagem
    -Cadastro de Categoria + Imagem

    Obrigado pela atenção ?

    1. Exactamente djoido. Vc cria um serviço sempre que vc precisa aterar o estado do sistema, principalmente porque irá haver uma transação associada. Ai vc manipula dentro do serviços os outros objetos do dominio para realizar a tarefa, que pode envolver uma entidade ou muitas.

  14. Eu estou fazendo da seguinte forma:

    class ServicoFornecedor {

    public void CadastrarFornecedor(EntidadeProduto Produto){
    RepositorioProduto repositorioproduto = new RepositorioProduto();
    RepositorioImagem repositorioimagem = new RepositorioImagem();

    int idTipoOrigem = 4; // Tipo origem referente ao Fornecedor.
    int idOrigemConteudo = repositorioproduto.Cadastrar(Produto); //Dentro desse repositorio eu converto a entidade para um objeto dto e envio para a infra. A infra realiza o cadastro e retorna o id desse registro.

    repositorioimagem.Cadastrar(Produto.Imagem, idOrigemConteudo, idTipoOrigem);
    }
    }

    Eu coloquei “IdTipoOrigem” e “IdOrigemConteudo” porque eu centralizei o cadastro das imagens. Existe apenas uma tabela na base responsável pelo armazenamento(Nome da imagem e atributos) de todas as imagens gerenciadas dinamicamente por todos os módulos(Produto, Categoria, Marca etc.).

    O que acha ?

    Obrigado pela atenção

    1. Me parece bastante válido. Algumas coisas que eu mudaria. Modificaria o nome “cadastrar” para “salvar” porque quem Cadastra é o serviço, o repositório só persiste. Uma outra coisa que poderia fazer para melhorar seria criar um objeto Imagem que contém os três parâmetros que está passando ao repositório. Desta forma o método seria repositorioImagem.Salvar(imagem), que fica mais explicito. Esse objeto contem a imagem em si e o contexto a que ela se refere que são aqueles dois ints ali. Um outro detalhe é que os objetos de repositório deveriam ser injetados como privates no serviço e não ser instanciados dentro do método. Mas conceptualmente a ideia está correta. O serviço orquestra o uso dos repositórios.

  15. Olá!

    Mais uma dúvida

    O serviço ‘CadastrarProduto’ pode receber(Como parâmetro) os bytes da imagem, chamar um serviço de cadastro de arquivo da infra e gravar a imagem em uma pasta no servidor ?

    Obrigado pela atenção

    1. Não. Os bytes da imagem devem estar em um objeto Imagem que está no Produto. Quando vc escreveu “Produto.Imagem” achei que já tinha essa estrutura. Tudo bem que as imagens podem ser de várias coisas, mas do ponto de vista do modelo, o produto tem uma imagem, e a imagem é que tem bytes ( e já agora tb tem um mime type para saber o que esses bytes são) . O repositorio de imagens recebe esse objeto imagem e lá dentro acessa os bytes e grava. É o repositorio de imagens que vai fazer essas operações que falou. A estrutura que vc apresentou antes estava blz, agora parece que vc está andando para trás. Não faça isso. Mantenha a estrutura que apresentou no outro comentário.

  16. A entidade imagem está assim(em asp.net):

    class imagem {
    public int Id { get; private set; }
    public string NomeOriginal { get; private set; }
    public string NomeSistema { get; private set; }
    public string Extensao { get; private set; }
    public string ContentType { get; private set; }
    public OrigemArquivo oOrigem{ get; private set; }

    public Imagem(string NomeOriginal, string NomeSistema, string Extensao, string ContentType, OrigemArquivo oOrigem) {
    this.NomeOriginal = NomeOriginal;
    this.NomeSistema = NomeSistema;
    this.Extensao = Extensao;
    this.ContentType = ContentType;
    this.oOrigem = oOrigem;

    }

    }

    A dúvida era como salvar/deletar essa imagem no servidor.

    Pelo que eu entendi é o respositório de imagens que faz o cadastro da imagem na base de dados e salva(com a ajuda da infra) o arquivo em uma pasta no servidor.

    Obrigado pela atenção

    1. Exatamente, o repositório de imagens trata da persistência na base e na pasta. Isso pode ser feito diretamente pelo repositório ou por outro objeto que o repositório usa.

  17. Sérgio,

    Antes de mais nada parabéns pelo blog. Muito bom.

    Pode me ajudar a resolver um problema ?

    Eu preciso criar um formulario para editar informações do usuário. As informações eu busco direto do dao e mostro na tela ex. BuscarPorId(int id). A query sql vai estar dentro do método na camada da infra.

    Se eu precisar buscar uma entidade pelo id ex. BuscarUsuarioPorId(int id). A query sql vai estar no repositório e vai ser passada para um método da infra executar.

    Nas situações acima eu vou ter dois métodos na infra que vão retornar as mesmas informações(UsuarioTO). A única diferença é que um método vai receber a query como parâmetro e o outro a query vai estar embutida.

    Eles vão retornar as mesmas informações só que em contexto diferentes.

    É correto ter esses dois métodos na infra ou eu poderia criar um metodo no repositorio que nao monta a query, mas chama esse método da infra que contém a query embutida?

    Agradeço a ajuda.

    1. Primeiro, entenda que não faz muto sentido usar Repositório com DAO. O repositório poderia criar a query numa string sql e passar ao dao para executar, mas isso faria o repositorio acoplado à sua camada inferior o que não tem vantagem nenhuma. Nesse caso é mais simples deixar a query dentro do DAO e não usar o Repositorio. Se quiser usar os dois juntos precisa criar um objeto que represente a query, e deixar o DAO transformar esse objeto em SQL. O repositorio não pode usar a tecnologia subjacente.
      Também não faz sentido misturar, tendo métodos onde a query está dentro do DAO e métodos onde está fora. Ao usar o padrão DAO com queries fixas é melhor que todas estejam dentro do DAO e os métodos do dao apenas recebem parametros da query e não a query em si. Neste modelo, o repositorio não tem utilidade. Para usar o Repositorio vc precisa usar o padrão DomainStore em vez de DAO. Entenda que são dois modelos diferentes. O repositorio mantém a construção das queries, mas o faz de uma forma agnóstica à tencologia ( padrão QeryObject) pois só assim é possivel a camada de baixo decidir se aquilo deve virar SQL ou XPath ou outra coisa qualquer. Quem faz essa conversão é o DomainStore. E só existe um único domain store e não 1 para cada entidade. Leia este artigo no javabuilding que explica melhor como seria a arqutietura com Repositorio.
      Se prefere usar DAO tudo bem, apenas encapsule o SQL dentro dos DAOs e chame os DAOs diretamente dos serviços sem passar pelo repositorio.

  18. Entendi. Vou trocar o Dao pelo Domainstore.

    No caso como eu faria para exibir dado bruto em uma página, exemplo lista de notícias com paginação e campo de busca ?

    Preciso passar pelo repositório ?

    1. Para exibir listas você invoca o repositorio no método que lhe dá a lista. Tipo:

      repositorio.findAllClients()

      Este método pode ter filtros se precisar

      repositorio.findAllClientsBy(ClientsFilter clientsFilter)

      Se você escolheu seu repositorio retornar list , vc tem diretamente

      List clients = repositorio.findAllClientsBy(clientsFilter)

      Se vc escolheu ele retornar um QueryResult então vc invoka o método no query result que lhe dá al lista.

      Para paginação é melhor ter objetos especiais que usam o QueryResult ou o Repositorio diretamente para fazer a paginação. Existem várias formas de implementar o paginator ( veja no javabuilding um exemplo) , mas é bom que vc implemente de um jeito que possa delegar ao banco de dados para fazer a paginação. Dê também uma lida em http://www.javabuilding.com/search/academy/patterns/repository.html

  19. Olá Sergio mais um post muito bom, o exemplo do domíno do djoido (vendas,estoques,fornecedores) é muito bom,
    porque engloba bastante situações do dia a dia que encontramos no mercado.
    Pelo que li acho que estou usando os services e repositórios quase de forma correta, no entanto ainda
    tenho algumas dúvidas.consideremos as classes

    public class Material{
    private Long materialId;
    private String nome;
    private String descricao;
    private GrupoMaterial categoriaMaterial;
    private UnidadeMaterial unidadeMaterial;
    private Integer quantidadeInicial;
    private BigDecimal valorInicial;
    private Integer quantidadeRessuprimento;
    //…
    }
    public class Movimento {
    private Long movimentoId;
    private Enum tipoMovimento;
    private Integer saldo;
    private BigDecimal valorUnitario;
    private BigDecimal valorTotal;
    private Material material;
    private Date data;
    //…
    }

    public class Requisicao{
    private Long requisicaoId;
    private Date data;
    private Requisitante req;
    private Collection requisicaoDetalhes;
    private Enum requisicaoStatus;
    //…
    }
    public class RequisicaoDetalhe {
    private Integer requisicaoDetalheId;
    private Requisicao requisicao;
    private Material material;
    private Integer quantidade;
    //…
    }

    o saldo em estoque de material não fica em material, eu guardo este saldo no
    movimento, pego sempre o ultimo movimento, se for uma entrada crio um novo saldo incrementando a quantidade que entra no movimento mais
    o saldo anterior, se for uma saida o saldo atual é o saldo anterior menos a quantidade saindo, então tenho meu service
    que tem controle transacional,valida e utiliza 3 repositorios para realizar uma tarefa.ainda tou achando estrano
    os sets que estou dando no novo movimento, talvez pudesse utilizar um assembler ou passar tudo pelo construtor do movimento
    pois o service está manipulando os atributos do movimento, não estou ferindo o encapsulamento?
    @Stateless
    @TransactionManagement(TransactionManagementType.CONTAINER)
    public class RequisicaoService{

    @EJB private MovimentoRepository movimentoRepo;
    @EJB private MaterialRepository materialRepo
    @EJB private RequisicaoRepository requisicaoRepo;

    public void atenderRequisicao(Requisicao requisicao){

    Movimento ultimoMovimentoMaterial = null;
    Requisicao reqTesteAtd = ds.findRequisicaoByPrimaryKey(id);

    if (reqTesteAtd.isAtendida()){
    throw new BusinessException(“Requisição já Atendida”);
    }else{
    for (RequisicaoDetalhe b: requisicao.requisicaoDetalhes()){
    ultimoMovimentoMaterial = movimentoRepo.findUltMovimentoByMaterialId(b.getMaterial().getMaterialId());
    if (ultimoMovimentoMaterial == 0) {
    throw new BusinessException(“O material “+ b.getMaterial().getNome()+” Não há saldo cadastrado.\n Atualize o saldo do material\n para atender a requisição. “);
    }else{
    if (ultimoMovimentoMaterial.getSaldo()b.getQuantidade()){
    throw new BusinessException(“A quantidade atendida do material “+ b.getMaterial().getNome()+” én superior a quantidade solicitada.\n Informe uma\n quantidade menor.”);
    }
    }
    for (RequisicaoDetalhe a: requisicaoDetalhes) {
    /* Aqui talvez devesse passar o ultimo movimento e a requisicaoDetalhe por
    construtor e assim devolver um movimento montado*/
    movimento = new Movimento();
    movimento.setMaterial(a.getMaterial());
    movimento.setTipoMovimento(“SS”);
    movimento.setSaldo(ultimoMovimentoMaterial.getSaldo()-a.getQuantidadeAtendida());
    movimento.setValorTotal(ultimoMovimentoMaterial.getValorUnitario()*movimento.getSaldo());
    movimento.setValorUnitario(ultimoMovimentoMaterial.getValorUnitario());
    movimentoRepo.cadastrarMovimento(movimento);
    }
    requisicao.atender();
    requisicaoRepo.alterarRequisicao(requisicao);
    }
    }
    esse é um uso correto de um service?
    Outra dúvida, talvez essa modelagem esteja errada pois o saldo fica apenas
    no movimento,se eu quero simplesmente saber a quantidade em estoque de um produto eu tenho ter o último movimento do produto e chamar algum service,ou
    então fazer isso aqui:

    public class Material(){
    //injetado de alguma forma
    MovimentoRepository repo;

    public Integer getQuantidadeEstoque
    repo.saldoUltimoMovimento(this);

    }
    já li diversos posts seus e sei que vc não concorda com esta abordagem e na verdade eu também não,pensei
    em criar um campo quantidadeAtual em Material e no service eu atribuiria a quantidadeEmEstoque o saldo do ultimo movimento
    mas ai corro o risco novamente de ferir o encapsulamento não? como você solucionaria este problema?

    public class RequisicaoService{
    /…/

    public void atenderRequisicao(Requisicao requisicao){
    /…/
    for (RequisicaoDetalhe a: requisicaoDetalhes) {

    Material mat =a.getMaterial.atualizaQuantidadeAtual(ultimoMovimento);
    materialRepository.atualizar(mat);

    }
    }
    }
    public class Material(){
    /…/
    private Integer quantidadeAtual;

    public void atualizaQuantidadeAtual(Movimento mov){
    this.quantidadeAtual = mov.getSaldo();
    }

    public Integer getQuantidadeAtual(){
    return quantidadeAtual;
    }

    }

    1. Os conceitos de movimento, conta e saldo são um típico problema. No seu caso é uma conta de estoque, mas o mesmo principio do ser aplicado a qualquer tipo de conta que possa ser debitada e creditada.
      Conceptualmente o saldo é um calculo, não uma propriedade. O saldo que coloca no movimento ser como um histórico e é por isso que tem que pegar o ultimo. Para saber o saldo numa certa data, o que você faz ?
      Se tem muitos movimentos em um dia, pegar o ultimo do dia parece fazer sentido, mas a query não é tao simples quanto pegar o ultimo que existe. Se precisar criar um relatório de estoque no tempo, a coisa é mais complicada.

      Portanto, em geral o saldo é realmente um valor calculado e deve existir um método que o calcula: CalculaSaldoEstoque(Material, Data) que nada mais é que um sum de todos os movimentos num intervalo de datas entre o inicio dos tempos e um marco. Manter o saldo no movimento ou na conta é uma técnica que vem lá de trás dos tempos do clipper para evitar o calculo “força bruta” do sum. Portanto, não ha problema em manter o saldo no movimento, desde que isso não se veja. O encapsulamento está no fato do método CalculaSaldoEstoque(Material, Data) não receber nem retornar objetos Movimento, embora por baixo dos panos é o movimento que é usado para calcular.

      Na prática, se forem necessários relatorios ( o que normalmente acontece) o modelo de usar o movimento funciona, mas requer filtros de quais movimentos considerar. Para evitar isso, normalmente o sistema mantém uma entidade de saldo por conta e dia com o saldo no inicio e fim do dia. Pode continuar tento no movimento, mas esta outra entidade consolida os dados para uso futuro em relatórios. O movimento representa então como o saldo no incio do dia, se transformou no do fim do dia.

  20. Olá!

    Em uma aplicação em C# eu encontrei o seguinte código no repositório:

    =============================

    StringBuilder sSql = new StringBuilder();
    sSql.Append(“update usuario set Nome=@Nome,Login=@Login, Senha=@Senha, IdPerfil=@IdPerfil, IdStatus=@IdStatus where Id=@Id”);

    MySqlCommand oCmd = new MySqlCommand();
    oCmd.CommandText = sSql.ToString();
    oCmd.Parameters.AddWithValue(“@Id”, oUsuario.Id);
    oCmd.Parameters.AddWithValue(“@Nome”, oUsuario.Nome);
    oCmd.Parameters.AddWithValue(“@Login”, oUsuario.Login);
    oCmd.Parameters.AddWithValue(“@Senha”, oUsuario.Senha);
    oCmd.Parameters.AddWithValue(“@IdPerfil”, oUsuario.oPerfil.Id);
    oCmd.Parameters.AddWithValue(“@IdStatus”, oUsuario.oStatus.Id);

    new Dao.Cadastrar(oCmd)

    =====================================

    O método da classe Dao está assim:

    void Cadastrar(MySqlCommand comando){
    //Abrindo conexao

    comando.ExecuteNonQuery();

    //Fechando conexao
    }

    =============================

    isso é correto ?

    Obrigado pela atenção

    1. Não. Dois motivos principais
      1) O DAO serve para isolar a comunicação com o mecanismo de persistência. Ou seja, se o mecanismo mudar o DAO pode mudar, mas o repositorio não. O Repositorio tem que ser agnóstico em relação ao que o DAO faz. Faria mais sentido um codigo como

      new DAO().Cadastrar(oUsuario);

      e o codigo que cria o command estar no DAO.

      No caso, por exemplo, se o SGDB mudar da MySQL para Oracle ou SQLServer será necessário mudar os repositórios. Isso é errado pois é contrario ao Principio de Separação de Responsabilidades.

      2) Uma outra coisa errada é dar new diretamente dentro do Repositório. O Dao deve ser passado como parâmetro do construtor em coerência com o Principio da Inversão de Dependência. Se isso não for possivel, pelo menos o padrão Factory deve ser usado. Isto se encaixa com o item anterior. No caso de o DAO mudar de um MySQLDao para um OrableDao, por exemplo, é necessário mudar o codigo do repositorio ? No caso sim. è preciso dar um new de um objeto diferente. Mas se a depdencnia for invertida, o Repositório irá receber como parâmetro um objecto da class DAO (ou da interface IDao , como seria mais comum). O Repositorio não sabe sobre como esse dao é implementado. O repositorio se limita a chaamr o dao e pronto. Se um outro dao for criado e tivermos que trocar, o que será trocado é o ponto que envia o dao para o repositorio e não o repositorio em si. Se usar um ferramenta como o Spring.Net bastará mudar um xml e nem sequer é preciso mudar código algum em qualquer repositório.

      Espero que tenha sido claro e que ajude.

Deixe um comentário