Как правильно использовать шаблон репозитория?
Мне интересно, как я должен группировать свои репозитории? Как из примеров, которые я видел на asp.net mvc и в моих книгах они в основном используют один репозиторий для каждой таблицы базы данных. Но это похоже на множество репозиториев, из-за которых вам придется вызывать много репозиториев позже для насмешек и прочего.
Так что я предполагаю, что я должен сгруппировать их. Однако я не уверен, как их сгруппировать.
прямо сейчас я сделал регистрационный репозиторий для обработки всей моей регистрации материал. Однако есть как 4 таблицы, которые мне нужно обновить, и прежде чем у меня было 3 репозитория для этого.
например, одна из таблиц является таблицей лицензий. При регистрации я смотрю на свой ключ и проверить его, чтобы увидеть, если существует в базе данных. Теперь что произойдет, если мне нужно проверить этот лицензионный ключ или что-то еще из этой таблицы в другом месте, кроме регистрации?
одном месте может быть логин(проверьте, если ключ не истек).
Так что бы я сделал в такой ситуации? Перепишите код еще раз (перерыв сухой)? Попробуйте объединить эти 2 репозитория вместе и надеяться, что ни один из методов не нужен в какой - то другой момент времени(например, у меня может быть метод, который проверяет, используется ли имя пользователя-возможно, мне это понадобится где-то еще).
кроме того, если я объединю их вместе, мне понадобится либо 2 слоя сервиса, идущих в один и тот же репозиторий, так как я думаю, что вся логика для 2 разных частей сайта будет длинной, и мне придется иметь имена, такие как ValidateLogin (), ValdiateRegistrationForm (), ValdiateLoginRetrievePassword() и т. д.
или позвонить в репозиторий в любом случае и просто иметь странное звучащее имя вокруг?
просто кажется трудным сделать репозиторий, который имеет достаточно общее имя, чтобы вы могли использовать его для многих мест вашего приложения и все еще иметь смысл, и я не думаю, что вызов другого репозитория в репозитории будет хорошей практикой?
7 ответов:
одна вещь, которую я сделал неправильно, когда играл с шаблоном репозитория - так же, как и вы, я думал, что таблица относится к репозиторию 1:1. Когда мы применяем некоторые правила из управляемых доменом репозиториев проектирования-группирования проблема часто исчезает.
репозиторий должен быть в совокупный корень а не таблица. Это означает - если сущность не должна жить одна (т. е.-если у вас есть
Registrant
, который участвует в частностиRegistration
) - это просто сущность, она не нуждается репозиторий, он должен быть обновлен/создан / получен через репозиторий aggregate root, к которому он принадлежит.конечно-во многих случаях этот метод сокращения количества репозиториев (на самом деле - это скорее метод структурирования вашей модели домена) не может быть применен, потому что каждая сущность должна быть агрегированным корнем (что сильно зависит от вашего домена, я могу предоставить только слепые догадки). В вашем примере -
License
кажется, совокупный корень, потому что вы должны быть в состоянии проверьте их без контекстаRegistration
сущности.но это не ограничивает нас в репозиториях каскад (
Registration
репозиторий имеет право ссылатьсяLicense
репозиторий при необходимости). Это не ограничивает нас ссылкойLicense
репозиторий (предпочтительно - через МОК) непосредственно изRegistration
"объект".просто постарайтесь не вести свой дизайн через осложнения, связанные с технологиями или непониманием чего-то. Группировка репозиториев в
ServiceX
просто потому, что вы не хочу строить 2 репозитория-это не очень хорошая идея.гораздо лучше было бы дать ему имя -
RegistrationService
т. е.но сервисы следует избегать в целом - они часто являются причиной, которая приводит к анемичной домена модель.
EDIT:
Начните использовать МОК. Это действительно облегчает боль от инъекционных зависимостей.
Вместо того, чтобы писать:var registrationService = new RegistrationService(new RegistrationRepository(), new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
вы сможете написать:
var registrationService = IoC.Resolve<IRegistrationService>();
P. s. было бы лучше использовать так называемый Common service locator но это только пример.
одна вещь, которую я начал делать, чтобы решить эту проблему, - это фактически разработать службы, которые обертывают N репозиториев. Надеюсь, ваши рамки DI или IoC могут помочь сделать это проще.
public class ServiceImpl { public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { } }
это имеет смысл? Кроме того, я понимаю, что говоря об услугах в этом поместье, может быть, или не может на самом деле соответствовать принципам DDD, я просто делаю это, потому что это, кажется, работает.
то, что я делаю, это у меня есть абстрактный базовый класс, определенный следующим образом:
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); }
затем вы можете получить репозиторий из абстрактного базового класса и расширить свой единственный репозиторий до тех пор, пока общие аргументы отличаются, например;
public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>, ReadOnlyRepository<string, IRegistrationItem>
etc....
мне нужны отдельные репозитории, потому что у нас есть ограничения на некоторые из наших хранилищах, и это дает нам максимальную гибкость. Надеюсь, это поможет.
у меня есть это как мой класс репозитория, и да, я расширяюсь в репозитории таблицы / области, но все же мне иногда приходится ломаться.
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>(); } } } }
EDIT
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 ) { }
у меня также есть datacontext, который был создан с помощью Linq2SQL.класс dbml.
Итак, теперь у меня есть стандартный репозиторий, реализующий стандартные вызовы, такие как All и Find, и в моем AdminRepository у меня есть конкретные вызовы.
не отвечает на вопрос сухой, хотя я этого не делаю думать.
вот пример реализации универсального репозитория с использованием FluentNHibernate. Он способен сохранять любой класс, для которого вы написали mapper. Он даже способен генерировать вашу базу данных на основе классов mapper.
шаблон репозитория-это плохой шаблон дизайна. Я работаю со многими старыми проектами .Net, и этот шаблон обычно вызывает ошибки "распределенные транзакции", "частичный откат" и "пул соединений исчерпан", которых можно было бы избежать. Проблема в том, что шаблон пытается обрабатывать соединения и транзакции внутри, но они должны обрабатываться на уровне контроллера. Также EntityFramework уже абстрагирует много логики. Я бы предложил использовать шаблон службы вместо повторного использования общий код.
Я предлагаю вам посмотреть Резкий Архитектуры. Они предлагают использовать один репозиторий для каждой сущности. Я использую его в настоящее время в моем проекте и мы довольны результатами.