Padrão de Repositório vs DAL

93

Eles são a mesma coisa? Acabei de assistir ao tutorial da Storefront de Rob Connery e eles parecem ter técnicas semelhantes. Quer dizer, quando eu implemento um objeto DAL, tenho os métodos GetStuff, Add / Delete etc. e sempre escrevo a interface primeiro para que possa alternar o banco de dados depois.

Estou confundindo as coisas?

Mike
fonte

Respostas:

88

Você definitivamente não é aquele que confunde as coisas. :-)

Acho que a resposta à pergunta depende de quanto você deseja ser purista.

Se você quiser um ponto de vista DDD estrito, isso o levará por um caminho. Se você olhar para o repositório como um padrão que nos ajudou a padronizar a interface da camada que separa entre os serviços e o banco de dados, isso o levará para outra.

O repositório, da minha perspectiva, é apenas uma camada claramente especificada de acesso aos dados. Ou, em outras palavras, uma maneira padronizada de implementar sua camada de acesso a dados. Existem algumas diferenças entre as diferentes implementações de repositório, mas o conceito é o mesmo.

Algumas pessoas colocarão mais restrições DDD no repositório, enquanto outras usarão o repositório como um mediador conveniente entre o banco de dados e a camada de serviço. Um repositório como um DAL isola a camada de serviço de dados específicos de acesso.

Um problema de implementação que parece torná-los diferentes é que um repositório geralmente é criado com métodos que usam uma especificação. O repositório retornará dados que satisfaçam essa especificação. A maioria dos DALs tradicionais que tenho visto terá um conjunto maior de métodos em que o método terá qualquer número de parâmetros. Embora isso possa parecer uma pequena diferença, é um grande problema quando você entra nos domínios do Linq e Expressions. Nossa interface de repositório padrão se parece com isto:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

Este é um DAL ou um repositório? Neste caso, acho que são os dois.

Kim

Kim Major
fonte
5
Atrasado para a festa aqui, mas por que T [], não List <T> (ou similar)?
Mike Kingscott
27
Talvez IEnumerable <T> seja o melhor.
Venemo
9
ou IQueryable <T>
kenwarner
1
Acho que IQueryable <T> seria a melhor escolha, porque permite encadear métodos e adiar a execução, permitindo que o banco de dados faça todo o trabalho.
0lukasz0
4
@kenwarner Acho que retornar IQueryable <T> vaza a abstração. Você deve retornar objetos de domínio de seu repositório.
Mateus
42

Um repositório é um padrão que pode ser aplicado de muitas maneiras diferentes, enquanto a camada de acesso a dados tem uma responsabilidade muito clara: o DAL deve saber como se conectar ao seu armazenamento de dados para realizar operações CRUD.

Um repositório pode ser um DAL, mas também pode ficar na frente da DAL e atuar como uma ponte entre a camada de objeto de negócios e a camada de dados. A implementação usada varia de projeto para projeto.

Jeromy Irvine
fonte
23

Uma grande diferença é que um DAO é uma maneira genérica de lidar com a persistência de qualquer entidade em seu domínio. Um repositório, por outro lado, lida apenas com raízes agregadas.

pondermático
fonte
26
A primeira coisa a entender é que um repositório como padrão faz parte de um sistema maior conhecido como Domain Driven Design. No domínio DDD, os objetos são agrupados em agregados, cada um com uma raiz agregada. Por exemplo, PurchaseOrder é uma raiz agregada e OrderItems são filhos da raiz agregada. Um repositório lida apenas com raízes agregadas. Ou seja, um OrderItem, por exemplo, nunca é carregado independentemente de sua raiz agregada. Portanto, você nunca teria um repositório OrderItem no DDD. No entanto, em um sistema não DDD, você poderia ter um OrderItemDao, já que Dao não está restrito a raízes agregadas.
pondermatic
NG, obrigado! Eu comecei a ver dessa forma, mas isso deixa claro. Vou ter que começar a ler toda a literatura DDD!
David
@bingle, ótima descrição das raízes agregadas e como os objetos filhos são carregados por um repositório. Onde existiria um repositório em um aplicativo de várias camadas? Pude ver que ele está em uma biblioteca de camada de acesso a dados, mas como carrega objetos filho, ele deveria existir na biblioteca de camada lógica? Meu instinto me diz camada de acesso a dados, mas eu queria sua opinião sobre o assunto.
Jeff LaFay
12

Eu estava procurando uma resposta para uma pergunta semelhante e concordo com as duas respostas mais bem classificadas. Tentando esclarecer isso para mim mesmo, descobri que se as especificações, que andam de mãos dadas com o padrão Repositório, forem implementadas como membros de primeira classe do modelo de domínio, então posso

  • reutilize as definições de especificação com parâmetros diferentes,
  • manipular os parâmetros das instâncias de especificação existentes (por exemplo, para se especializar),
  • combiná- los,
  • realizar lógica de negócios neles sem nunca ter que fazer nenhum acesso ao banco de dados,
  • e, é claro, teste-os de unidade independentemente das implementações reais do Repositório.

