EF4、IoC (Unity) 和存储库的工作单元属于哪里?

发布于 2024-10-17 23:25:38 字数 742 浏览 3 评论 0原文

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

当将 EF4 和 Unity 与存储库模式结合使用时,我试图找出我的 UnitOfWork 所属的位置(具体而言,创建的位置)。

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

然而,我的工作单元需要注入 EF4 上下文(或者,在我的例子中,需要注入上下文的接口 - IObjectContext)。我不确定应该在哪里创建 UoW 并注入上下文。

以下是我能想到的可能选项,但没有一个是理想的:

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

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

  • 将上下文直接注入到服务中,允许我创建一个 UoW(上下文)。这看起来很糟糕,因为我现在已经将上下文公开给服务,并且应该将其与存储库隔离。

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

提前致谢。

I see several questions relating somewhat to this, but I still can't find the answer I'm looking for, so I'm posting my question. If another question holds the answer (and I'm just not seeing it), please point me to it.

I'm trying to figure out where my UnitOfWork belongs -- and specifically, gets created -- when using EF4 and Unity with the Repository pattern.

Basically, I have a service that is used to implement my business logic. This service constructor takes in the repository, so the service gets injected with my repository. The service then uses the injected repository to carry out actions against the data store -- but I need to wrap these in a unit of work.

My unit of work, however, needs to be injected with the EF4 context (or, in my case, and interface of the context -- IObjectContext). And I'm not sure where the UoW should be created and injected w/ the context.

Here are the possible options I can think of, none of which seem ideal:

  • Include the UoW in the service constructor, thus having the service injected w/ the unit of work, which in turn is injected w/ my EF4 context. But this seems wrong because I don't want my UoW created on every instance of the repository.

  • Do an on-demand creation using container.Resolve to get an instance of the UoW, injecting my EF4 context. This seems excessive having to constantly hit the IoC container, rather than already having access to the UoW.

  • Inject the context directly into the service, allowing me to create a UoW(context). This seems bad since I've now exposed the context to the service, and this should be isolated to the repository.

So my question is, is one of these methods acceptable, or is there another method I'm not thinking of?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月依秋水 2024-10-24 23:25:38

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

恕我直言,定义 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 将不会传递给控制器​​,而是传递给服务 Facade,并且服务 Facade 将被注入到控制器。如果您的业务逻辑将通过 Web 服务(或其他远程技术)公开,您肯定会使用这种方法。

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

There are probably several ways how to use this so I will describe one which I found useful.

Imho the place to define UoW is in Application logic - the logic which calls your business layer (business services). The reason for this is that UoW should represent logical business trasaction - application logic (or service facade in case of remote calls) defines what is logical transaction. So for example in MVC you can go with architecture where each controller action represents single 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(...);
  }
}

In this example my controller is depenent on two business services and action calls them both - UoW then save changes performed by both services. That is the reason why I think the UoW should be available in controller because if your application layer don't have access to UoW you can't compose (reuse) your logic from several service calls (because each probably calls its own SaveChanges).

Other approach is with service facade. Facade will be public interface of your business layer and it will hide service composition:

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

In such case UoW will not be passed to controller but to service facade and service facade will be injected to controller. You will definitely use this approach if your business logic will be exposed over web service (or other remote technology).

The last problem which you have to deal with is passing UoW to services. Services as well as UoW are injected into controller (presenter, service facade or whatever) but in the same time UoW (or ObjectContext) must be injected into services so that internally used repositories can work with it. For this you need correct IoC lifetime manager so that it returns same instance for all injections within same "request". In case of web application you need PerHttpRequest lifetime manager (which you must implement by yourselves because Unity does not provide it).

不回头走下去 2024-10-24 23:25:38

管理此问题的一种方法是使用 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();
}

One way is to manage this is to use the method described in http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/ That article implements the ContextManager for Wcf services. For ASP.NET app we could use something like this.

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文