使用实体框架的存储库 + 工作单元模式

8
我在网上搜索了很久,但始终找不到适合我的应用程序的设计。
我正在寻找Repository+UnitOfWork模式,该模式将管理连接并在完成时自动释放它们。
我需要支持Web应用程序和每个请求都有自己的UnitOfWork以及Windows应用程序和每个线程都有自己的UnitOfWork。 我需要在完成请求/线程时自动处理UnitOfWork。 我还希望支持异常回滚。
目前我使用StructureMap,所以我不介意在建议答案中继续使用它。
我需要Repository模式是为了实现对所有实体的所需功能。 我需要UnitOfWork模式来允许对多个实体进行更改。
非常感谢您的任何帮助。
谢谢。

你好,请看一下这个庞大的项目:http://microsoftnlayerapp.codeplex.com/ - Alireza Maddah
@Alireza Maddah:有很多东西,我不知道从哪里开始,也不知道在哪里寻找例子。 - Naor
请同时查看 http://silverlightcookbook.codeplex.com。 - Steven
4个回答

3

我和你使用了相同的方式,这让我到达了现在的位置。我必须支持Web应用程序和Windows应用程序。在Application_EndRequest中使用UnitOfWork.Current.Dispose()可以处理Web应用程序中的UnitOfWork。但是在Windows应用程序中,UnitOfWork从未被处理。这就是我的问题。这个示例没有明智地处理UnitOfWork的释放。 - Naor
是的,不幸的是,就像其他人所说的一样,您需要一些逻辑来自行处理它。对我来说(例如),几乎所有的请求都是通过 WCF 发送的,因此当 WCF 会话关闭时,我能够处理上下文(context)的释放。 对于其他情况,我确实需要手动调用Dispose。这只是生活的一个事实! :) - DanTheMan

1
去年我写了一篇关于编写支持LINQ的存储库的文章,这些存储库可以轻松地进行单元测试,并且与依赖注入很好地配合使用。这是文章。简而言之,该文章描述了一个工作单元,模仿了LINQ to SQL DataContext并包装了一个抽象实际O/RM工具的IDataMapper接口。工作单元包含类型为Repository<TEntity>的属性,例如Repository<Customer>Repository<Order>,而存储库类实现了IQueryable<T>,允许您在其上使用LINQ。 IDataMapper是一个简单的接口,看起来像这样:
public interface IDataMapper : IDisposable
{
    Repository<T> GetRepository<T>() where T : class;

    void Save();
}

该文章中描述的解决方案旨在使单元测试和依赖注入更加友好。实际上,您唯一需要的配置就是以下内容:

string northwindConnection = GetConStr("Northwind");

container.RegisterSingle<IUnitOfWorkFactory<NorthwindUnitOfWork>>(
    new LinqToSqlNorthwindUnitOfWorkFactory(northwindConnection));

container.RegisterSingle<IUnitOfWorkFactory<SalesUnitOfWork>>(
    new EntityFrameworkSalesUnitOfWorkFactory());

但是在你的NorthwindUnitOfWork中,你定义了所有的存储库。如果你有超过30个实体,每个实体都有一个存储库怎么办?我几乎在每次应用程序更新时都会添加表格 - 这将导致NorthwindUnitOfWork中发生很多更改,并且它将是一个巨大的文件。难道没有通用解决方案吗? - Naor
@Naor:事实上,“NorthwindUnitOfWork”仅供方便之用。如果您愿意,可以直接使用“IDataMapper”(并将其称为“IUnitOfWork”)。 “NorthwindUnitOfWork”只是定义了一堆属性(每个实体一个)并调用“IDataMapper.GetRepository<T>”方法。我最初采用了这种方法,但这使我的应用程序代码变得不太干净。确实需要更改“NorthwindUnitOfWork”以添加任何实体,但您实际上有多少次添加新实体呢? - Steven
我经常添加实体..这是一个尚未完成的大型应用程序。我会再次查看您的帖子,并理解NorthwindUnitOfWork并不重要,IDataMapper实际上是IUnitOfWork。 - Naor
@Naor:这种方法的优点是,虽然需要编写相当数量的代码来设置,但是在添加新实体时需要添加的代码非常少。是的,您需要在NorthwindUnitOfWork中添加一个属性和可选的GetById扩展方法,但您不需要为该实体添加新存储库,也不需要额外的测试类。 - Steven

1

1
NCommon似乎利用了一个静态的UnitOfWork类。这个类在DI术语中被实现为环境上下文,这是一种DI反模式。因为OP想要使用依赖注入,NCommon似乎不是一个好选择。然而,它仍然可以用于教育目的。 - Steven

0

如果您已经拥有工作单元和存储库,并且正在使用StructureMap,那么问题在哪里呢?

您可以简单地将您的类配置为:

ObjectFactory.Configure(x => x.For<IUnitOfWork>()
                              .HybridHttpOrThreadLocalScoped()
                              .Use<EFUnitOfWork>());

你可以使用依赖注入将工作单元传递给仓储。


我已经完成了,但是当线程完成时它没有处理UnitOfWork。 - Naor
没有解决方案会为您处理上下文。这始终是您的责任,因为您知道何时不再需要它。 - Ladislav Mrnka
那么我应该把它丢到哪里呢? - Naor
1
你必须知道!它不是无缘无故被称为工作单元 - 它代表单个业务操作/交易,不应用于其他任何事情。 - Ladislav Mrnka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接