Что такое IRepository и для чего он используется? - PullRequest
36 голосов
/ 25 декабря 2010

Что такое IRepository? Почему это используется, короткие и простые примеры не повредят.

Ответы [ 4 ]

46 голосов
/ 27 декабря 2010

MVC способствует разделению интересов, но это не останавливается на уровне MVC.

Доступ к данным сам по себе является проблемой.Это должно быть сделано в бите M MVC, то есть в модели.Как вы структурируете свою модель, зависит от вас, но люди обычно следуют проверенным и проверенным схемам (зачем изобретать велосипед?).Шаблон репозитория является текущим стандартом.Однако не ожидайте простой формулы, потому что вариантов столько же, сколько и разработчиков. Почти.

IRepository - это просто интерфейс, который вы создаете (он не является частью MVC или ASP.NET или.СЕТЬ).Это позволяет вам «отделить» ваши репозитории от реальных реализаций.Разделение - это хорошо, потому что это означает, что ваш код ...:

  1. Ваш код гораздо более пригоден для повторного использованияЭто просто хорошо.
  2. Ваш код может использовать Inversion of Control (или Inpension Injection).Это хорошо, чтобы ваши проблемы были хорошо разделены.Это особенно хорошо, потому что это позволяет юнит-тестирование ...
  3. Ваш код может быть юнит-тестирование.Это особенно хорошо в больших проектах со сложными алгоритмами.Это хорошо везде, потому что расширяет ваше понимание технологий, с которыми вы работаете, и доменов, которые вы пытаетесь смоделировать в программном обеспечении.
  4. Ваш код строится на основе лучших практик, следуя общему шаблону.Это хорошо, потому что это значительно упрощает обслуживание.

Итак, после того, как вы продали развязку, ответ на ваш вопрос заключается в том, что IRepository - это интерфейс, который вы создаете и который наследует ваши хранилища.Это дает вам надежную иерархию классов для работы.

Я обычно использую универсальный IRepository.Т.е.:

IRepository

Там, где Tentity - это сущность.Код, который я использую:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wingspan.Web.Mvc
{
    public interface IRepository<TEntity> where TEntity : class
    {
        List<TEntity> FetchAll();
        IQueryable<TEntity> Query {get;}
        void Add(TEntity entity);
        void Delete(TEntity entity);
        void Save();
    }
}

Конкретная реализация этого интерфейса будет:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

using Wingspan.Web.Mvc;

namespace ES.eLearning.Domain
{
    public class SqlRepository<T> : IRepository<T> where T : class
    {
        DataContext db;
        public SqlRepository(DataContext db)
        {
            this.db = db;
        }

        #region IRepository<T> Members

        public IQueryable<T> Query
        {
            get { return db.GetTable<T>(); }
        }

        public List<T> FetchAll()
        {
            return Query.ToList();
        }

        public void Add(T entity)
        {
            db.GetTable<T>().InsertOnSubmit(entity);
        }

        public void Delete(T entity)
        {
            db.GetTable<T>().DeleteOnSubmit(entity);
        }

        public void Save()
        {
            db.SubmitChanges();
        }

        #endregion
    }
}

Это позволит мне написать:

SqlRepository<UserCourse> UserCoursesRepository = new SqlRepository<UserCourse>(db);

Где дБэто экземпляр DataContext, внедренный, скажем, в Service.

С UserCoursesRepository теперь я могу писать методы в своем классе Service, например:

public void DeleteUserCourse(int courseId)
        {
            var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single();
            UserCoursesRepository.Delete(uc);
            UserCoursesRepository.Save();
        }

А теперь в моих контроллерах я могу просто написать:

MyService.DeleteUserCourse(5);
MyService.Save();

Т.е. разработка вашего приложения становится в большей степени сборочной линией, которая ведет к ОЧЕНЬ простому контроллеру.Каждый кусочек сборочной линии может быть проверен независимо от всего остального, поэтому ошибки будут подавлены в зародыше.

Если это длинный, громоздкий ответ, то это потому, что реальный ответ:

Купите книгу Стивена Сандерсона Pro ASP.NET MVC 2 Framework и научитесь думать в MVC.

14 голосов
/ 25 декабря 2010

IRepository - это интерфейс, который вы указываете при реализации шаблона репозитория.Как сказал @Brian Ball, это не часть .NET, это интерфейс, который вы создаете.

Разработчики, использующие шаблон репозитория, широко рекомендуют использовать интерфейс для реализации.Например, в приложении, которое я сейчас разрабатываю, у меня есть 5 репозиториев.4 конкретных и 1 общий.Каждый из них наследуется от IRepository, что гарантирует, что у меня не будет проблем в будущем с различиями в реализациях.

