DNN Object Hydrator -- CBO解析

http://www.dnnsun.com/Blog/tabid/67/EntryID/11/language/zh-CN/Default.aspx

这篇文章

如果你开发过DNN模块或阅读过模块的代码,你应该会知道模块控制类所经常使用的一个对象CBO,它在DNN里是大名鼎鼎的,几乎所有的模块开发都会涉及并使用这一对象,在DNN数据访问策略白皮书中,你可看到如下的架构图:
从上图我们可一目了然CBO在DNN的核心作用: 在业务逻辑层和表示层处理业务对象数据。
那究竟什么是CBO呢?
CBO的全称是Custom Business Object,翻译过来就是自定义(或定制)业务对象. 它是最初DNN为了最小化移植从数据层传输来到自定义业务逻辑对象信息的代码工作量,创建了一个通用的utility类。就像 二十四画生博客提到那样,它是实现从数据库中读取数据并实例化自定义业务对象(Custom Business Object)的类。从另外一个角度来说,自定义业务对象(也可简称CBO)就是保存数据的一种方式,用这种方式能让我们更方便的在业务逻辑层和表示层采用面向对象的方法来处理数据。一般来说这个类里定义的每个属性在Datareader里都有相应的字段对应。这些映射的信息的名称和数据类型都必须是唯一的。
在此,我还是引用二十四画生博客的一些数据比较一下模块开发过程中使用CBO的一些优点.一般对实例化自定义业务对象的操作:
1、从数据库读取数据,以DataSet或DataTable取得数据。
2、利用自定义业务对象的构造函数实例化每一个对象。
3、然后再将实例化后的对象传递到业务逻辑层。
这种方式是很麻烦的,不仅要写大量的代码来实现这种功能,而且难以维护,如果当一个自定义业务对象要增加一个属性的时候需要改动多处代码。
而DNN里CBO类的原理是利用.net中的反射机制,动态的从DataReader中读取数据,并给相应的对象属性赋值,从而起到实例化对象的效果。当然为了起到通用作用所填充的对象都是object类型的,所以需要用CType进行转换。举一个例子,如果你在数据库中有一个Table,暂且就取名为Customers,现在你可以通过一个SQL语句或存储过程取出包含一个包含Customers相关字段的DataReader,如果你定义的业务对象有一个FirstName属性,并且数据库也有一个字段为FirstName,那你就可以借助CBO把DataReader的字段为FirstName分配给业务对象的FirstName属性,从而实现了填充的自动化。由此你可看到如果业务对象具有很多的属性时,使用CBO的确是节省了很多的代码量,而且可扩展性很好,以后业务需要添加字段,那修改的地方仅仅是业务对象的属性定义,所做的修改无非就是增加一个新的属性。比较详细的例子你可以看看二十四画生博客所举的例子。
下边列举你在开发过程最频繁使用CBO的两个静态方法:
FillObject: 通过IDataReader读取数据并实例化单一的对象
FillCollection:通过IDataReader读取数据并实例化对象集合到ArrayList或List 中
在代码中对应经常看到就是类似如下:
public List GetHelloWorlds(int moduleId)
 {
    return CBO.FillCollection (DataProvider.Instance().GetHelloWorlds(moduleId));
 }
 public HelloWorldInfo GetHelloWorld(int moduleId, int itemId)
 {
    return (HelloWorldInfo)CBO.FillObject(DataProvider.Instance().GetHelloWorld(moduleId, itemId), typeof(HelloWorldInfo));
 }
以上就是一些关于使用CBO的优势,下边开始说说本文的重点,那就是使用CBO会有什么的弊端和何时使用CBO是最佳的呢?
自从4.x版本开始, DNN的性能问题一直是核心团队努力的重点,如何最优化DNN是不可避免的问题,如何在性能和用户体验掌握最佳平衡点?而CBO就是其中一个例子.根据DNN核心团队在性能测试中,CBO.CreateObject()是DNN应用程序中最影响速度的10个方法之一 ,几乎每次服务器请求都会创建,就像刚才提到的CBO类主要提供一系列的静态方法去读取DataReader并将其转化为一个新的业务对象,也就是一个填充的过程,但在编译的过程中CBO是不知道它所填充的对象是什么类型的,而众所周知,.net中的发射机制一直都是很昂贵的资源,而CBO方法里所使用的创建Activator.CreateInstance(objType)要比正常生成一个对象慢得多,同时PropertyInfo.SetValue也要比在对象里边直接通过setter来设置属性值开销要昂贵些。还有一点CBO与生俱来的缺点就是它只能填充简单数据类型对象,而不适用于一些复杂,深层数据对象. 故出于开销造成的性能问题和复杂对象的考虑,一些DNN核心控制类在频繁读取数据填充业务对象时并不采用CBO模式,比如TabController, ModuleController and MembershipProvider,而是创建自定义的填充方法,有FillTabInfo, FillModuleInfo 等等,
除了以上两点,CBO还有一些致命的缺陷,比如数据库Table的字段必须和业务对象定义的属性保持一致的名称和字段值Null的处理,就拿Null来说,如果你在模块开发时,所定义的业务对象在对应数据的值为空时,如果使用 CBO读取的话,那你只能得到DNN默认Nulll类所处理的默认值(比如布尔型为false,整型为0,字符类型为空字符串),而你可能需要字符类型为null时返回”unknown”字符串,而这时你唯一能做的就是修改核心代码,再重新编译,显然这是一个得不偿失的策略.
CBO 的优势:
1) 节省代码量,简易便捷
2) 动态加载
3) 可扩展性,升级比较容易
CBO 的弊端:
1) 开销造成的性能问题
2) 只能填充简单数据类型对象
3) 数据库Table的字段必须和业务对象定义的属性保持一致的名称,有一定的限制性。
4) Null处理缺乏灵活性
到此我们可看出,CBO带来的便捷及其节省代码量的同时不可避免地牺牲了性能,而目前性能是DNN的一个最大的瓶颈,当然具体使用是否CBO主要还是考虑项目的框架及其模块的详细设计,最后总结一下,这是个人观点,仅供参考:如果你对性能要求不是很高,业务对象简单或具有很多属性(且业务对象不确定),那就不妨使用CBO,否则自定义创建填充方法吧,所带来的性能提升就是一个很诱惑的理由。最后给出一个自定义填充方法的例子,你在Survey模块里可找到:
Public Shared Function GetSurvey(ByVal SurveyID As Integer, ByVal ModuleId As Integer) As SurveyInfo
            Dim SurveyInfo As SurveyInfo = New SurveyInfo
            Using dr As IDataReader = DataProvider.Instance().GetSurvey(SurveyID, ModuleId)
                While dr.Read
                    SurveyInfo.SurveyId = Convert.ToInt32(dr("SurveyId"))
                    SurveyInfo.ModuleId = Convert.ToInt32(dr("ModuleID"))
                    SurveyInfo.Question = Convert.ToString(dr("Question"))
                    SurveyInfo.OptionType = Convert.ToString(dr("OptionType"))
                    SurveyInfo.ViewOrder = Convert.ToInt32(ConvertNullInteger(dr("ViewOrder")))
                    SurveyInfo.Votes = Convert.ToInt32(ConvertNullInteger(dr("Votes")))
                    SurveyInfo.CreatedByUser = Convert.ToInt32(dr("CreatedByUser"))
                    SurveyInfo.CreatedDate = Convert.ToDateTime(dr("CreatedDate"))
                End While
            End Using
            Return SurveyInfo
End Function
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值