Шаблон репозитория плюсы и минусы каждой реализации - PullRequest
8 голосов
/ 28 июля 2011

Привет, глядя на шаблон репозитория, который обычно кажется реализованным примерно так:

public class GenericRepository<TEntity> where TEntity : class
{
    // other business

    public virtual TEntity GetByID(object id)
    {
        return db.Set().Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        db.Set().Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = db.Set().Find(id);
        Delete(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        db.Set().Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

Таким образом, для каждого типа, с которым вы хотите работать (например, для обновления), вам нужно создать экземпляр репозитория.

Итак, если бы у меня было два типа, я хотел бы сохранить Cars и Trucks, мне нужно было бы перейти:

var carRepository = new GernericRepository<Car>();
carRepository.Update(myCar);

var truckRepository = new GernericRepository<Truck>();
carRepository.Update(myTruck);

Итак, у вас есть отдельные репозитории для каждого типа. Чтобы сохранить все сразу, вам нужно unitOfWork, чтобы все они использовали один и тот же контекст и сохраняли одновременно.

Конечно, не было бы лучше иметь что-то вроде:

public class GenericRepository
{
    // other business

    public virtual TEntity GetByID<TEntity>(object id) where TEntity : class
    {
        return db.Set<TEntity>().Find(id);
    }

    public virtual void Insert<TEntity>(TEntity entity) where TEntity : class
    {
        db.Set<TEntity>().Add(entity);
    }

    public virtual void Delete<TEntity>(object id) where TEntity : class
    {
        TEntity entityToDelete = db.Set<TEntity>().Find(id);
        Delete(entityToDelete);
    }

    public virtual void Update<TEntity>(TEntity entityToUpdate) where TEntity : class
    {
        db.Set<TEntity>().Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

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

Таким образом, вы можете обновить свои автомобили и грузовики так:

var repository = new GernericRepository<Car>();
repository.Update<Car>(myCar);
rRepository.Update<Truck>(myTruck);

Конечно, это лучший метод? Я что-то пропустил? Он автоматически имеет только один контекст.

Ответы [ 2 ]

6 голосов
/ 28 июля 2011

Шаблон репозитория не отделяет доступ к данным из хранилища данных, для чего предназначен инструмент ETL, такой как NHibernate или Enity Framework. Шаблон репозитория предоставляет многократно используемые методы для извлечения данных.

Ранее я использовал так называемый «универсальный» репозиторий, как вы описали и думали, что это было здорово. Пока вы не поймете, что просто положили другой слой поверх NHibernate или Entity Framework, вы поймете, что все прошло, Пит Тонг.

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

public interface IEmployee interface
{
    IEmployee GetEmployeeById(Guid employeeId);

    IEmployee GetEmployeeByEmployeeNumber(string employeeNumber);

    IEnumerable<IEmployee> GetAllEmployeesWithSurname(string surname);

    IEnumerable<IEmployee> GetAllEmployeesWithStartDateBetween(DateTime beginDateTime, DateTime endDateTime);
}

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

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

1 голос
/ 28 июля 2011

Generics сам по себе не является реализацией шаблона репозитория. Мы все видели базовый базовый класс, используемый в примерах реализации шаблонов репозитория, но это делается для того, чтобы сделать вещи СУХОЙ (Don't-Repeat-Yourself) путем наследования от базового класса (GenericRepository в вашем случае) к более специализированным дочерним классам ,

Только при использовании базового базового класса GenericRepository предполагается, что вашим репозиториям понадобятся только самые основные методы CRUD. Для более сложной системы каждый репозиторий становится более специализированным на основе требований к данным базовых бизнес-объектов.

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

...