Как правильно использовать шаблон репозитория?


Мне интересно, как я должен группировать свои репозитории? Как из примеров, которые я видел на asp.net mvc и в моих книгах они в основном используют один репозиторий для каждой таблицы базы данных. Но это похоже на множество репозиториев, из-за которых вам придется вызывать много репозиториев позже для насмешек и прочего.

Так что я предполагаю, что я должен сгруппировать их. Однако я не уверен, как их сгруппировать.

прямо сейчас я сделал регистрационный репозиторий для обработки всей моей регистрации материал. Однако есть как 4 таблицы, которые мне нужно обновить, и прежде чем у меня было 3 репозитория для этого.

например, одна из таблиц является таблицей лицензий. При регистрации я смотрю на свой ключ и проверить его, чтобы увидеть, если существует в базе данных. Теперь что произойдет, если мне нужно проверить этот лицензионный ключ или что-то еще из этой таблицы в другом месте, кроме регистрации?

одном месте может быть логин(проверьте, если ключ не истек).

Так что бы я сделал в такой ситуации? Перепишите код еще раз (перерыв сухой)? Попробуйте объединить эти 2 репозитория вместе и надеяться, что ни один из методов не нужен в какой - то другой момент времени(например, у меня может быть метод, который проверяет, используется ли имя пользователя-возможно, мне это понадобится где-то еще).

кроме того, если я объединю их вместе, мне понадобится либо 2 слоя сервиса, идущих в один и тот же репозиторий, так как я думаю, что вся логика для 2 разных частей сайта будет длинной, и мне придется иметь имена, такие как ValidateLogin (), ValdiateRegistrationForm (), ValdiateLoginRetrievePassword() и т. д.

или позвонить в репозиторий в любом случае и просто иметь странное звучащее имя вокруг?

просто кажется трудным сделать репозиторий, который имеет достаточно общее имя, чтобы вы могли использовать его для многих мест вашего приложения и все еще иметь смысл, и я не думаю, что вызов другого репозитория в репозитории будет хорошей практикой?

7 85

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 уже абстрагирует много логики. Я бы предложил использовать шаблон службы вместо повторного использования общий код.

Я предлагаю вам посмотреть Резкий Архитектуры. Они предлагают использовать один репозиторий для каждой сущности. Я использую его в настоящее время в моем проекте и мы довольны результатами.