我看到几个与此有关的问题,但我仍然无法找到我正在寻找的答案,所以我发布了我的问题。如果另一个问题得到答案(我只是没有看到),请指出我。
我正在尝试弄清楚我的UnitOfWork所属的位置 - 特别是在创建时 - 使用EF4和Unity与存储库模式。
基本上,我有一个用于实现业务逻辑的服务。此服务构造函数接收存储库,因此服务将注入我的存储库。然后,该服务使用注入的存储库对数据存储执行操作 - 但我需要将它们包含在一个工作单元中。
然而,我的工作单元需要注入EF4上下文(或者,在我的情况下,和上下文的接口 - IObjectContext)。而且我不确定UoW应该在哪里创建并注入上下文。
以下是我能想到的可能选项,其中没有一个看起来很理想:
在服务构造函数中包含UoW,从而使用工作单元注入服务,然后使用我的EF4上下文注入。但这似乎是错误的,因为我不想在存储库的每个实例上创建我的UoW。
使用container.Resolve进行按需创建以获取UoW的实例,注入我的EF4上下文。这似乎过于不得不经常点击IoC容器,而不是已经有权访问UoW。
直接将上下文注入服务,允许我创建UoW(上下文)。这似乎很糟糕,因为我现在已经将上下文暴露给服务,这应该被隔离到存储库。
所以我的问题是,这些方法中的一种是否可以接受,还是有其他方法我没想到?
提前致谢。
答案 0 :(得分:12)
可能有几种方法可以使用它,所以我将描述一个我发现有用的方法。
Imho定义UoW的地方是应用程序逻辑 - 调用业务层(业务服务)的逻辑。原因是UoW应该代表逻辑业务trasaction - 应用程序逻辑(或远程调用时的服务外观)定义什么是逻辑事务。因此,例如在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被注入到控制器(演示者,服务外观或其他)中,但同时必须将UoW(或ObjectContext)注入到服务中,以便内部使用的存储库可以使用它。为此,您需要正确的IoC生命周期管理器,以便它在同一“请求”中为所有注入返回相同的实例。在Web应用程序的情况下,您需要PerHttpRequest生命周期管理器(您必须自己实现,因为Unity不提供它)。
答案 1 :(得分:1)
管理这种方法的一种方法是使用http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/中描述的方法。该文章实现了ContextManager for 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();
}