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

Взаимодействие между единицей работы и шаблонами репозитория

После прочтения большого количества статей я до сих пор не уверен в отношении ответственности шаблона Unit of Work при взаимодействии с репозиториями.

Хранилища несут ответственность за загрузку и сохранение агрегированных корневых объектов, поэтому рассмотрим следующий пример кода:

using(IUnitOfWork uow = container.CreateUnitOfWork())
{
     Repository<ARoot> roots = container.GetRepository<ARoot>();
     ARoot root = root.FindByName("ARoot");
     root.Name = "ANewName";

     roots.Save(root);
     uow.Commit();
}

Единица интерфейса работы будет определяться следующими способами:

public interface IUnitOfWork
{
     void Insert(object);
     void Update(object);        
     void Delete(object);
     void Commit();
     void Rollback();
}

Предположим, что репозиторий реализован с использованием очень простого SQL Mapper, поэтому FindByName содержит некоторый прямой SQL для возврата ARoot, будет ли реализация Save выглядеть примерно так:

public void Save(T entity)
{
      IUnitOfWork uow = GetUnitOfWork();
      // Tell the UOW we are updating this entity
      uow.Update(entity);
}

Код Commit Work Commit затем построил бы все необходимые SQL, чтобы отобразить объект обратно в БД?

Вопрос 2)

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

public void Save(T entity)
{
      IUnitOfWork uow = GetUnitOfWork();
      // Tell the UOW we are updating this entity
      uow.Update(entity);
      uow.Update(entity.AChildObject);
}

ИЛИ... Альтернативно

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

using(IUnitOfWork uow = container.CreateUnitOfWork())
{
     Repository<ARoot> roots = container.GetRepository<ARoot>();
     ARoot root = root.FindByName("ARoot");
     root.Name = "ANewName";

     //roots.Save(root);
     uow.Update(root);
     // and commit
     uow.Commit();
}

Спасибо,

Джеймс

4b9b3361

Ответ 1

В нашем проекте мы используем репозиторий, чтобы вести себя так же, как коллекция Entities, а UnitOfWork используется для отслеживания изменений этих объектов и для их записи в хранилище данных.

Если вы используете LinqToSql или какой-либо другой OR Mapper, то, скорее всего, он будет реализовывать шаблон UnitOfWork сам по себе, поэтому часто мы просто экземпляр ORMapper в нашем собственном IUnitOfWork.

Наш интерфейс репозитория обычно что-то вроде.

  IEnumerable<Order> FindByCustomerId(string customerId);
  void Add(Order order);
  void Remove(Order order);

У нас нет никакого метода сохранения в Репозитории. Если нам не нужен модуль UnitOfWork, методы Add/Remove действуют непосредственно на хранилище данных.

Если нам нужен UnitOfWork, тогда публичный интерфейс - это что-то вроде...

void Commit();
void Rollback();

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

Когда мы используем LinqToSql, DataContext позаботится об отслеживании изменений, в Rollback мы просто создаем новый контекст. Стойкость обрабатывается через корень и его детей. Один экземпляр UnitOfWork разделяется между всеми репозиториями.

Если мы не используем LinqToSql, мы реализуем наш собственный UnitOfWork, возможно, он вызывает веб-сервис или что-то в этом роде, в этом случае мы сами отслеживаем изменения в самих классах сущностей, используя класс EntityBase.

У нас есть репозиторий для каждого корня, но иногда дети одного корня используются как сами корни, поэтому нам часто нужно что-то вроде OrderLineRepository, потому что у нас есть пример использования в нашей системе: пользователь хочет выполнить поиск заказа линии.

Ответ 2

Как правило, мне нравится видеть, что UoW отслеживает изменения, которые сохраняются, напрямую вызывая IRepository.Save().

Я также предпочитаю, чтобы код UoW обрабатывался как аспект и вне взаимодействия с доменом. Это означает, что он либо обрабатывается некоторыми глобальными обработчиками команд, либо кодом веб-служб как часть завершения запроса. Другими словами, начало запроса открывает единицу работы, заканчивая ее закрытие. Таким образом, домен может не знать UoW и его реализацию.

Выполнение единицы работы - это то, что затем приводит к изменениям, вызванным вызовом методов .Save() и других методов изменения. Вполне возможно, что UoW - это то, что каким-то образом отслеживает эти изменения.

Ответ 3

  • UnitOfWork - это ваша транзакция Обработчик
  • Репозиторий выполняет acutal работать для загрузки/сохранения объектов в хранилище данных

Я использую определения, похожие на:

IUnitOfWork { Commit(); }
IRepository { GetAll(); GetById(); Add(T item); Remove(T item); }

У меня не было бы UnitOfWork, создающего SQL - эта логика была бы в вашем репозитории. В каком хранилище данных вы используете?