Estou me perguntando como devo agrupar meus repositórios? Como nos exemplos que vi no asp.net mvc e em meus livros, eles usam basicamente um repositório por tabela de banco de dados. Mas isso parece ser um monte de repositórios levando você a ter que chamar muitos repositórios mais tarde para simulação e outras coisas.
Então, acho que devo agrupá-los. No entanto, não tenho certeza de como agrupá-los.
Agora mesmo fiz um repositório de registro para lidar com todas as minhas coisas de registro. No entanto, existem cerca de 4 tabelas que preciso atualizar e antes eu tinha 3 repositórios para fazer isso.
Por exemplo, uma das tabelas é uma tabela de licença. Quando eles se registram, eu olho sua chave e verifico se existe no banco de dados. Agora, o que acontece se eu precisar verificar esta chave de licença ou alguma outra coisa daquela tabela em algum outro local diferente do registro?
Um ponto pode ser o login (verifique se a chave não expirou).
Então, o que eu faria nesta situação? Reescrever o código novamente (quebrar DRY)? Tente mesclar esses 2 repositórios e espero que nenhum dos métodos seja necessário em algum outro momento (como talvez eu possa ter um método que verifica se userName é usado - talvez eu precise disso em outro lugar).
Além disso, se eu mesclá-los, precisaria de 2 camadas de serviço indo para o mesmo repositório, pois acho que ter toda a lógica para 2 partes diferentes de um site seria longo e eu teria que ter nomes como ValidateLogin (), ValdiateRegistrationForm () , ValdiateLoginRetrievePassword () e etc.
Ou ligar para o Repositório de qualquer maneira e apenas ter um nome estranho por aí?
Simplesmente parece difícil fazer um repositório com um nome geral o suficiente para que você possa usá-lo para muitos pontos de sua aplicação e ainda faça sentido e eu não acho que chamar outro repositório em um repositório seria uma boa prática?
fonte
Respostas:
Uma coisa que eu fiz de errado quando brinquei com o padrão de repositório - assim como você, pensei que a tabela se relacionasse com o repositório 1: 1. Quando aplicamos algumas regras do Domain Driven Design - o problema de agrupamento de repositórios geralmente desaparece.
O repositório deve ser por raiz agregada e não por tabela. Isso significa - se a entidade não deve viver sozinha (ou seja - se você tem um
Registrant
participante em particularRegistration
) - é apenas uma entidade, não precisa de um repositório, deve ser atualizada / criada / recuperada através do repositório de raiz agregada dela pertence.Claro - em muitos casos, esta técnica de reduzir a contagem de repositórios (na verdade - é mais uma técnica para estruturar seu modelo de domínio) não pode ser aplicada porque cada entidade deve ser uma raiz agregada (que depende muito de seu domínio, Posso fornecer apenas palpites cegos). Em seu exemplo -
License
parece ser uma raiz agregada porque você precisa ser capaz de verificá-los sem contexto deRegistration
entidade.Mas isso não nos restringe a repositórios em cascata (o
Registration
repositório pode fazer referência aoLicense
repositório, se necessário). Isso não nos restringe a referenciarLicense
repositório (preferível - por meio de IoC) diretamente doRegistration
objeto.Apenas tente não conduzir seu projeto por complicações fornecidas por tecnologias ou por mal-entendidos. Agrupar repositórios
ServiceX
apenas porque você não quer construir 2 repositórios não é uma boa ideia.Muito melhor seria dar-lhe um nome próprio -
RegistrationService
ou seja,Mas os serviços devem ser evitados em geral - eles geralmente são a causa que leva ao modelo de domínio anêmico .
EDIT:
Comece a usar IoC. Ele realmente alivia a dor de injetar dependências.
Em vez de escrever:
var registrationService = new RegistrationService(new RegistrationRepository(), new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
você será capaz de escrever:
var registrationService = IoC.Resolve<IRegistrationService>();
Ps Seria melhor usar o chamado localizador de serviço comum, mas isso é apenas um exemplo.
fonte
Uma coisa que comecei a fazer para resolver isso é realmente desenvolver serviços que envolvam N repositórios. Esperançosamente, seus frameworks DI ou IoC podem ajudar a tornar isso mais fácil.
public class ServiceImpl { public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { } }
Isso faz sentido? Além disso, eu entendo que falar de serviços nesta mansão pode ou não estar de acordo com os princípios do DDD, eu só faço isso porque parece funcionar.
fonte
O que estou fazendo é ter uma classe base abstrata definida da seguinte forma:
public abstract class ReadOnlyRepository<T,V> { V Find(T lookupKey); } public abstract class InsertRepository<T> { void Add(T entityToSave); } public abstract class UpdateRepository<T,V> { V Update(T entityToUpdate); } public abstract class DeleteRepository<T> { void Delete(T entityToDelete); }
Você pode então derivar seu repositório da classe base abstrata e estender seu único repositório, desde que os argumentos genéricos sejam diferentes, por exemplo;
public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>, ReadOnlyRepository<string, IRegistrationItem>
etc ....
Eu preciso de repositórios separados porque temos restrições em alguns de nossos repositórios e isso nos dá o máximo de flexibilidade. Espero que isto ajude.
fonte
Eu tenho isso como minha classe de repositório e sim, eu estendo no repositório de tabela / área, mas ainda às vezes tenho que quebrar o DRY.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MvcRepository { public class Repository<T> : IRepository<T> where T : class { protected System.Data.Linq.DataContext _dataContextFactory; public IQueryable<T> All() { return GetTable.AsQueryable(); } public IQueryable<T> FindAll(Func<T, bool> exp) { return GetTable.Where<T>(exp).AsQueryable(); } public T Single(Func<T, bool> exp) { return GetTable.Single(exp); } public virtual void MarkForDeletion(T entity) { _dataContextFactory.GetTable<T>().DeleteOnSubmit(entity); } public virtual T CreateInstance() { T entity = Activator.CreateInstance<T>(); GetTable.InsertOnSubmit(entity); return entity; } public void SaveAll() { _dataContextFactory.SubmitChanges(); } public Repository(System.Data.Linq.DataContext dataContextFactory) { _dataContextFactory = dataContextFactory; } public System.Data.Linq.Table<T> GetTable { get { return _dataContextFactory.GetTable<T>(); } } } }
EDITAR
public class AdminRepository<T> : Repository<T> where T: class { static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString); public AdminRepository() : base( dc ) { }
Eu também tenho um datacontext que foi criado usando a classe Linq2SQL.dbml.
Portanto, agora eu tenho um repositório padrão implementando chamadas padrão como All e Find e em meu AdminRepository tenho chamadas específicas.
Não responde à pergunta de DRY, embora eu não ache.
fonte
Aqui está um exemplo de uma implementação de Repositório genérico usando FluentNHibernate. Ele é capaz de persistir qualquer classe para a qual você escreveu um mapeador. É ainda capaz de gerar seu banco de dados com base nas classes do mapeador.
fonte
O padrão Repositório é um padrão de design ruim. Eu trabalho com muitos projetos .Net antigos e esse padrão normalmente causa erros "Transações distribuídas", "Reversão parcial" e "Pool de conexões esgotado" que podem ser evitados. O problema é que o padrão tenta lidar com conexões e transações internamente, mas essas devem ser feitas na camada do controlador. Além disso, o EntityFramework já abstrai muito da lógica. Eu sugeriria usar o padrão de serviço em vez de reutilizar o código compartilhado.
fonte
Eu sugiro que você dê uma olhada em Sharp Architecture . Eles sugerem o uso de um repositório por entidade. Estou usando atualmente em meu projeto e estou muito satisfeito com os resultados.
fonte