Retornando um IQueryable de um IRepository


8

Usando o padrão Repository, é adequado retornar um IQueryable de um conjunto de dados (tabela) para uso genérico?

É muito útil em muitos casos, especialmente ao usar bibliotecas externas que utilizam essa interface, por exemplo, alguns plugins que classificam / filtram e se ligam a elementos da interface do usuário.

No entanto, expor um IQueryable às vezes parece deixar o design propenso a erros. Isso, associado a um uso incorreto de carregamento lento, pode levar a graves ocorrências de desempenho.

Por outro lado, ter métodos de acesso para cada uso parece redundante e também muito trabalhoso (considerando testes de unidade, etc.).


2
OMI: Ocultar a tecnologia de persistência (EF, NHibernate) dos desenvolvedores é uma má ideia. Apenas exponha o que essa tecnologia expõe.
— Euphoric

@Euphoric Ok, mas se no ASP.NET MVC eu tenho controladores com 3000 linhas onde as pessoas criam com alegria new DbContext()sempre que precisam e ligam SaveChanges()quando querem. Não é possível testar nada e a única coisa que consigo pensar é em uma camada adicional ocultando-a.
— Mateusz

@Mateusz Isso não é problema da tecnologia, mas das pessoas. Você tem desenvolvedores de baixa qualidade ou gerenciamento de baixa qualidade, que é incapaz de treinar adequadamente esses desenvolvedores.
— Eufórico

Respostas:


12

Mark Seemann tem um excelente post sobre este assunto: IQueryable is Tight Coupling . Ele resume bem na parte final (ênfase minha):

Você pode pensar que tudo isso é um exercício teórico, mas realmente importa. Ao escrever o Código Limpo, é importante projetar uma API de forma que fique claro o que ela faz.

Uma interface como essa oferece garantias falsas:

public interface IRepository
{
    IQueryable<T> Query<T>();
}

De acordo com a lei do LSP e Postel, parece garantir que você possa escrever qualquer expressão de consulta (não importa quão complexa) contra a instância retornada, e sempre funcionaria .

Na prática, isso nunca vai acontecer.

Os programadores que definem essas interfaces invariavelmente têm em mente um ORM específico e implicitamente tendem a permanecer dentro dos limites que sabem que são seguros para esse ORM específico. Esta é uma abstração com vazamento.

Se você tem um ORM específico em mente, seja explícito. Não esconda atrás de uma interface. Cria a ilusão de que você pode substituir uma implementação por outra. Na prática, isso é impossível. Imagine tentar fornecer uma implementação em um armazenamento de eventos.

O bolo é uma mentira.

O ORM, como o Entity Framework, é uma implementação do padrão Repositório e Unidade de Trabalho. Não há necessidade de envolvê-los em outro.


Obrigado pela resposta. Parece que minhas preocupações atendem às de Seemann muitas vezes, mas na verdade não tomei tempo para lê-lo, o que pretendo. A única coisa que discordo é que um repositório - mesmo se fortemente acoplado - é muito útil para encapsular a lógica de negócios, mesmo que em um nível de acesso mais simples (por exemplo: VisibleItems, DeletedItems) etc., e ajude com o conceito DRY.
— Mihalis Bagos

@ Kristof Apenas uma pergunta para "Entity Framework são implementações do repositório e do padrão da Unidade de Trabalho". O que posso fazer para que as pessoas não coloquem new DbContext()controlador e lógica complexa no método único no MVC e também não coloquem lógica nas visualizações? Eu tenho código legado em que não posso fazer nenhum teste de unidade. Para habilitar os testes e impedir que as pessoas façam códigos muito ruins, preciso de uma camada adicional. Portanto, preciso implementar meus próprios repositórios para fins educacionais.
— Mateusz

Existem outras opções, como classes de serviço ou classes de comando e consulta.
— Kristof Claes

1

Não haverá consenso sobre este assunto. Na minha opinião e experiência, um Repositório deve retornar objetos com usos específicos. Pelo menos se você usar o Repository Pattern conforme definido por Eric Evens no DDD. Um repositório é uma "ponte" que conecta lógica de negócios, persistência e fábricas.

Se você deseja acessar a persistência mais diretamente, talvez esteja procurando o Padrão de Gateway.

No entanto, pelo que você diz aqui, você gostaria de ocultar a exposição à persistência para que o Padrão de Proxy seja útil para você.


Embora a exposição à persistência não seja uma preocupação principal, é obrigatória pelo menos uma abstração de nível superior para padrões como entidades pai-filho. Também examinarei esses padrões, obrigado!
— Mihalis Bagos
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.