Куда относится Единица работы с EF4, IoC (Unity) и репозиторием? - PullRequest
7 голосов
/ 17 февраля 2011

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

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

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

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

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

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

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

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

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

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

Ответы [ 2 ]

12 голосов
/ 17 февраля 2011

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

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 его не предоставляет).

1 голос
/ 17 февраля 2011

Одним из способов управления этим является использование метода, описанного в 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();
}
...