【问题标题】:Where does Unit Of Work belong w/ EF4, IoC (Unity), and Repository?带有 EF4、IoC (Unity) 和存储库的工作单元属于哪里?
【发布时间】:2011-06-28 21:59:19
【问题描述】:

我看到几个与此相关的问题,但我仍然找不到我正在寻找的答案,所以我发布了我的问题。如果另一个问题有答案(而我只是没有看到),请指出它。

在将 EF4 和 Unity 与 Repository 模式一起使用时,我试图找出我的 UnitOfWork 所属的位置 - 尤其是创建的位置。

基本上,我有一个服务用于实现我的业务逻辑。此服务构造函数接收存储库,因此服务被注入到我的存储库中。然后该服务使用注入的存储库对数据存储执行操作——但我需要将它们包装在一个工作单元中。

然而,我的工作单元需要注入 EF4 上下文(或者,在我的情况下,以及上下文的接口——IObjectContext)。而且我不确定应该在哪里创建和注入 UoW。

以下是我能想到的可能选项,但似乎都不理想:

  • 在服务构造函数中包含 UoW,从而使服务与工作单元一起注入,而工作单元又与我的 EF4 上下文一起注入。但这似乎是错误的,因为我不希望在存储库的每个实例上都创建我的 UoW。

  • 使用 container.Resolve 进行按需创建以获取 UoW 的实例,注入我的 EF4 上下文。不得不不断地访问 IoC 容器,而不是已经可以访问 UoW,这似乎太过分了。

  • 将上下文直接注入服务,允许我创建 UoW(上下文)。这似乎很糟糕,因为我现在已经向服务公开了上下文,这应该与存储库隔离。

所以我的问题是,这些方法中的一种是否可以接受,还是我没有想到的另一种方法?

提前致谢。

【问题讨论】:

    标签: entity-framework repository unity-container ioc-container unit-of-work


    【解决方案1】:

    可能有几种方法可以使用它,所以我将描述一种我认为有用的方法。

    恕我直言,定义 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)。

    其他方法是使用服务外观。 Facade 将是您的业务层的公共接口,它将隐藏服务组合:

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

    在这种情况下,UoW 不会传递给控制器​​,而是传递给服务外观,并且服务外观将被注入控制器。如果您的业务逻辑将通过 Web 服务(或其他远程技术)公开,您肯定会使用这种方法。

    您必须处理的最后一个问题是将 UoW 传递给服务。服务和 UoW 都被注入到控制器(presenter、service facade 或其他)中,但同时必须将 UoW(或 ObjectContext)注入到服务中,以便内部使用的存储库可以使用它。为此,您需要正确的 IoC 生命周期管理器,以便它为同一“请求”中的所有注入返回相同的实例。对于 Web 应用程序,您需要 PerHttpRequest 生命周期管理器(您必须自己实现,因为 Unity 不提供它)。

    【讨论】:

    • 感谢您的帖子。这是有道理的,我将在周末尝试这种方法。我可能会跟进一些问题,但从概念上讲,这似乎是合理的。
    • 我还没有深入了解我的项目(试图找出其他做法),但到目前为止这对我有用,所以我将其标记为答案。再次感谢您的帮助。
    【解决方案2】:

    一种管理方法是使用http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/ 中描述的方法,该文章为 Wcf 服务实现了 ContextManager。对于 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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-07
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-13
      • 1970-01-01
      相关资源
      最近更新 更多