Мне интересно, как мне группировать свои репозитории? Как и в примерах, которые я видел на asp.net mvc и в моих книгах, они в основном используют один репозиторий для каждой таблицы базы данных. Но похоже, что много репозиториев, из-за чего вам придется позже вызывать множество репозиториев для насмешек и прочего.
Так что я предполагаю, что мне следует сгруппировать их. Однако я не уверен, как их сгруппировать.
Прямо сейчас я сделал репозиторий регистрации, чтобы обрабатывать все мои регистрационные вещи. Однако есть около 4 таблиц, которые мне нужно обновить, и до того, как у меня было 3 репозитория для этого.
Например, одна из таблиц - это таблица лицензий. Когда они регистрируются, я смотрю на их ключ и проверяю, есть ли он в базе данных. Что произойдет, если мне нужно будет проверить этот лицензионный ключ или что-то еще из этой таблицы в другом месте, кроме регистрации?
Одно место может быть логином (проверьте, не истек ли срок действия ключа).
Итак, что я буду делать в этой ситуации? Перепишите код еще раз (прервать СУХОЙ)? Попробуйте объединить эти два репозитория вместе и надейтесь, что ни один из методов не понадобится в какой-то другой момент времени (например, возможно, у меня может быть метод, который проверяет, используется ли userName - возможно, мне это понадобится где-то еще).
Кроме того, если я объединю их вместе, мне понадобятся 2 уровня обслуживания, идущие в один и тот же репозиторий, поскольку я думаю, что вся логика для двух разных частей сайта будет длинной, и мне нужно будет иметь такие имена, как ValidateLogin (), ValdiateRegistrationForm () , ValdiateLoginRetrievePassword () и т. Д.
Или все равно позвонить в Репозиторий и иметь какое-то странное имя?
Просто кажется сложным создать репозиторий с достаточно общим именем, чтобы вы могли использовать его для многих мест вашего приложения и при этом иметь смысл, и я не думаю, что вызов другого репозитория в репозитории будет хорошей практикой?
Ответы:
Одна вещь, которую я сделал неправильно, когда играл с шаблоном репозитория - как и вы, я думал, что эта таблица относится к репозиторию 1: 1. Когда мы применяем некоторые правила из Domain Driven Design - проблема группировки репозиториев часто исчезает.
Репозиторий должен быть для каждого агрегированного корня, а не для таблицы. Это означает, что если объект не должен жить один (то есть - если у вас есть объект,
Registrant
который участвует в частностиRegistration
) - это просто объект, ему не нужен репозиторий, он должен быть обновлен / создан / извлечен через репозиторий совокупного корня принадлежит.Конечно - во многих случаях этот метод уменьшения количества репозиториев (на самом деле - это больше метод структурирования вашей модели домена) не может быть применен, потому что каждый объект должен быть совокупным корнем (что сильно зависит от вашего домена, Могу только догадываться вслепую). В вашем примере -
License
кажется, что это совокупный корень, потому что вам нужно иметь возможность проверять их без контекстаRegistration
объекта.Но это не ограничивает нас каскадными репозиториями (
Registration
репозиторию разрешено ссылаться наLicense
репозиторий, если это необходимо). Это не ограничивает нас ссылками наLicense
репозиторий (желательно - через IoC) непосредственно изRegistration
объекта.Просто постарайтесь не доводить свой дизайн до усложнений, связанных с технологиями, или непонимания чего-либо. Группировать репозитории
ServiceX
только потому, что вы не хотите создавать 2 репозитория, - не лучшая идея.Гораздо лучше было бы дать ему собственное имя -
RegistrationService
т.е.Но в целом следует избегать услуг - они часто приводят к анемичной модели предметной области .
РЕДАКТИРОВАТЬ:
Начните использовать IoC. Это действительно облегчает введение зависимостей.
Вместо написания:
var registrationService = new RegistrationService(new RegistrationRepository(), new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
вы сможете написать:
var registrationService = IoC.Resolve<IRegistrationService>();
Ps. Было бы лучше использовать так называемый общий локатор сервисов, но это всего лишь пример.
источник
Одна вещь, которую я начал делать для решения этой проблемы, - это фактически разрабатывать сервисы, которые обертывают репозитории 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>
так далее....
Мне нужны отдельные репозитории, потому что у нас есть ограничения на некоторые из наших репозиториев, и это дает нам максимальную гибкость. Надеюсь это поможет.
источник
У меня это как класс репозитория, и да, я расширяю репозиторий таблицы / области, но все же мне иногда приходится ломать 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>(); } } } }
РЕДАКТИРОВАТЬ
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 ) { }
У меня также есть текст данных, который был создан с использованием класса Linq2SQL.dbml.
Итак, теперь у меня есть стандартный репозиторий, реализующий стандартные вызовы, такие как All и Find, а в моем AdminRepository есть определенные вызовы.
Не отвечает на вопрос о DRY, хотя не думаю.
источник
Вот пример универсальной реализации репозитория с использованием FluentNHibernate. Он способен сохранять любой класс, для которого вы написали картограф. Он даже способен сгенерировать вашу базу данных на основе классов сопоставления.
источник
Шаблон репозитория - плохой шаблон проектирования. Я работаю со многими старыми проектами .Net, и этот шаблон обычно вызывает ошибки «Распределенные транзакции», «Частичный откат» и «Исчерпание пула подключений», которых можно было избежать. Проблема в том, что шаблон пытается обрабатывать соединения и транзакции изнутри, но они должны обрабатываться на уровне контроллера. Также EntityFramework уже абстрагирует большую часть логики. Я бы предложил использовать шаблон Service вместо повторного использования общего кода.
источник
Предлагаю вам взглянуть на Sharp Architecture . Они предлагают использовать один репозиторий для каждой сущности. Я использую его в своем проекте и очень доволен результатами.
источник