基于Entity Framework的仓储设计

时间:2022-03-24 08:54:50

基于Entity Framework的仓储设计

针对开发人员注重于业务的开发而非数据操作的需求,本文在分析Entity Framework技术架构的基础上,从仓储的规约设计、仓储设计和仓储应用三个方面全面剖析了基于Entity Framework的仓储设计方法,高效实现了领域模型和数据库之间的映射层即仓储,真正实现了将数据操作从业务开发中隔离,从而极大的提高系统的开发效率。

【关键词】Entity Framework 仓储 规约设计

1 前言

数据访问作为管理信息系统中一个非常重要的模块。目前,涌现出了很多优秀的设计模式和开源库,Enterprise Library便是其中的典型代表。随着对象关系映射(ORM)工具的出现,人们希望数据访问能从业务处理中独立出来,使得系统开发人员能关注于业务处理而非数据的访问处理。近年来,借助于Entity Framework设计的仓储模式便应运而生,而且其应用越来越广泛。

2 Entity Framework技术架构

Entity Framework是由Microsoft开发并提供的ORM,它基于驱动管理,可支持任意数据库,提供Database First、 Model First、Code First三种设计开发模式。Entity Framework以Entity Data Model(EDM)为主,将数据逻辑层切分为三块,分别为Conceptual Schema,Mapping Schema与Storage Schema三层,其数据逻辑层上面还有Entity Client,Object Context以及LINQ可以使用。

Entity Framework的架构图如图1所示。Entity Framework利用了抽象化的数据结构,将每个数据库对象都转换成应用程序对象(entity),把数据字段相应转换为属性(property),关系则转换为结合属性(association),让数据库的E/R(实体/关系)模型完全转化成对象模型。这样,允许软件开发人员能用最熟悉的编程语言来调用访问。

3 仓储设计

仓储(Repository)是领域模型和数据库之间的一个映射层。其工作流程是客户端对象首先以声明的方式构建查询规则,然后提交到仓储,仓储再根据规则返回规则约定的数据。客户端对象可以对仓储进行创建(Create)、更新(Update)、读取(Read)和删除(Delete)操作(简称CURD操作),仓储会自行将这些操作映射为数据库操作,并将操作结果提交到数据库中。因此,仓储提供了一种面向对象的数据操作。

规约模式(Specification)能辅助Entity Framework有效实现仓储,并在仓储实现过程中定义数据操作的规则。仓储重要目标就是将数据访问隔离开来,使得软件开发人员能更加注重于业务的开发而非数据的操作,Entity Framework借助于LINQ语法完成对数据的操作。

仓储的设计主要分为规约设计和仓储设计两个部分,仓储服务数据的存储和获取,规约主要用于约束数据存取的规则。

3.1 规约设计

仓储规约定义了客户端从仓储获取数据或者操作数据的规则。Entity Framework借助LINQ将客户端的业务规则组合成为功能函数(Function)。为了提供更加复杂业务的规则,Entity Framework规约提供了复合运算常用的运算符,包括And、Not、Or、And Not等。仓储规约模块关系如图2所示。

由图2可见,仓储的规约设计包含ISpecification接口,ICompositeSpecification接口和各自的实现类。ISpecification接口定义了AndSpec,AndNotSpec,NotSpec,OrSpec等复合操作规约,同时提供了GetExpress和IsSatisfiedBy运算,其中,GetExpress方法返回由LINQ组成的表达式树,IsStatisfieldBy则可验证某实体是否满足约定的规则。

ICompositeSpecification除了集成ISpecification外还定义了符合运算中所必须的Left和Right两个运算符,相应的代码如下所示:

Public Interface ICompositeSpecification(Of TEntity As Class) : Inherits ISpecification(Of TEntity)

ReadOnly Property Left As ISpecification(Of TEntity)

ReadOnly Property Right As ISpecification(Of TEntity)

End Interface

Specification类则实现了ISpecification接口,CompoisteSpecification类则实现了ICompositeSpecification接口。在Specification类实现接口的过程中用到了CompositeSpecification中的And,Or,AndNot来完成自身复合运算的需求。复合运算规约由接口和对应的规约实现组成,符合接口和其实现类的关系如图3所示。

在Specification类中借助复合规约接口和单一的规约接口组成对外服务的规约,Specification类和CompositeSpecification类间的关系如图4所示。在规约实现过程中,利用Expression完成相应的复合运算是关键。以下通过代码分析基于Expression的CompositeSepcification类和And操作规约的实现方法。

3.1.1 Composite Specification

为了让调用者以Func的形式进行规约运算,Specification类借助表达式树(Expression)完成相应的运算。对于符合运算,表达式必定包含Left和Right两个部分,所以,在CompositeSpecification类的定义中包含了Left和Right两个部分,相应代码如下所示:

Friend MustInherit Class CompositeSpecification(Of TEntity As Class)

Inherits Specification(Of TEntity)

Implements ICompositeSpecification(Of TEntity), ISpecification(Of TEntity)

Public Left As ISpecification(Of TEntity)

public Right As ISpecification(Of TEntity)

End Sub

End Class

除了Left和Right两个部分之外,CompositionSpecification类实际上还包括基类Sepcification中其余的运算符,而从CompositionSepcification类衍生出的子类主要实现AndNot,And,Or等符合运算。以下以AndNotSpecification为例说明子类对复合运算的实现方式。

3.1.2 AndNotSpecification

