Подтвердить что ты не робот

Стандарт хранилища Стандартизация методов

Все, что я пытаюсь найти правильное определение шаблона репозитория.

Мое первоначальное понимание было таким (крайне ошарашенным)

  • Отделите свои бизнес-объекты от своих объектов данных.
  • Стандартизировать методы доступа на уровне доступа к данным.

Я действительно видел 2 разных варианта реализации, и нет никаких официальных примеров онлайн, те, которые я видел, спрятаны в книгах.

Реализация 1:

public Interface IRepository<T>{
      List<T> GetAll();
      void Create(T p);
      void Update(T p);
}


public interface IProductRepository: IRepository<Product> {
      //Extension methods if needed
       List<Product> GetProductsByCustomerID();
}

Реализация 2:

public interface IProductRepository {
      List<Product> GetAllProducts();
      void CreateProduct(Product p);
      void UpdateProduct(Product p);
      List<Product> GetProductsByCustomerID();
}

Обратите внимание, что первое является общим Get/Update/GetAll и т.д., второе - это то, что я бы назвал "DAO".

Оба совместно используют извлечение из ваших объектов данных. Что мне нравится, но я могу сделать то же самое с простым DAO. Однако вторая часть стандартизирует операции доступа, в которых я вижу значение, если вы внедряете это предприятие, люди легко узнают набор методов доступа для вашего репозитория.

Я ошибаюсь, полагая, что стандартизация доступа к данным является неотъемлемой частью этого шаблона? Если оба правильны, почему вы решили сделать реализацию 2?

Rhino содержит хорошую статью об осуществлении 1, и, конечно, MS имеет неопределенный определение, а пример реализации 2 - здесь.

4b9b3361

Ответ 1

Во-вторых, цитата Фаулера цитируется oded. Я хочу отметить, что он сказал "подобный коллекции" интерфейс. Как вы реализуете коллекцию, как интерфейс, безусловно, зависит от вас, но никто не может и не должен пытаться скрыть тот факт, что он представляет собой удаленный источник данных. Поэтому он существенно отличается от коллекции в памяти, которая не нуждается в очистке изменений в удаленном хранилище данных. Механизм отслеживания изменений вашего ORM или вашего собственного решения определяет, насколько прозрачным это может быть сделано для вызывающего. Обычно удаление должно быть помечено явно, вставки являются доступными для обнаружения (постоянство по достижимости), и обновления иногда также должны быть отмечены явно. Объедините это со сложными зависимостями ваших совокупных корней, и вы увидите, что не такая коллекция.

Нет такой вещи, как "реализация канонического репозитория".

Существует постоянная борьба между сторонниками базового класса базового репозитория и теми, кто предпочитает реализовать каждый репозиторий самостоятельно. Хотя общая реализация привлекательна в простых сценариях, вы очень часто обнаружите, что это очень непроницаемая абстракция. Например, некоторые из ваших агрегатов могут быть только удалены (cistomizable через переопределение виртуальных методов), в то время как другие могут вообще не поддерживать операцию удаления.

Удостоверьтесь, что вы понимаете последствия каждого подхода, прежде чем принимать решение о том, какой маршрут принять. Грег Янг имеет хороший пост по существу общих хранилищ.

http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx

Ответ 2

От Мартина Фаулера "Шаблоны архитектуры корпоративных приложений" определение шаблона репозитория:

Промежуточное взаимодействие между слоями отображения домена и данных с использованием интерфейса, подобного коллекции, для доступа к объектам домена.

Итак, оба подхода верны.

Ответ 3

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

Я рекомендую, чтобы ваш разработчик IProductRepository получил доступ к универсальному IRepository<Product> через делегирование и ввел его через конструктор, чтобы вы могли составить свой класс, возможно, много IR-серверов и сгруппировать их за одним интерфейсом, что имеет смысл.

Я написал блог по этой теме, в то время как он специально ссылается на NHibernate, этот шаблон может быть применен к любому типу репозитория: Создание общего родового и расширяемого репозитория NHiberate версия 2

Ответ 4

С введением LINQ в .NET общий шаблон репозитория становится намного проще реализовать:

public interface IRepository<T> : IQueryable<T>
{
    void Add(T item);
    void Remove(T item);
}

Чтобы квалифицироваться как репозиторий, он просто должен иметь доступ к данным в базовом хранилище (легко предоставляется IQueryable) и изменять содержащиеся данные.

Вы можете предоставить расширения базовому интерфейсу, чтобы обеспечить перехваты для более сущностного поведения (например, проводки в вызове хранимой процедуры для репозитория на основе SQL), но большинство операций может быть выполнено простым интерфейсом.

Ответ 5

В дополнение к вашему универсальному интерфейсу репозитория (реализация 1) и вашим вариантам в репозитории, специфичном для ролей (реализация 2), вы также можете рассмотреть общий репозиторий методов:

public interface IRepository
{
    void Save<ENTITY>(ENTITY entity) where ENTITY : DomainEntity;

    ENTITY Load<ENTITY>(Guid id) where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>() where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery)
        where ENTITY : DomainEntity;
}

Эта третья версия исходит от этого blogpost от Jimmy Bogard, где он также выражает предпочтение универсальному интерфейсу репозитория. Я обычно следую за ним с базовым базовым базой репозитория, который реализует этот интерфейс; Таким образом, мне нужно только реализовать материал, который отличается для каждого объекта домена.

Ответ 6

Обычно я использую общий репозиторий с композицией вместо наследования. Это дает мне преимущество универсальной реализации с контролем того, какие методы выставлять.

Что-то вроде этого:

public Interface IRepository<T>{
  List<T> GetAll();
  void Create(T p);
  void Update(T p);
}


public interface IProductRepository {
  //Extension methods if needed
   List<Product> GetProductsByCustomerID();
   List<T> GetAll();
   void Create(T p);
   //Let assume here you should not be able to update the products
}

public ProductRepository : IProductRepository {
    private IRepository _repository;

    public ProductRepository(IRepository repository) {
        this._repository = repository;
    }

       List<T> GetAll() 
       {
            _repository.GetAll();
       }

       void Create(T p) 
       {
            _repository.Create(p);
       }

       List<Product> GetProductsByCustomerID() 
       {
          //..implementation goes here
       }
}

Ответ 7

Шаблон репозитория является одним из наиболее часто используемых шаблонов в разработке программного обеспечения. Есть много сообщений, которые могут быть отмечены как ответ на ваш вопрос. То, что мне нравится выделять, - это тот факт, что хорошая реализация репозитория будет улучшена, если вы используете IoC (Autofac, Windsor и т.д.). Я давно играл с некоторыми основами ADO.NET(LinqToSql, EF) и NHibernate. Вы всегда можете получить преимущества от общей реализации, если используете IoC. Вы можете определить интерфейсы для своих конкретных репозиториев и решить, когда вам действительно нужны определенные действия.