实现自己的O/R Mapping组件[一]-概念解析
我打算在业余时间写一个自己的、能够充分利用.NET特性O/R Mapping组件(能不能用不管它),基本的思路是研究代码生成器和一些成熟的O/R Mapping组件的思想来进行,如果有什么问题,大家请随时指正。我会不断地记录自己的开发与思考的过程,也当做一种形式上的开源吧。
基本概念的研究
整体构思
目前的O/R Mapping要么是基于代码生成的,代码生成有时候较难以管理,但它却具有非常高的灵活性,用户可以自由的更改生成的代码,从而做到更适合于自己的开发,比较常见的工具有N-Tier、Monstarillo等;另一种是一个持久层的框架,如XPO、NHibernate、Gentle.Net等等,这种的开发难度更高,但是在使用上比较方便,Java上的Hibernate就做得非常成功。但目前的O/R Mapping与.NET中的一些东西还很难对应,比如数据绑定,虽然都是基于IList接口,但它们仅提供了基本的数据绑定,在对于像Devexpress Grid这类控件中,并不能够支持DataView,DataSet等转换,使用可行性打了一些折扣。目前,Gentle.NET中提供了一个ObjectView的类,里面提供了持久类到数据集的转换,可以支持这类控件的一些高级功能。当然DataSet更重要的功能是通过与XmlDocument的同步功能,这个是经常需要使用到的(反正我要用....)。
所以,考虑在设计时,结合代码生成与数据集的编译两者,也就是说,针对不同的项目实施时,可以自已来配置生成的方式,可以是源代码的,也可以是配置后并进行了一定修改后的代码来编译成为程序集。
在第一步开发时期,为了提供开发效率,需要采用Log4Net、Microsoft DataAccess Block等组件,其它的日后再考虑。
1、基于关系的考虑
在关系模式中,是基于表结构的数据存储,数据间的关系是通过实施关系来进行维护的。在我所理解的概念中,关系型数据库中的表实际上是对数据一个边界限定,减少数据间的干扰,实际上,这个划分原则虽然是基于业务关系的,但它的划分也是与OO中的高内聚内耦合拍。
关系模式中,两个表间的一般的关联是都可以用M:N来表示,但M:N中可以仔细划分,一般意义上的划分有:一对一(1:1)、一对多(N:1)、多对多(M:N)、其它等四种关系:
a、一对一
这种关系通常是为了表的空间或性能上的问题而设计的,比如,一般为了查询统计,比如商品的基本信息表,往往把常用的字段设计为一张表,一些类似于附加信息的设计为另一张表。
b、一对多
比较常见,比如罗斯文数据库中的订单与订单明细表。
c、多对多
这种关系相对复杂一些,实际上,许多多对多关系的数据包都可以重构为一对多及一对一的关系的几个表,但也有不行的,具体取决于实体间对应的复杂度。
d、其它
严格来说,除上述三种,还有许多关系是无法表现的,比如数据录入中的辅助表(如地区列表,性别列表等),它们与其它表间确实存在着比较弱的耦合,但这种关系又是不允许被建模的。举个例子:供应商档案列表,在一个单据中,如果你存储的是供应商的标识,那么如果这份档案中的供应商被删除后,为了数据库的完整性,相应的供应商相关联的表也应该被删除掉,但实际上,你要做为一个历史信息进行存储,在历史档案中,是不可能仅写一个标识的,这样子谁也不知道供应商的名称是什么。通常这种情况的应对,取决于建模者的观念,有一部分建模者认为这样的两张表之间是没有任何关系的,也有的建模者认为这样的两张表是必须建立关系的,维护完整的机制就是被用过的数据不允许被删除。无论怎么样,每个人也许都有自己的处理办法。
2、对范式的考虑
数据库的设计一般是通过规范化向范式靠拢,一般是先试图让数据库的设计达到第三范式的标准,再根据实际的需要对数据库进行优化处理,这依赖于反范式的思想及合理地对索引的使用。
范式可以消除一些数据冗余,提高物理空间的利用率,从这个角度出发,我打算构造的O/R Mapping组件并不是直接面向于数据表的直接映射,因为范式处理后的表往往比较小,数据表看起来也比较零碎,如果构造如此多的小型类进行直接使用的话,会非常的麻烦,基于开发效率(暂时不管性能不性能的)的想法,打算在数据访问层次上对数据表进行映射,然后在业务实体的层次对类进行组合成比较有意义的数据后,再提供访问接口给客户端代码调用。
比如:一张订单表,包括了订单与订单明细,这里不打算把这两张表构造为两个类来给客户端进行调用,而通过映射为两个数据访问层次的实体类后,再通过映射业务实体的方法,并能这些小实体组合出完整的订单实体,因为对象间是引用关系,这里的订单表实际上并不会占用更多的内存空间,这里需要使用“懒”读取的方式进行,并且利用缓存机制提高访问效率,同时通过弱引用来减少缓存对空间带来的负担。
3、映射方式的初步构想
OO模式中,关系也是分为如同关系数据库的分割方式,但在许多概念上可以与关系模式进行对应,考虑最简单的映射方案,一个对象可以对应为一个数据行,所有的数据库中的字段对应为类中的字段,数据表本身是一个集合,所以就把它对应为对象的集合。
一般关系型数据库中的管理界面并不很理想,在对表的逻辑对象间的没有提供一个归类机制,所有的表对象都放在了一起,看起来非常混乱,设计者往往不得不通过对表进行一定的规则命名来进行划分。考虑到这种情况,对于关系比较紧密的一堆的表进行逻辑划分,考虑采用命名空间对这些进行归类。
这样的好处是,对于关系紧密的类(即同一个命名空间下的),可以生成存储过程来进行一次性的更新。
4、业务层次的映射
业务上的映射,考虑两种方式:a、通过对视图的映射,来实现业务层次的映射,但这要求建立大量的视图,也容易混乱。b、提供配置向导,生成xml配置文件,到代码生成阶段时,就通过读取这个xml中的定义来生成代码,以后业务实体需要发生更改时,再修改这个配置文件。
这个在实现上的复杂度在于对业务层的更新,业务层实体的数据更新不应该初步先通过调用数据层的更新来实现,等组件稳定后,再考虑重构业务层,让业务层可以直接对数据库进行批量更新处理,从而提升访问效率。
5、基于复杂的查询
不知道怎么办,再研究一下再说
其它....(待续)