AndNotSpecification对应数据库操作中的And Not组合运算符,运算的主体是借助于Left和Right完成And Not的运算过程,相应代码如下所示:

'''

''' AndNot运算

'''

'''

Friend Class AndNotSpecification(Of TEntity As Class)

Inherits CompositeSpecification(Of TEntity)

Sub New(left As ISpecification(Of TEntity), right As ISpecification(Of TEntity))

MyBase.New(left, right)

End Sub

Public Overrides Function GetExpression() As Expressions.Expression(Of Func(Of TEntity, Boolean))

Dim parameterExpression = Expression.Parameter(GetType(TEntity))

Dim parameterReplacer As New ParameterReplacer(parameterExpression)

Dim left = parameterReplacer.Replace(MyBase.Left.GetExpression.Body)

Dim right = parameterReplacer.Replace(Expression.Not(MyBase.Right.GetExpression.Body))

Dim body = Expression.And(left, right)

Return Expression.Lambda(Of Func(Of TEntity, Boolean))(body, New ParameterExpression() {parameterExpression})

End Function

End Class

在实现的过程中,主要是对于ParameterReplacer和Expression.Lambda函数的调用。关于ParameterReplacer和Expression.Lambda函数的帮助文档,可参考MSDN中的详细说明。

规约的设计旨在帮助软件开发人员以面向对象的方式完成数据的获取和设置。规约可视为仓储设计、实现的一个支撑环境。

3.2 仓储设计

规约接口和服务定义之后实际上已经完成了仓储的底部支撑。仓储的设计主要提供面向对象的数据操作方式。在实现仓储的过程中可以自定义映射层来完成从底层数据到业务模型的转换。目前,有SubSonic、NHibernate、Entity Framework等多种映射方式,其中,Entity Framework是映射框架的典型代表。

仓储的设计包括相关接口和对应功能类的设计。接口中定义仓储所提供的功能,根据CURD功能,主要包含增、删、改、查以及其基本扩展。仓储的设计结构如图5所示。

3.2.1 IRepository

IRepository接口即为仓储接口,其中定义了仓储的常规操作,接口中重点定义了数据的相关查询,而规约是作为参数查询条件来使用的。而对于接口的实现主要集中在Repository和AutoRepository中,IRepository接口的成员如下所示。

GetQueryable

Count

GetEntity

QueryEntityArray

QueryEntityArrayByPager

AddEntity

UpdateEntity

DeleteEntity

3.2.2 Repository

Repository是仓储实现的核心类,Repository类中提供了对接口定义类的所有的实现,实现的过程中主要针对所有的查询进行,而对于增、删、改的操作则定义为虚方法交由后续的AutoRepository实现。

在实现Repository的过程中,主要使用Entity Framework完成相关操作,为了更好地在后续的代码中集成DbContext,在自定义类EFDbContext中重写了GetDbSet,通过重写对获取DbSet的过程进行了验证和异常处理。整个仓储的结构如图6所示。

3.2.3 AutoRepository

因为增、删、改的操作时效性较强,而DbContext自身的缓存机制导致数据不会立即提交,所以Auto Repository的实现集中实现仓储中的增、删、该操作,并结合规约来组织增、删、改的条件对发生更新的数据立即提交。

3.2.4 RepositoryCreator

RepositoryCreator作为Repository工厂为调用者提供不同环境下需要的Repository,根据用户传递的条件和Context分别创建Repository或AutoRepotiroy实例,并通过创建RepositoryHelper提供了对分页查询的封装。

仓储借助于规约完成了对数据的增、删、改、查从内存到数据库,或从数据库到内存的映射,使得我们可以利用面向对象的思想构建我们模型并对模型进行使用而不必关心底层的数据操作。

4 总结

针对开发人员注重于业务的开发而非数据操作的需求,本文重点阐述了仓储的组成以及围绕仓储而展开的规约设计。借助于仓储开发人员可以根据业务需求直接设计面向对象的业务模型,并针对业务模型进行逻辑设计并完成核心功能,而对于数据的增、删、改、查操作则交由仓储统一完成。仓储从根本上改变了上层开发人员的开发模式,由以前的面向T-SQL开发转变为面向业务开发,从而高效实现了将数据操作从业务开发中隔离,极大提高了系统的开发效率。

参考文献

[1]张佳,许建国.基于Entity Framework的防作弊称重系统的设计与实现[J].电子技术与软件工程,2015(11).

[2]林平荣,鲁昭,黄煜祺.基于Entity Framework的图书馆光盘管理系统[J]. 现代计算机(专业版),2015(24).

[3]陈荣,张磊,冉杰.基于Entity Framework技术的安全生产标准化管理系统设计与应用[J].安全,2015(09).

[4] 高宏,王婷婷.基于MVC和Entity Framework的团餐系统[J].计算机与现代化,2014(12).

[5] 但斌斌,罗欢,陈奎生,熊凌,容芷君.Entity Framework在KR脱硫自动控制系统中的应用[J].制造业自动化,2013(05).

作者简介

邱海洋(1996-),男,江苏省徐州市人。大学专科学历。现为常州信息职业技术学院软件学院助教。研究方向为软件技术。

作者单位

1.常州信息职业技术学院软件学院 江苏省常州市 213164

2.苏州科大讯飞教育科技有限公司 江苏省苏州市 215002

上一篇:水利工程中的软基处理工艺探讨 下一篇:浅析调度自动化系统在供电企业的应用