- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在网上搜索了一个使用 Entity Framework 的 Repository/Unit of Work 模式的良好实现。我遇到的一切要么在抽象的某个点紧密耦合,要么假设 DbContext
工作单元和存储库使用的是共享的,并且应该在整个 HTTP
期间存在。请求(通过依赖注入(inject)的每个请求的实例)。
例如,假设您正在使用服务层的存储库,服务构造函数可能如下所示:
public DirectoryService(IUnitOfWork unitOfWork, ICountryRepository countryRepo, IProvinceRepository provinceRepo)
{
/* set member variables... */
}
工作单元构造函数可能如下所示:
public UnitOfWork(IDbContext context)
{
_context = context;
}
存储库构造函数可能如下所示:
CountryRepository(IDbContext context)
{
_context = context;
}
此解决方案盲目假设依赖注入(inject)正在设置工作单元和存储库以使用每个请求的实例共享相同的 IDbContext。这真的是一个安全的假设吗?
如果您使用每个请求实例的依赖注入(inject),相同的 IDbContext 将被注入(inject)多个工作单元。工作单元不再是原子的,是吗?我可能在一个服务中有待处理的更改,然后在另一个服务中提交这些更改,因为上下文在多个工作单元之间共享。
对我来说,设置 IDbContextFactory
似乎更有意义并获得每个工作单元的新数据库上下文。
public interface IDbContextFactory
{
IDbContext OpenContext();
}
public class UnitOfWork
{
private IDbContextFactory _factory;
private IDbContext _context;
UnitOfWork(IDbContextFactory factory)
{
_factory = factory;
}
internal IDbContext Context
{
get { return _context ?? (_context = _factory.OpenContext()); }
}
}
然后问题就变成了,我如何让我的工作单元实现对注入(inject)的存储库可用?我不想假设每个请求都有实例,因为那样我就回到了我开始的同一条船上。
我唯一能想到的就是跟随 Entity Framework 的领导并制作存储库 (IDbSet<T>)
部分工作单元(DbContext)
.
那么我可能会有这样的工作单元:
public class DirectoryUnitOfWork : IDirectoryUnitOfWork
{
private IDbContextFactory _factory;
private IDbContext _context;
public DirectoryUnitOfWork(IDbContextFactory factory)
{
_factory = factory;
}
protected IDbContext Context
{
get { return _context ?? (_context = _factory.OpenContext()); }
}
public ICountryRepository CountryRepository
{
get { return _countryRepo ?? (_countryRepo = new CountryRepository(Context)); }
}
public IProvinceRepository ProvinceRepository
{
get { return _provinceRepo ?? (_provinceRepo = new ProvinceRepository(Context)); }
}
void Commit()
{
Context.SaveChanges();
}
}
然后我的目录服务开始看起来像这样
public class DirectoryService : IDirectoryService
{
private IDirectoryUnitOfWork _unitOfWork;
public DirectoryService(IDirectoryUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public GetCountry(int id)
{
return _unitOfWork.CountryRepository.GetById(id);
}
public GetProvince(int id)
{
return _unitOfWork.ProvinceRepository.GetById(id);
}
public void AddProvince(Province province)
{
_unitOfWork.ProvinceRepository.Create(province);
Country country = GetCountry(province.CountryId);
country.NumberOfProvinces++; // Update aggregate count
_unitOfWork.Commit();
}
/* ... and so on ... */
}
这看起来工作量很大,但使用这种方法可以使所有内容松散耦合并且可以进行单元测试。我是否缺少更简单的方法,或者这是一个很好的方法 if
我要抽象掉 Entity Framework 吗?
最佳答案
你不应该永远不要抽象一个 ORM(它本身就是一个抽象),但是你应该抽象 Persistence。我使用的唯一 UoW 是一个数据库事务,这是一个持久性细节。您不需要同时使用 UoW 和 Repository。您应该考虑如果您真的需要所有这些东西。
就个人而言,我默认使用存储库,因为持久化是我在应用程序中做的最后一件事。我不关心模式本身,我关心的是将我的 BL 或 UI 与 DAL 解耦。您的上层(除了 DAL 之外的所有层,从依赖关系的角度来看,它是最低层)应该始终了解抽象,以便您可以在 DAL 实现中随心所欲。
许多开发人员不知道的一个技巧是,设计模式(尤其是架构模式)应该首先被视为高级原则,其次才是技术诀窍。简而言之,最重要的是模式试图实现的好处(原则,大局),而不是它的实际实现(“低级”细节)。
问问自己,为什么 BL 首先应该知道 UoW。 BL 只知道处理业务对象的抽象。而且你永远不会像以前那样处理整个 BL,你总是处于特定的 BL 上下文中。您的 DirectoryService 似乎在为自己的利益做很多事情。更新统计数据看起来与添加新省份不属于同一上下文。另外,为什么需要 UoW 进行查询?
我经常看到的一个错误是,当开发人员没有做最重要的部分:设计本身时,他们急于编写任何代码(附加设计模式)。当您的设计不当时,问题就会出现,您就开始寻找解决方法。其中之一是具有 Repository 属性的 UoW,它需要像 BL 这样的高层来了解比业务问题更多的信息。现在 BL 需要知道您正在使用 UoW,这是一种较低级别的模式,它对 DAL 非常有用,但对 BL 不太好。
顺便说一句,当您处理“读取”情况时,UoW 对于查询毫无意义,UoW 仅用于“写入”。我没有提到 EF 或任何 ORM,因为它们并不重要,您的 BL 服务(目录服务)已经被不当设计所需的基础设施细节破坏了。请注意,有时您确实需要妥协才能实现解决方案,但事实并非如此。
正确的设计意味着您了解您的限界上下文(是的,无论您想执行多少 DDD,您都可以应用它的 DDD 概念)并且不要将可能使用相同数据的所有内容放在一个地方。您有特定的用例上下文,并且计算省份(演示/报告详细信息)实际上是与添加省份不同的用例。
添加省份然后发布一个事件,向处理程序发送信号以更新统计数据是一种更优雅、更易于维护的解决方案。也不需要 UoW。
你的代码看起来像这样
public class DirectoryService : IDirectoryService
{
public DirectoryService(IProvinceRepository repo, IDispatchMessage bus)
{
//assign fields
}
/* other stuff */
//maybe province is an input model which is used by the service to create a business Province?
public void AddProvince(Province province)
{
_repo.Save(province);
_bus.Publish( new ProvinceCreated(province));
}
}
public class StatsUpdater:ISubscribeTo<ProvinceCreated> /* and other stat trigger events */
{
public void Handle(ProvinceCreated evnt)
{
//update stats here
}
}
在某种程度上它简化了事情,在其他方面你可能认为它使事情复杂化。实际上,这是一种可维护的方法,因为统计更新程序可以订阅许多 事件,但逻辑只保留在一个类中。并且 DirectoryService 仅执行假定它执行的操作(名称 AddProvince 的哪一部分提示您该方法还更新统计信息?)。
总而言之,在急于将 UoW、DbContext、Repositories 作为属性等复杂化之前,您需要更好地设计 BL
关于c# - 使用 Entity Framework 时,存储库应该是工作单元的属性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23987471/
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicates: What is a framework? What does it do? Why do we need a f
我在按照 http://msdn.microsoft.com/en-us/data/jj591621.aspx 处的 Microsoft Data Developer 过程启用代码优先迁移时遇到了一些
我正在从 迁移项目 Entity Framework 4.3 在 .net 4 上运行到 Entity Framework 5 在 .net 4.5 上运行。在不做任何更改的情况下,当我尝试运行该项目
我正在使用 Entity Framework 6 并使用 EntityFramework Extended 来执行一些批量更新和批量删除。批量更新和批量删除工作正常,但我还需要知道更新/删除的实体(即
我在实体上添加了一个列,然后从模型中生成数据库或构建解决方案,然后收到一条消息,提示我刚添加的新列未映射。该数据库以前是从模型创建的,没有错误。 当我右键单击Entity并选择Table Mappin
每次我尝试运行我的代码时都会崩溃,因为我尝试启动函数以调用 SDK 的任何部分。 我在构建过程中包含了 FoundationSDK: 并且我在头文件中包含了对 SDK 的引用: 但是每次我运行这个,我
我以前能够毫无问题地提交我的申请。我的工作流程中唯一改变的部分是使用 Sourcetree。在对以下框架进行更新后,我在提交到 iOS App Store 时收到此警告。我还收到一封电子邮件,其中包含
假设我为 Asp.NET Web 应用程序安装了 .NET Framework 2.0、3.0、3.5。 我意识到 Framework 3.0 和 3.5 只是 Framework 2 的扩展,不太清
是否有 SaveChanges 事件在保存更改后但在更新更改跟踪器之前触发? 我正在使用 EF 6。 我需要在某个实体的状态发生变化时执行任务。 我已经覆盖了 SaveChanges 来设置它。我可以
我正在使用一个现有的数据库,并且我已经将其中一个表映射为一个实体(因为我需要映射一个外键)。 因此,在初始化此数据库时,我希望 EF 忽略此实体,因为它已经存在。 我该怎么做? 最佳答案 您应该使用
我有 3 个表需要与 Entity Framework 进行映射,但我不确定解决此问题的正确方法。这是我的 3 个实体: public class User { [Key] public
我首先使用 VS 2010 和 Entity Framework 代码(版本 6)。我有两个实体,每个实体都在自己的上下文中,我想在它们之间创建一对多关系。 上下文 1 具有以下实体: public
我知道 EF 在 CodePlex 上是开源的,但我没有看到当前发布的 5.0 版本的分支。我在哪里可以得到这个源代码? 最佳答案 没有。他们只开源了 post 5 版本。第一次签到可能足够接近,但再
我们目前有一个数据库很大的系统,存储过程既用于CUD又用于查询。数据集用于从 SP 查询中检索结果。 现在我们正在研究使用 Entity Framework 针对同一个数据库开发另一个项目。在查询数据
我有一个每 10 秒运行一次的 Windows 服务......每次运行时,它都会获取一些测试数据,对其进行修改并使用 EntityFramework 将其保存到数据库中。但是,在每一秒运行时,当我尝
我对在我们的场景中仅将 Entity Framework 与存储过程一起使用的合理性有疑问。 我们计划拥有一个 N 层架构,包括 UI、BusinessLayer (BLL)、DataAccessLa
当我使用 Entity Framework 时,我想在上下文中查询出一条记录并将其添加到具有相同架构的另一个上下文中,在查询出记录后,我将其从上下文中分离出来,但是相关实体都没有了,是吗?有什么办法解
我正在使用 Entity Framework 5 构建 ASP.Net MVC4 Web 应用程序。我必须使用现有的 sql server 数据库,但也想使用 Code First,所以我遵循了本教程
在 Entity Framework 4.0 中使用 T4 模板创建 POCO 会丢失什么?为什么使用 Entity Framework 4.0 时的默认行为不创建 POCO? 最佳答案 你会失去很多
我在网上使用 Repository Pattern 和 EF 看了很多例子。但他们都没有真正谈到与相关实体的合作。 就像说用户可以有多个地址。 IUserRepository User CreateU
我是一名优秀的程序员,十分优秀!