EntityFramework之领域驱动设计实践(九):储的实现:深入篇

早在年前的时候就已经在CSAI博客发表了上一篇文章:《仓储的实现:基础篇》。苦于日夜奔波于工作与生活之间,一直没有能够抽空继续探讨仓储的实现细节,也让很多关注EntityFramework和领域驱动设计的朋友们备感失望。

闲话不多说,现在继续考虑,如何让仓储的操作在相同的事物处理上下文中进行。DDD引入仓储模式,其目的之一就是能够通过仓储隐藏对象持久化的技术细节,使得领域模型变得更为“纯净”。由此可见,仓储的实现是需要基础结构层的组件支持的,表现为对数据库的操作。在传统的关系型数据库操作中,事务处理是一个很重要的概念,虽然从目前某些大型项目看,事务处理会降低效率,但它保证了数据的完整性。关系型数据库仍然是目前数据持久化机制的主流,事务处理的实现还是很有必要的。

为了迎合仓储模式,就需要对经典的ObjectContext使用方式作一些调整。比如,原本我们可以非常简单地使用using (EntitiesContainer ec = new EntitiesContainer())语句来界定LINQ to Entities的操作范围,并使用ObjectContext的SaveChanges成员方法提交事务,而在引入了仓储的实现中,就不能继续采用这种经典的使用方式。这让EntityFramework看上去变得很奇怪,也很牵强,我相信很多网友会批评我的做法,因为我把问题复杂化了。

其实,这应该是关注点不同罢了。关注EntityFramework的开发人员,自然觉得经典的调用方式简单明了,而从DDD的角度看呢?只能把关注点放在仓储上,而把EntityFramework当成是仓储的一种技术选型(当然从DDD角度讲,我们完全可以不选择 EntityFramework,而去选择其它技术)。所以本文暂且抛开EntityFramework,继续在上文的基础上,讨论仓储的实现。

前面提到,仓储的实现需要考虑事务处理,而且根据DDD的经验,针对每一个聚合根,都需要有个仓储对其进行持久化以及对象重新组装等操作。为此,我的想法是,将仓储操作“界定”在某一个事务处理上下文(Context)中,仓储的实例是由Context获得的,这有点像 EntityFramework中ObjectContext与EntityObject的关系那样。由于仓储是来自于transaction context,所以它知道目前处于哪个事务上下文中。我定义的这个transaction context如下:

Transaction Context

public interface IRepositoryTransactionContext : IDisposable
{
   IRepository<TEntity> GetRepository<TEntity>()
     where TEntity : EntityObject, IAggregateRoot;
   void BeginTransaction();
   void Commit();
   void Rollback();
}

上面第三行代码定义了一个接口方法,这个方法的主要作用就是返回一个针对指定聚合根实体的仓储实例。剩下那三行代码就很明显了,那是标准的 transaction操作:启动事务、提交事务以及回滚事务。

时间: 2024-10-28 21:32:43

EntityFramework之领域驱动设计实践(九):储的实现:深入篇的相关文章

EntityFramework 之领域驱动设计实践

写在前面 其实这系列文章已经被很多网友转载过了,我自己也在前面的博客中给出了原文的链接.但毕竟博客园的人气更旺,加上不少网友强烈要求我把文章转贴到博客园,因此最终下定决心,将这系列文章重新整理并转贴在博客园上. 根据网友的讨论结果,以及自己在实践中的不断积累,在整理的过程中,我会将原文中的描述作相应调整.不仅如此,也有不少关心领域驱动设计的网友在原文的评论栏目中提了问题或作了批注,我也针对网友的问题给予了细致的答复,为了能够让更多的朋友了解到问题的本质,本次整理稿会将评论部分也一一列出,供大家参

EntityFramework之领域驱动设计实践(三):一个简易的销售系统

案例:一个简易的销售系统 从现在开始,我们将以一个简易的销售系统为例,探讨EntityFramework在领域驱动设计上的应用.为了方便讨论,我们的销售系统非常简单,不会涉及客户存在多个收货地址的情况,也不会包含任何库存管理的内容.假设我们的系统只需要维护产品类型.产品以及客户信息,并能够帮客户下订单.跟踪订单状态,以及接受客户退货.从简单的分析我们大致可以了解到,这个系统将会有如下实体:客户.单据.产品及其类型.单据分为销售订单和退货单两种,每个单据可以有多个单据行(比如销售订单行和退货单行)

