Li recentemente que não é uma boa prática usar o padrão de repositório em conjunto com um ORM. Pelo meu entendimento, isso ocorre porque a abstração que eles fornecem sobre o banco de dados SQL é muito gotejante para ser contida pelo padrão.
Eu tenho algumas perguntas sobre isso:
O que você faz se deseja trocar os ORMs? Você teria um código específico do ORM em seu aplicativo se não o contivesse em um repositório.
O padrão do repositório ainda é válido quando você não está usando um ORM e você está usando o ADO.NET para acessar dados e preencher os dados do objeto?
Se você usa um ORM, mas não o padrão do repositório, onde mantém as consultas mais usadas? Seria sensato representar cada consulta como uma classe e ter algum tipo de fábrica de consultas para criar instâncias?
fonte
Respostas:
1) É verdade, mas com que frequência você muda um ORM?
2) Eu diria que sim, porque um contexto ORM é uma espécie de repositório e oculta muito trabalho envolvendo a criação de consultas, recuperação de dados, mapeamento etc. Se você não usa um ORM, essa lógica ainda precisa residir em algum lugar. Não sei se isso se qualificaria como o padrão de repositório no sentido mais estrito da palavra ...
3) Encapsular consultas é algo que vejo frequentemente, mas isso geralmente é mais para fins de teste / stub. Fora isso, eu seria cuidadoso ao reutilizar uma consulta em diferentes partes de um aplicativo, porque você corre o risco de criar uma dependência de algo que pode mudar n-vezes (n sendo o número de locais em que você usa a consulta).
fonte
Eu ainda não estava em uma posição em que a empresa de repente decidiu mudar a tecnologia de acesso a dados. Se isso acontecer, será necessário algum trabalho. Costumo abstrair operações de acesso a dados por meio de interfaces. O repositório é uma maneira de resolver isso.
Eu teria um assembly diferente para implementação concreta da minha camada de acesso a dados. Por exemplo, eu posso ter:
Company.Product.Data
eCompany.Product.Data.EntityFramework
montagens. O primeiro assembly seria usado apenas para interfaces, enquanto outro seria uma implementação concreta da lógica de acesso a dados do Entity Framework.Eu acho que cabe a você decidir qual padrão é válido ou não. Eu usei um padrão de repositório na camada de apresentação. Uma coisa a ter em mente é que as pessoas gostam de lançar responsabilidades nos repositórios. Antes que você perceba, sua classe de repositório estará dançando, cantando e fazendo todo tipo de coisa. Você quer evitar isso.
Eu vi uma classe de repositório que começou com as responsabilidades GetAll, GetById, Update e Delete, o que é bom. Quando o projeto foi concluído, essa mesma classe tinha dezenas de métodos (responsabilidades) que nunca deveriam estar lá. Por exemplo, GetByForename, GetBySurname, UpdateWithExclusions e todos os tipos de coisas malucas.
É aqui que consultas e comandos entram em jogo.
Eu acho que é uma boa idéia usar consultas e comandos em vez de repositórios. Eu faço o seguinte:
Defina a interface para uma consulta. Isso o ajudará a testar a unidade. Por exemplo
public interface IGetProductsByCategoryQuery { ... }
Defina a implementação concreta de uma consulta. Você poderá injetá-las através da estrutura de IoC de sua escolha. Por exemplo
public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
Agora, em vez de poluir o repositório com dezenas de responsabilidades, simplesmente agrupo minhas consultas em espaços para nome. Por exemplo, uma interface para a consulta acima pode residir:
Company.SolutionName.Products.Queries
e a implementação pode residir emCompany.SolutionName.Products.Queries.Implementation
Quando se trata de atualizar ou remover dados, eu uso o padrão de comando da mesma maneira.
Alguns podem discordar e dizer que antes que o projeto seja concluído, você terá dezenas de classes e espaços para nome. Sim você irá. Na minha opinião, é uma coisa boa, pois você pode navegar pela solução no IDE de sua escolha e ver instantaneamente que tipo de responsabilidades um componente possui. Se você decidiu usar um padrão de repositório, precisará procurar dentro de cada classe de repositório tentando definir suas responsabilidades.
fonte
AVISO LEGAL: O que se segue é baseado no meu entendimento e breve experiência do referido padrão (que é o repositório). Eu posso estar fazendo errado ... na verdade, tenho certeza de que estou fazendo errado :). Portanto, embora seja uma tentativa de resposta, também é uma pergunta disfarçada.
Estou usando o padrão Repository para abstrair a camada de acesso a dados, que na maioria dos casos é um ORM. É uma interface genérica, com métodos para criar, ler, atualizar, excluir e implementar classes para LINQ to SQL e EF até agora. Eu poderia fazer uma implementação que grava em arquivos XML no disco (apenas um exemplo selvagem do que eu poderia fazer com ele). Não estou implementando a Unidade de trabalho, pois ela é suportada pelos ORMs. Se necessário, eu provavelmente poderia implementá-lo. Eu gosto dessa maneira porque, até agora, me proporcionou uma boa separação. Não estou dizendo que não há alternativas melhores.
Para responder suas perguntas:
Para dar outro exemplo, os funcionários da Umbraco abstraíram o contêiner de DI, para o caso de quererem mudar para outra coisa.
fonte
Se o ORM oferece flexibilidade de LINQ, carregamento ansioso etc., não o ocultarei atrás de nenhuma camada extra.
Se envolver sql bruto (micro ORM), o "método por consulta" deve ser usado de qualquer maneira para obter reutilização, tornando assim o padrão do repositório um bom ajuste.
Por que você precisaria mudar?
O que possui a maioria dos recursos de que você precisa deve ser usado. É possível que um novo lançamento do ormX traga novos recursos e seja melhor que o atual, mas ...
Se você optar por ocultar o orm, poderá usar apenas os recursos que todos os candidatos têm em comum.
Por exemplo, você não pode usar
Dictionary<string, Entity>
propriedades em suas entidades porque o ormY não pode lidar com elas.Supondo que o LINQ seja usado, a maioria dos comutadores orm está apenas alternando as referências da biblioteca e substituindo
session.Query<Foo>()
porcontext.Foos
ou similar até compilar. Tarefa chata, mas leva menos tempo do que codificar a camada de abstração.Sim. O código deve ser reutilizável e isso significa colocar a construção do sql, a materialização do objeto etc. em um só lugar (classe separada). Você também pode chamar a classe "XRepository" e extrair uma interface dela.
Supondo que o LINQ seja usado, um wrapper de classe seria um exagero no IMHO. Uma maneira melhor seria métodos de extensão
Qualquer código usado em vários locais (ou com potencial) e bastante complicado (propenso a erros) deve ser extraído para um local centralizado.
fonte