浅谈C#中的延“.NET研究”迟加载(2)——善用virtual

  之前的文章"浅谈C#中的延迟加载(1)——善用委托"中介绍了三层结构中在Model层对实体类的属性实现延迟加载的方法,该方法利用C#中的委托来实现,最后虽然延迟加载的目的得以实现,但是给客户端(例如UI层)暴露了不必要的属性(一个委托对象,我使用了泛型的Fun类来实现)。这篇文章介绍一种方法来隐藏这个属性,同时又可以达到延迟加载的目的,更重要的是这一切都是在之前的基础上来完成的,不需要改变原来使用到实体类的地方的代码。

  按照惯例,我们考虑一下想要我们的代码达到什么效果:首先在Model.Acticle(文章实体类)中的Category属性和原来一样,只在需要的时候通过调用委托来获取文章所属分类(Model.ArticleCategory类)。同时这个委托是不被客户端(例如UI层)代码看到的。。。设计模式中有一句话,大致的意思是通常在两个事物之间加上一个中间层,可以把事情变得简单,于是我们这样考虑,能不能加多一个中间层来实现呢?

  把Category属性定义为虚拟的(virtual),去掉委托,继承Model.Acticle类实现一个子类,把委托放到到这个子上海网站建设类里面来,由个子类里面去实现Category属性的get选择器,客户端访问的是一个用该子类做实例化的Model.Acticle类对象,这样一来客户端代码访问的依旧是Model.Acticle类,但是看不到用于实现延迟加载的委托却又能在Category属性中获取到需要的数据。呵呵,由于我是写文章的人,所以觉得这个思路很好理解,但是看文字的您可能感觉有点晕,下面用代码来说明应该就清楚了。

  首先我们修改Mode上海徐汇企业网站设计与制作l.Acticle类,给他瘦身,瘦身结果如下:


c#代码
// 文章实体类
  public class Article
 {
 public int ArticleID { get; set; }
 public string Title { get; set; }
 public string Cotnent{ get; set; }
 public DateTime CreateTime { get; set; }
 public int CategoryID { get; set; }
 // 文章所属分类
  public virtual Model.ArticleCategory Category
 {
get;
}
 }

  对比上一篇文章,可以发现作为延迟加载用的委托不见了,另外就是Category的get选择器中不再有任何逻辑代码,并且该属性被声明为virtual了。

  下一步我们创建多一层出来。新建一个名为DModel的类库(注意:该层需要引用Model层,然后被Dal层引用)。接下来在DModel层也创建一个Article类,没错!用他来继承Model.Acticle类。Dmodel.Acticle长成下面这个样子:


c#代码
 namespace DModel{
 // 文章 
public class Article : Model.Article
 {
 // 所属分类
 protected Model.ArticleCategory _category;
 public override Model.ArticleCategory Category
 {
 get
 {
if (_category == null)
{
if (CategoryLazyLoader != null)
{
 _category = CategoryLazyLoader(CategoryID);
 }
else
 {
_category = null;
 }
 }
 return _category;
 }
 }
 // 文章分类延时加载器(委托)
 public Func<int, Model.ArticleCategory> CategoryLazyLoader { get; set; } }}

  是的,看到了么,委托跑这儿来了,并且他实现了Model.Acticle的Category属性的get选择器,里面的逻辑是不是也很熟悉呢。

  接着还有一个地方要做点小修改,就是Dal层中获取一个文章实体类的方法,也就是前一篇文章中写到的public Model.Article GetArticleById(int articleId)方法了,修改后如下:


c#代码
 // 根据文章ID获取文章实体类对象public Model.Article GetArticleById(int articleId){
 //上海闵行企业网站设计与制作 从数据库中取出数据,得到一个DateRow或者DateRader之类的东东然后初始化一个文章实体类对象
 DModel.Article article = ... // ...是代码 - -!
 // 创建文章分类数据访问对象
 Dal.ArticleCategory articleCategory = new Dal.ArticleCategory();
 // 指定延时加载委托
 article.CategoryLazyLoader = articleCategory.GetArticleCategoryById;
 // 返回文章对象
 return article;}

  请注意上面代码中这一句,DModel.Article article = ... // ...是代码 - -!,我们得到一个DModel.Article对象,最后以Model.Article的形式返回(C#中的装箱,是吧~)。再次告诉你的同事吧,你不用去管那个委托了,因为你现在拿到的Mode.Article对象中看不到那玩意,反正对你也没用。果然,看不见了,延迟加载的目的也达到鸟! 总结一下,本文讲的比前一篇文章讲的东西还少,主要记住三点: 1、把Category属性声明为虚拟的; 2、把Category原来的逻辑代码推迟到子类里面实现; 3、用子类(DModel.Acticle)实例话父类(Model.Acticle)。

  好了,用这个方法把项目里面类似Category这样的实体类属性修改为virtial吧,创建子类去重写它实现延迟加载,子类只有Dal层知道它的存在,Bll层和UI层对此一无所知,他们还是和原来一样用着,啥都不用修改,但是代码的效率明显有了提高,现在属性没有被使用就不会读取数据库了,数据库的压力也减少了^_^!!!

  这一切看起来似乎没问题,直到一个BUG被发现......在一个实体类中,有一个属性,按照之前的逻辑是我们给它赋值的时候,会对其他属性做相应的修改,现在给重写掉了,之前的逻辑,没拉.(待续)

