浅谈C#中的延时加载(1)——善用委托
时间:2011-01-13 来源:serafin
这段时间学习了一下NHibernate,顺便了解了一下延时加载的原理和实现等,今天写了篇文章,已经发在我自己的个人博客上,顺便也发到博客园来给大家分享,技术含量比较少,勿要见怪!
原文地址:http://www.youguanbumen.net/Article.aspx?id=69
【原文】
很久以前就听过“延时加载”这个东西,不过没有理解是什么意思,现在算是了解一二了,写点文章作为读书笔记,把自己的想法记录一下,希望对初学者帮助,不管是初学者或者高手如果发现文章那里写得不好或者有更好的思路和做法记得告诉我哦^^。文章打算写成两三篇,这个是第一篇。
在三层结构中我们通常会使用多一个叫做“模型层”的东西,这一层中最主要做的事情是把数据库中的表 (或者其他数据源,例如xml或者自己定义的一种数据格式)转成对应的类,例如有一个文章表,这时候在这一层就会有一个文章类;文章类的属性对应着文章表的列,例如文章标题属性对应文章标题列。 实体类和数据表一一对应是最简单的情况,这时候实体类和实体类是各自独立存在的,没有出现相互引用的关系。 但是,几乎每一个数据库中的表都是存在关联关系的(关系型数据库),例如除了文章表之外,还会有一个文章分类表,假如说每一篇文章都必须属于一个分类,那么在数据库中表现出来的就是文章表中有一个外键字段指向文章分类表的主键 ,在C#代码中表示出来的是文章类中有一个属性(文章分类ID),通过这个属性我们就可以知道文章所属的分类、并且可以准确地通过代码查询数据库,获取一个文章分类实体类的对象,读取到文章所属分类的相关信息。
以上的过程看起来一点问题都没有,整理一下思路,就是读取数据库,获取一个文章类对象,通过文字类对象中的文章分类ID的值,以这个值为查询条件去数据库中读取数据,获取一个文章分类对象,当然对数据库的操作我们通常 是封装在“数据访问层”中。然而从面向对象的角度考虑,我们会希望从文章类包含有文章分类的信息,用代码表示“文章分类”和“文章”两个实体类如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
namespaceModel
{
// 文章分类实体类
publicclassArticleCategory
{
publicintCategoryID { get; set; }
publicstringCategoryName { get; set; }
}
// 文章实体类
publicclassArticle
{
publicintArticleID { get; set; }
publicstringTitle { get; set; }
publicstringCotnent{ get; set; }
publicDateTime CreateTime { get; set; }
publicintCategoryID { get; set; }
// 文章所属分类
publicModel.ArticleCategory Category{ get; set; }
}
}
|
从上面的代码可以看到,在文章实体类中出现了一个Model.ArticleCategory类型的属性Category,我们想要的就是通过这个属性直接读取文章所属分类的详细信息。问题出现了,在数据库访问层中我们从数据库中读取数据去实例化一个文章实体类对象之后, 要选择在什么时候去给Category赋值。
- 选择一:立刻给通过分类ID(CategoryID属性)去获取所属文章分类的对象,然后塞给“文章所属分类”属性(Category) ,然后再返回文章对象。这种方法在有一点不好,就是万一得到文章对象之后根本不用去使用到Category属性……显然这种做法不佳。
- 选择二:在需要的时候再去读取文章分类,然后给文章类对象的Category属性赋值,但……这和没有这个属性其实也没有什么区别。
- 选择三:在Category属性的get访问器中实现读取数据库获取文章分类的代码,这样如果没有使用到Category属性的 时候是不会调用到这些代码的,也就不会去访问数据库拿东西了,为了避免每次访问Category属性都去读取数据库, 我们给他增加一个所有字段,得到的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
protectedModel.ArticleCategory _category;
publicModel.ArticleCategory Category
{
get
{
if(_category == null)
{
// 创建文章分类数据访问层对象
Dal.ArticleCategory articleCategoryDal = newDal.ArticleCategory();
// 获取文章分类
_category = articleCategoryDal.GetArticleCategoryByCategoryID(CategoryID);
}
return_category;
}
// set访问器就不需要了
}
|
乍看起来似乎没问题,但要考虑一点,在三层结构中数据的传输靠的就是“模型层”,“模型层”处于三层之下, 换句话说,“模型层”不会去引用三层中的任何一层,而上面代码中的GetArticleCategoryByCategoryID很显然是在三层之中,也许是在“业务逻辑层”或者“数据访问层”,所以...循环引用了,这种做法也不佳。如何实现对在文章类中对Category属性的数据进行延时加载呢?整理思路,根据需求一步步分析: