上一回说到普通属性的延迟加载,这次说下我对于联结关系的延迟加载的看法。
所谓联结关系,就是一对一、一对多、多对多这样的对象之间的关系。一说到这类延迟加载,就不能不想到NHibernate。通过编辑配置文件,即可实现联结关系的延迟加载。我不想进行太多的介绍,毕竟,比我研究得深入的大有人在。所以就只如主题了。
曾经,我也曾经考虑过用配置文件和CustomAttribute来定义联结关系,并且付诸实现。基本的xml定义方式如下:
<Relation Property="" TargetType="" RelationType="" ConditionColumn="" SlaveColumn="" JoinTable="" JoinType=”” JoinTableConditionColumn="" JoinTableSlaveColumn=""></Relation>
其中:
1、 Property是实体的属性,如果用CustomAttribute就可以省掉。
2、 TargetType是延迟加载的数据类型。
3、 RelationType是关系类型,一对多还是多对多。
4、 ConditionColumn也就是作为条件的列,主要是为了取得延迟加载的条件。从ConditionColumn对应的属性中获取值进行查询。
5、 SlaveColumn是从表的列。
6、 JoinTable是中间表。
7、 JoinType是联结的类型,比如:left join、left outer join、full join之类。
8、 JoinTableConditionColumn是使用中间表的时候,中间表中作为条件的列。
9、 JoinTableSlaveColumn是谁哦用中间表的时候,中间表和从表列对应的列。
用SQL语句来描述就是:
1、 不使用中间表:from TargetType.Table where SlaveColumn = ConditionColumn.Value
2、 使用中间表:from TargetType.Table JoinType join JoinTable on JoinTableSlaveColumn = SlaveColumn where JoinTableConditionColumn = ConditionColumn.Value
考虑以下几种情况:
1、 不使用中间表的一对一延迟加载
2、 不使用中间表的一对多延迟加载
3、 使用中间表的一对一延迟加载
4、 使用中间表的一对多延迟加载
其中1和2比较容易搞定,直接根据“ConditionColumn”所对应的属性,用“SlaveColumn”作为条件列,获取TargetType所对应的表名进行查询即可。如果是一对一,则填充实体,赋值。如果是一对多,则填充实体集合,赋值。对于3和4使用了中间表的情况,就更麻烦些,毕竟要生成“Join”语句嘛。先用“JoinTableConditionColumn”和“ConditionColumn”所对应的属性值生成“join”之后的“where”条件。然后用“SlaveColumn”和“JoinTableSlaveColumn”生成“join” 语句的“on” 部分。当然也少不了根据“JoinTable”和“JoinType”的“join”语句的“join”部分。查询的结果,就如1和2那样同等对待了。
从上面的描述可以看出,我没有特别定义多对多关系。因为,所谓的多对多只是数据库意义上的,在使用ORM后,如果从对象的加载的角度来看,多对多其实就是一对多,只是多对多一般都会有一个中间表而已。
现在,开始说关键问题了。上面说的是“曾经”,这表示现在我放弃了这种做法。下面就开始说明一下“现在”。
通过配置或者“CustomAttribute”的确可以实现延迟加载自动化(至少是半自动化吧)。但是这些自动化真能带来所期望的便利吗?不使用中间表的延迟加载还好说,使用中间表你要在配置中填多少东西?稍微写错,就会出现问题,虽然在调试时我会输出异常,但是这并不能像编译时检查那样方便,而且提供的信息也不如用SQL语句时那样直观。这也是使用配置动态生成SQL的弊端,不能在第一时间检查错误,也不能在出错时给出非常明确的提示。还有一点让我也觉得很头疼,SQL语句可以直接放到查询分析器进行调试,那些配置该如何验证,虽然我们可以用代码生成器,但是小的修改直接手工怎么减少出错呢?而且,自动化的加载只能做到有限的自动化,双向的关联就比较不好处理。如果再用配置,不是更容易导致混乱。持久化的时候呢?
经过一番斗争之后,我决定从另一个角度来思考问题。我在《我的框架(11)——普通属性延迟加载》中间但描述了处理的思路,和普通属性延迟加载一样,联结关系延迟加载也简化为“Relation(KeyColumn)”。联结关系延迟加载和普通属性延迟加载稍微有些不同,普通属性延迟加载仅进行一次加载,但是联结关系延迟加载时只要“Key”发生了变化,就会导致重新加载。框架仅负责在Key改变后,在需要加载时将必要的信息提供给使用者,并对延迟加载属性赋值。使用者则根据框架提供的信息自己负责数据的加载。这样一来,就避免了复杂的配置,也可以让使用者用自己最擅长的方式根据框架提供的“Key”加载数据。更进一步,因为数据的加载方式是由使用者自己定义的,当异常出现时,使用者可以很容易根据异常所包含的信息来排除错误。
posted @ 2009-12-28 08:40 陈鹏(偶是坏人) 阅读(1855) 评论(0)
编辑