Что касается примеров кода, я постараюсь:

interface IRepository<T> where T : class {
    IQueryable<T> Select();
}

Реализованокак универсальный репозиторий:

public class Repository<T> : IRepository<T> where T : class {
    public IQueryable<T> Select() {
        return this.ObjectContext.CreateObjectSet<T>();
    }
}

Реализован как специализированный репозиторий:

public class EmployeeRepository : IRepository<Employee> {
    public IQueryable<Employee> Select() {
        return this.ObjectContext.Employees;
    }
}

Оба Repository<T> и EmployeeRepository реализуют IRepository, однако они продолжают выполнять запросынемного по-другому.Универсальный репозиторий должен создать набор объектов T, прежде чем он сможет что-либо предпринять.

Имейте в виду, что Repository<T> должен быть заблокирован для интерфейса, тогда как EmployeeRepository может реализовывать более специализированныеметоды для выполнения более сложной логики.

Надеюсь, это вам немного поможет.

3 голосов
/ 25 декабря 2010

IRepository не определен тип в .Net Framework. Обычно, когда вы видите интерфейс с таким названием, программа использует шаблон репозитория (https://web.archive.org/web/20110503184234/http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx). Обычно, когда люди используют этот шаблон, они создают интерфейс, которого придерживаются все репозитории. Есть много преимуществ для этого. Некоторые из преимуществ - это удаление кода и модульное тестирование.

Для этого также характерно использование IoC (http://en.wikipedia.org/wiki/Inversion_of_control).

2 голосов
/ 22 апреля 2014

Хранилище - это абстракция, которая представляет любое базовое и произвольное хранилище данных, как если бы это была коллекция объектов в памяти.

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

Таким образом, IRepository - это интерфейсный контракт, который определяет, как код Api желает, чтобы код клиента взаимодействовал с хранилищем. Это часто включает в себя добавление, обновление, удаление и получение контрактов, как, например, этот очень распространенный пример контракта с репозиторием:

public interface IRepository<TEntity> where TEntity : class
{
    List<TEntity> GetAll();
    void Add(TEntity entity);
    void Delete(TEntity entity);
    void Save();
}

Но я предпочитаю использовать другой интерфейс по нескольким причинам.

Во-первых, вы обычно не будете использовать репозиторий сам по себе, вы, вероятно, будете использовать его с шаблоном единицы работы, поэтому в репозитории не должно быть метода Save (). У него может быть Update(T entity) метод - но почему? Объект, который вы получаете из репозитория, будет автоматически обновляться / обновляться так же, как любой другой объект, который вы получили бы из любого вида коллекции объектов, потому что вы получили ссылки на сами объекты. (Например: если ваш TEntity является Person объектом, и вы получаете человека "Чак", и вы изменяете его фамилию с "Bartowski" на "Carmichael", хранилище, по-видимому, уже обновило указанную сущность. Если это кажется ненадежным, в реализации метода Update(T entity) нет ничего плохого.)

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

Наконец, наш контракт имеет больше смысла для истинной природы хранилища - коллекция объектов в памяти, которые представляют собой произвольное хранилище данных, возможно, отключенное .

public interface IRepository<TEntity> where TEntity : class
{

    List<TEntity> GetAll();
    List<TEntity> Get(Func<TEntity, bool> where);
    void Insert(TEntity entity);
    void Insert(IEnumerable<TEntity> entities);
    void Remove(TEntity entity);
    void Remove(IEnumerable<TEntity> entities);

    void SyncDisconnected(TEntity entity, bool forDeletion = false);
    void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}

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

public interface IRepository<TEntity> where TEntity : DomainObject
{
    TEntity GetById(object Id);

    List<TEntity> GetAll();
    List<TEntity> Get(Func<TEntity, bool> where);
    void Insert(TEntity entity);
    void Insert(IEnumerable<TEntity> entities);
    void Remove(TEntity entity);
    void Remove(IEnumerable<TEntity> entities);

    void SyncDisconnected(TEntity entity, bool forDeletion = false);
    void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}

Если вам не нравится необязательный параметр forDeletion, вы можете добавить метод, который также позволяет синхронизировать удаленные объекты:

    void SyncDisconnectedForDeletion(TEntity entity);

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

Этот интерфейс можно реализовать для ЛЮБОГО репозитория ЛЮБОГО базового хранилища данных, подключенного или отключенного, включая другие абстракции к базовым хранилищам данных, например Entity Framework.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...