EntityFramework之领域驱动设计实践(七):模型对象的生命周期

上文中已经提到了管理领域模型对象生命周期的两大角色,即工厂与仓储,并对工厂的EntityFramework实践作了详细的描述.本节主要介绍仓储的概念,由于仓储的内容比较多,我将在接下来的两节中具体讲解仓储的架构设计与实践经验. 仓储(Repository),顾名思义,就是一个仓库,这个仓库保存着领域模型的实体对象.在业务处理的过程中,我们有可能需要把正在参与处理过程的对象保存到仓储中,也有可能会从仓储中读取需要的实体对象,抑或将对象直接从仓储中删除.上文也用一张简要的状态图描述了仓储在管理领域模

EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject

虽然从技术角度讲,DataTable与EntityObject并没有什么可比性,然而,它暗示了一场革命正在悄然进行着,即使是微软,也摆脱不了这场革命的飓风. 软件设计思想需要革命,需要摆脱原有的思路,而走向面向领域的道路.你或许会觉得听起来很玄乎,然而目前软件开发的现状使你不得不接受这样的现实,仍然有大帮的从业人员成天扯着数据库不放,仍然有大帮的人在问:"我要实现xxxx功能,我的数据库应该如何设计?"这些人犯了根本性的错误,就是把软件的目的搞错了,软件研究的是什么?是研究如何使用计算

EntityFramework之领域驱动设计实践(六):模型对象的生命周期

首先应该认识到,是对象就有生命周期.这一点无论在面向对象语言还是在领域驱动设计中都适用.在领域驱动设计中,模型对象生命周期可以简要地用下图表示: 通过上图可以看到,对象通过工厂从无到有创建,创建后处于活动状态,此时可以参与领域层的业务处理:对象通过仓储实现持久化(也就是我们常说的"保存")和重建(也就是我们常说的"读取").内存中的对象通过析构而消亡,处于持久化状态的对象则通过仓储进行撤销(也就是我们常说的"删除").整个状态转换过程非常清晰.

EntityFramework之领域驱动设计实践(五):聚合

聚合(Aggregate)是领域驱动设计中非常重要的一个概念.简单地说,聚合是这样一组领域对象(包括实体和值对象),这组领域对象联合起来表述一个完整的领域概念.比如,根据Eric Evans<领域驱动设计>一书中的例子,一辆车包含四个轮子,轮子离开"车"就毫无意义,此时这个联合体就是聚合,而"车"就是聚合根(Aggregate Root). 从实践中得知,并非领域模型中的每个实体都能够完整地表述一个明确的领域概念,就比如客户与送货地址的关系.假设在某个应

EntityFramework之领域驱动设计实践(二):分层架构

在引入实例以前,我们有必要回顾,并进一步了解分层架构."层"是一种体系结构模式[POSA1],也是被广大软件从业人员用得最为广泛而且最为灵活的模式之一.记得在CSDN上,时常有朋友问到:"分层是什么?为什么要分层?三层架构是不是就是表现层.业务逻辑层和数据访问层?" 到这里,你可能会觉得这些朋友的问题很简单,分层嘛,不就是将具有不同职责的组件分离开来,组成一套层内部高聚合,层与层之间低耦合的软件系统吗?不错!这是分层的目标.但是,我们应该如何分层呢? 领域驱动设计的

EntityFramework之领域驱动设计实践(八):仓储的实现:基本篇

我们先从技术角度考虑仓储的问题.实体框架(EntityFramework)中,操作数据库是非常简单的:在ObjectContext中使用 LINQ to Entities即可完成操作.开发人员也不需要为事务管理而操心,一切都由EF包办.与原本的ADO.NET以及LINQ to SQL相比,EF更为简单,LINQ to Entities的引入使得软件开发变得更为"领域化". 下面的代码测试了持久化一个 Customer实体,并从持久化机制中查询这个Customer实体的正确性.从代码中可

EntityFramework之领域驱动设计实践(四):存储过程

EntityFramework(EF)中有一项功能,就是能够根据数据库中的存储过程生成实体的行为(或称方法,以下统称方法).我在本系列的第一篇博文中就已经提到,这种做法并不可取!因为存储过程是技术架构中的内容,而我们所关注的却是领域模型. Andrey Yemelyanov在其"Using ADO.NET EF in DDD: A Pattern Approach"一文中,有下面这段话: In this context, the architect also identified th