Posso até ir tão longe e afirmar que , a menos que o padrão Repository seja usado junto com o padrão Specification, não é realmente "Repository", mas um DAL. Um exemplo inventado em pseudocódigo:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

Veja o Ensaio de Especificação de Fowler para detalhes (foi nisso que eu baseei acima).

Um DAL teria métodos especializados como

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

Você pode ver como isso pode se tornar rapidamente complicado, especialmente porque você precisa definir cada uma das interfaces DAL / DAO com esta abordagem e implementar o método de consulta DAL.

Em .NET, as consultas LINQ podem ser uma maneira de implementar especificações, mas combinar Specification (expressões) pode não ser tão fácil quanto com uma solução caseira. Algumas idéias para isso estão descritas nesta pergunta do SO .

Thomas Jung
fonte
2

Minha opinião pessoal é que se trata de mapeamento, consulte: http://www.martinfowler.com/eaaCatalog/repository.html . Portanto, a saída / entrada do repositório são objetos de domínio, que na DAL podem ser qualquer coisa. Para mim, isso é uma adição / restrição importante, pois você pode adicionar uma implementação de repositório para um banco de dados / serviço / qualquer coisa com um layout diferente, e você tem um lugar claro para se concentrar em fazer o mapeamento. Se você não quisesse usar essa restrição e tivesse o mapeamento em outro lugar, ter diferentes maneiras de representar os dados pode impactar o código em lugares que ele não deveria mudar.

Eglasius
fonte
1

É tudo uma questão de interpretação e contexto. Eles podem ser muito semelhantes ou mesmo muito diferentes, mas contanto que a solução faça o trabalho, o que está em um nome!

c00ke
fonte
1

Repositório é um padrão, esta é uma maneira de implementar as coisas de forma padronizada para reutilizar o código como podemos.

Xulfee
fonte
1

A vantagem de usar o padrão de repositório é simular sua camada de acesso a dados, para que você possa testar o código da camada de negócios sem chamar o código DAL. Existem outras grandes vantagens, mas isso parece ser muito vital para mim.

Shailesh
fonte
1
Você ainda pode simular um DAL, não precisa ser um repositório em si. O ponto importante é que qualquer estratégia de acesso a dados que você usar deve implementar uma interface. Isso permitirá que você use contêineres IoC, bem como teste perfeitamente seu código de negócios sem a necessidade de um armazenamento de dados.
cdaq
0

Pelo que entendi, eles podem significar basicamente a mesma coisa - mas a nomenclatura varia de acordo com o contexto.

Por exemplo, você pode ter uma classe Dal / Dao que implementa uma interface IRepository.

Dal / Dao é um termo da camada de dados; as camadas mais altas de seu aplicativo pensam em termos de Repositórios.

remotefacade
fonte
0

Portanto, na maioria dos casos (simples), o DAO é uma implementação do Repositório?

Até onde eu entendo, parece que o DAO lida precisamente com o acesso db (CRUD - Não seleciona embora ?!), enquanto o Repositório permite abstrair todo o acesso aos dados, talvez sendo uma fachada para vários DAO (talvez diferentes fontes de dados).

Estou no caminho certo?

Mike
fonte
Na verdade, eu inverteria isso e diria que, de um ponto de vista simplista, um Repositório é um estilo de implementação específico para um DAO, mas sim, você está no caminho certo. (R de CRUD = Leitura, então essa é sua escolha.)
Jeromy Irvine
0

No mundo externo (ou seja, código do cliente), o repositório é o mesmo que DAL, exceto:

(1) seus métodos de inserir / atualizar / deletar são restritos a ter o objeto de contêiner de dados como parâmetro.

(2) para a operação de leitura, pode ser necessária uma especificação simples como um DAL (por exemplo, GetByPK) ou uma especificação avançada.

Internamente, ele funciona com um Data Mapper Layer (por exemplo, contexto de estrutura de entidade, etc.) para executar a operação CRUD real.

O que o padrão de repositório não significa: -

Além disso, tenho visto muitas pessoas ficarem confusas por ter um método Save separado como a implementação de amostra do padrão de repositório, além dos métodos Insert / Update / Delete que confirma todas as alterações na memória realizadas pelos métodos insert / update / delete no banco de dados. Podemos ter um método Save definitivamente em um repositório, mas isso não é responsabilidade do repositório isolar CUD na memória (Criar, Atualizar, Excluir) e métodos de persistência (que realiza a operação real de gravação / alteração no banco de dados), mas o responsabilidade do padrão da Unidade de Trabalho.

Espero que isto ajude!

Ashraf Alam
fonte
0

Alguém poderia argumentar que um "repositório" é uma classe específica e um "DAL" é a camada inteira que consiste em repositórios, DTOs, classes de utilitários e tudo o mais que for necessário.

Jonathan Allen
fonte