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

Что такое IRepository и для чего он используется?

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

4b9b3361

Ответ 1

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

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

IRepository - это просто интерфейс, который вы создаете (он не является частью MVC или ASP.NET или .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);

Где db - это экземпляр DataContext, внедренный, скажем, в Сервис.

С 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.

Ответ 2

An 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

IRepository не является определенным типом в структуре .Net. Обычно, когда вы видите интерфейс с именем, он использует шаблон репозитория (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).

Ответ 4

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

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

Таким образом, 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, и вы получаете человека "Чак", и вы меняете его фамилию от "Бартовски" до "Кармайкл", репозиторий предположительно уже обновил указанный объект. кажется неуловимым в вашем сознании, нет ничего плохого в реализации метода 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.