Куда относится Единица работы с EF4, IoC (Unity) и репозиторием?

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

Я пытаюсь выяснить, где принадлежит мой UnitOfWork и, в частности, он создается при использовании EF4 и Unity с шаблоном Repository.

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

Моя единица работы, однако, должна быть внедрена с контекстом EF4 (или, в моем случае, и с интерфейсом контекста - IObjectContext). И я не уверен, где UoW должен быть создан и введен в контексте.

Вот возможные варианты, которые я могу придумать, ни один из которых не кажется идеальным:

  • Включите UoW в конструктор службы, таким образом, добавив службу с единицей работы, которая, в свою очередь, будет введена с моим контекстом EF4. Но это кажется неправильным, потому что я не хочу, чтобы мой UoW создавался в каждом экземпляре хранилища.

  • Выполните создание по требованию, используя container.Resolve, чтобы получить экземпляр UoW, внедряя мой контекст EF4. Это кажется чрезмерным из-за того, что вам постоянно приходится попадать в контейнер IoC, а не иметь доступ к UoW.

  • Внедрить контекст непосредственно в сервис, что позволяет мне создавать UoW(контекст). Это кажется плохим, так как я теперь предоставил контекст сервису, и он должен быть изолирован от репозитория.

Итак, мой вопрос, является ли один из этих методов приемлемым, или есть другой метод, о котором я не думаю?

Заранее спасибо.

2 ответа

Решение

Есть, вероятно, несколько способов, как использовать это, поэтому я опишу тот, который я нашел полезным.

Imho место для определения UoW находится в логике приложения - логике, которая вызывает ваш бизнес-уровень (бизнес-сервисы). Причина этого в том, что UoW должен представлять логическую бизнес-операцию - логика приложения (или фасад службы в случае удаленных вызовов) определяет, что такое логическая транзакция. Так, например, в MVC вы можете использовать архитектуру, в которой каждое действие контроллера представляет собой одно UoW:

public class MyController : Controller
{
  public MyController(IFirstService firstService, ISecondService secondService,
    IUnitOfWork unitOfWork)
  { ... }

  [HttpPost]
  public ActionResult SomeAction(Model data)
  {
    _firstService.SomeProcessing(data);
    _secondService.SomeProcessing(data);
    _unitOfWork.SaveChanges();
    return RedirectToAction(...);
  }
}

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

Другой подход с сервисным фасадом. Фасад будет публичным интерфейсом вашего бизнес-уровня и будет скрывать состав сервиса:

_firstService.SomeProcessing(data);
_secondService.SomeProcessing(data);
_unitOfWork.SaveChanges();

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

Последняя проблема, с которой вам приходится сталкиваться, это передача UoW сервисам. Службы, а также UoW внедряются в контроллер (презентатор, фасад службы или что-то еще), но в то же время UoW (или ObjectContext) должны вводиться в службы, чтобы внутренне используемые репозитории могли работать с ним. Для этого вам нужен правильный менеджер времени жизни IoC, чтобы он возвращал один и тот же экземпляр для всех инъекций в рамках одного и того же "запроса". В случае веб-приложения вам нужен менеджер времени жизни PerHttpRequest (который вы должны реализовать сами, потому что Unity его не предоставляет).

Одним из способов управления этим является использование метода, описанного в http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/ Эта статья реализует ContextManager для сервисов Wcf. Для приложения ASP.NET мы могли бы использовать что-то вроде этого.

public class AspNetDBContextManager<TContext> : IDBContextManager
    where TContext : IDBContext, new()
{
    #region IDBContextManager Members

    public IDBContext GetDBContext()
    {
        return this.GetOrCreateDbContext();
    }

    private IDBContext GetOrCreateDbContext()
    {
        if (HttpContext.Current == null)
        {
            throw new InvalidOperationException("Can be used only within ASP.NET applications");
        }

        string dbContextKey = string.Format("__AspNetDBCM__{0}__", HttpContext.Current.GetHashCode());

        object dbContext = HttpContext.Current.Items[dbContextKey];

        if (dbContext == null)
        {
            dbContext = new TContext();

            if (dbContext != null)
            {
                HttpContext.Current.Items[dbContextKey] = dbContext;
            }
        }

        return dbContext as IDBContext;
    }

    #endregion
}

public interface IDBContext
{
    object Context { get; }
}


public interface IDBContextManager
{
    IDBContext GetDBContext();
}
Другие вопросы по тегам