时间: 2024-08-22 14:51:12

浅谈C#中的延“.NET研究”迟加载(2)——善用virtual的相关文章

浅谈javascript中this在事件中的应用

 这篇文章主要介绍了浅谈javascript中this在事件中的应用实例,非常有助于我们对this关键字的理解,这里推荐给大家.     this关键字在javascript中是非常强大的,但是如果你不清楚它是怎么工作的就很难使用它.   代码如下: function dosomething(){ this.style.color="#fff"; }   上面这段代码中的this指向什么呢,运行dosomething()会输出什么呢? 在javascript中,this总是指向当前执行

浅谈VC中的字节对齐

原文地址:浅谈VC中的字节对齐 前几天时,在公司和同事说到了字节对齐,一直对这个概念比较模糊,只是在<程序员面试宝典>中看到过简单的描述和一些面试题.后来在论坛中有看到有朋友在询问字节对齐的相关问题,自己也答不上来,觉得应该研究一下,所以就有了这一篇博文,是对学习的一个总结,也是对成长轨迹的一个记录.       字节对齐,又叫内存对齐,个人理解就是一种C++中的类型在内存中空间分配策略.每一种类型存储的起始地址,都要求是一个对齐模数(alignment modulus)的整数倍.问题来了,为

[技术学习]浅谈MFC中超类化技术的实现 .

自 Panr 的 Blog // 关键词:// 面对对象编程.超类化.子类化.Superclassing// MFC.CWnd::SubclassWindow// 通用控件.CMNCTRL//// 主题:// 通过CWnd::SubclassWindow 函数的分析,浅谈MFC中超类化技术的实现////// 背景// 我在2002-12月见了mahongxi (烤鸡翅膀)(色摸)在CSDN上的一个帖// 介绍了MFC中窗体的超类化的概念,以下是对我个人回贴的总结//// 日志// 修改:Panr

浅谈c++中的stl中的map用法详解_C 语言

Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一

浅谈Python中copy()方法的使用

  这篇文章主要介绍了浅谈Python中copy()方法的使用,Python中的拷贝分为潜拷贝和深拷贝,本文只是简单介绍用法,需要的朋友可以参考下 copy()方法返回字典的浅拷贝. 语法 以下是copy()方法的语法: ? 1 dict.copy() 参数 NA 返回值 此方法返回字典的浅拷贝. 例子 下面的例子显示了copy()方法的使用. ? 1 2 3 4 5 6 #!/usr/bin/python   dict1 = {'Name': 'Zara', 'Age': 7};   dict

浅谈ASP中Request对象获取客户端数据的顺序

request|对象|客户端|数据 浅谈ASP中Request对象获取客户端数据的顺序 /**描述:在使用ASP Request对象时需要注意的小问题作者:慈勤强Email : cqq1978@yeah.net**/ 在ASP中Request对象是获取客户端提交数据的一个很重要的对象,大家对他也是非常熟悉了.虽然如此,还是经常有人问我下面的几种写法有什么不同,到底应该怎么写?strMessage = Request("msg")strMessage = Request.Form(&qu

浅谈jquery中delegate()与live()

  这篇文章主要介绍了浅谈jquery中delegate()与live()的相关资料,需要的朋友可以参考下 delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序 例如给id是showspan的div中的span标签添加事件 ? 1 2 3 4 5 6 7 8 9 10 <div id="showspan"><span>showspan**showspan</span></div> <span>

浅谈javascript中call()、apply()、bind()的用法

  浅谈javascript中call().apply().bind()的用法         一直对Javascript中的apply/call/bind的用法很模糊,恰好看到了这篇文章.对三者之间的区别与联系算是有了比较清晰的认识.这里记录下来,分享给大家. call(thisObj,arg1,arg2...).apply(thisObj,[obj1,obj2...])这二个方法是每个函数都包含的非继承的方法 call(thisobj[, args])和apply(thisobj[, arg

浅谈java中异步多线程超时导致的服务异常_java

在项目中为了提高大并发量时的性能稳定性,经常会使用到线程池来做多线程异步操作,多线程有2种,一种是实现runnable接口,这种没有返回值,一种是实现Callable接口,这种有返回值. 当其中一个线程超时的时候,理论上应该不 影响其他线程的执行结果,但是在项目中出现的问题表明一个线程阻塞,其他线程返回的接口都为空.其实是个很简单的问题,但是由于第一次碰到,还是想了一些时间的.很简单,就是因为阻塞的那个线 程没有释放,并发量一大,线程池数量就满了,所以其他线程都处于等待状态. 附上一段自己写的调