Pergunta

Eu tenho vindo a explorar BDD / DDD e como consequência a tentar chegar a uma implementação adequada do padrão Repository. Até agora, tem sido difícil encontrar um consenso sobre a melhor maneira de implementar isso. Tentei reduzi-lo para as seguintes variações, mas não estou certo que é a melhor abordagem.

Para referência Estou construindo uma aplicação ASP.MVC com NHibernate como um back-end.

public interface IRepository<T> {
        // 1) Thin facade over LINQ
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IQueryable<T> Find();
        // or possibly even
        T Get(Expression<Func<T, bool>> query);
        List<T> Find(Expression<Func<T, bool>> query);
}

public interface IRepository<T> {
        // 2) Custom methods for each query
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySku(string sku);
        IList<T> FindByName(string name);
        IList<T> FindByPrice(decimal price);
        // ... and so on
}

public interface IRepository<T> {
        // 3) Wrap NHibernate Criteria in Spec pattern
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}


public interface IRepository<T> {
        // 4) Expose NHibernate Criteria directly
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> Find(ICriteria criteria);
        // .. or possibly
        IList<T> Find(HQL stuff);
}

Meus pensamentos iniciais são de que

1) é grande do ponto de vista da eficiência, mas pode entrar em apuros como as coisas ficam mais complicadas.

2) parece muito tedioso e pode acabar com uma classe muito cheia, mas por outro lado oferece um alto grau de separação entre a minha lógica de domínio e camada de dados que eu gosto.

3) parece difícil frente para cima e mais trabalho para consultas de escrita, mas limita a contaminação cruzada apenas para a camada de Specs.

4) Minha pelo menos favorito, mas a sua implementação, possivelmente, mais direta e possivelmente o mais banco de dados eficiente para consultas complexas, embora ele coloca muita responsabilidade sobre o código de chamada.

Foi útil?

Solução

Eu acho que eles são todas as opções boas (exceto talvez 4 se você não quer se amarrar nhibernate), e parece que você tem prós e contras bem analisadas para tomar uma decisão sobre o seu próprio com base no seu esforço atual. Não bater- muito duro para isso.

Atualmente estou trabalhando em uma mistura entre 2 e 3 eu acho que:

public interface IRepository<T> 
{
        ...
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}

public interface ISpecificRepository : IRepository<Specific> 
{
        ...
        IList<Specific> FindBySku(string sku);
        IList<Specific> FindByName(string name);
        IList<Specific> FindByPrice(decimal price);
}

E há também uma classe base Repository (do T).

Outras dicas

Há também um bom argumento para uma "nenhuma das anteriores" abordagem.

O problema com repositórios de genéricos é que você está fazendo a suposição de que todos os objetos em seu sistema irá apoiar todas as quatro operações CRUD: Criar, Ler, update, delete. Mas em sistemas complexos, você provavelmente vai ter objetos que suportam apenas algumas das operações. Por exemplo, você pode ter objetos que são somente leitura, ou objetos que são criados mas nunca atualizados.

Você poderia quebrar a interface IRepository em pequenos interfaces para ler, apagar, etc. mas isso fica confuso muito rapidamente.

Gregory Jovem faz um bom argumento (de uma perspectiva camadas DDD / software) que cada repositório deve apoiar apenas as operações que são específicos para o objeto de domínio ou agregado que você está trabalhando. Aqui está o seu artigo sobre repositórios genéricos .

E para uma visão alternativa, ver este Ayende Blog Post .

Uma das coisas que estamos fazendo é que todos os nossos repositórios têm necessidades diferentes, de modo que estamos criando uma coleção de interfaces:

public interface IReadOnlyRepository<T,V>
{
   V Find(T);
}

Neste exemplo, a ler único repositório só faz recebe do banco de dados. A razão para o T, V é o V representa o que é devolvido pelo repositório e T representa o que é passado, então você poderia fazer algo parecido com isto:

public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer>
{
    public Customer Find(int customerId)
    {
    }

    public Customer Find(string customerName)
    {
    }
}

Eu também pode criar interfaces de separadas para o suplemento, Update e Delete. Dessa forma, se meu repositório não precisa do comportamento, em seguida, ele simplesmente não implementar a interface.

Eu sou um fã bif de 1, porque posso criar filtros e métodos de extensão paginação do que eu posso aplicar aos IQueryable <> valores de retorno para o método de localização. I manter os métodos de extensão na camada de dados e, em seguida, construir sobre a voar na camada de negócios. (Não é totalmente pura, é certo.)

Claro que, quando o sistema estabiliza eu tenho a opção de fazer métodos Find específicas usando os mesmos métodos de extensão e otimizar usando Func <>.

Ao usar NH com Linq seu repositório pode ser:

session.Linq<Entity>()

As especificações são as coisas que lidam com:

IQueryable<Entity>

Você pode fachada tudo fora, se quiser, mas isso é um monte de trabalho mundano para abstrair uma abstração.

Simples é bom. Yah, NH faz bancos de dados, mas oferece tantas mais padrões. Tendo diferente do DAL dependem de NH está longe de ser um pecado.

Eu acredito que depende de suas necessidades. É importante pensar sobre repositório em conjunto com outros padrões de projeto que você considera de usar. Finalmente, muito depende do que você espera de repositório (que são as principais razões para usá-lo).

Você precisa criar camada rígida (por exemplo, você precisará substituir NHibernate com Entity Framework no futuro)? Você quer teste de escrita especialmente para os métodos de repositório?

Não há melhor maneira como criar repositório. Há apenas algumas maneiras e é definitivamente até você, o que é o mais prático para suas necessidades.

Wither o Repositório

Um artigo relevante por Jimmy Bogard de LosTechies

http: // www .lostechies.com / blogs / jimmy_bogard / Arquivo / 2009/09/10 / murchar-the-repository.aspx

Além disso, outro artigo rápido com alguns comentários que sugerem a versão # 2 é realmente um padrão DOA e não um repositório.

http://fabiomaulo.blogspot.com/2009/06 /linq-and-repository.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top