Register  |  
About the author
Baldwin's Status
 Contact Me
Baldwin Sun
Senior Developer for dnn solution & founder of SunBlog module...
Blog搜索
相册库
更多照片请查看相册库
最新评论
Rss Feed
feedsky
抓虾
pageflakes
newsgator
哪吒
我们的服务
  • DotNetNuke 咨询
  • Web设计及其模块开发
  • 免费建站
  • 电子商务
  • 开拓市场
我们致力于开发定制的web 2.0 ,所服务的客户主要包括小中型企业,社区俱乐部及其非盈利机构组织。我们将利用开源的DNN作为我们核心的系统机制,更多相关信息...

王者归来—再谈CBO

Posted in [解析DNN代码], [DNN模块开发], [剖析DNN架构] By baldwin

我之前有过一篇文章谈论过CBO的一系列弊端和对CBO变通自定义填充业务对象的想法,如果需要了解得更清楚的话,可以先去看看DNN Object Hydrator -- CBO解析
这次我为什么写了如此的标题:王者归来—再谈CBO呢,原因是最新版本的DNN 4.6.2增加了一个新的接口IHydratable,这个接口可以让我们开发模块重新充分的利用到CBO更为强大的功能而无需添加其他代码,具体的实现方式在下文会详细讲述,在此我先补充一下CBO的一个优势(我的上篇文章没有提到),那就是自从4.4版本以来,DNN对性能的重视达到前所未有的程度,故此考虑到CBO的相关弊端而采取了自定义填充业务对象的方式来优化核心代码,比如TabController, PortalController and ModuleController这几个控制类中都是使用自定义填充业务对象的方式.然而这种方式所带来的一个很明显的副作用是你必须自己管理DataReader 对象,也就是你必须确定DataReader 是否已关闭,链接状态是否处于断开等一系列问题的处理.而使用原先的CBO则不需关心这些操作,CBO会负责这些逻辑判断,在你读取数据时DataReader肯定时处于连接状态.
除了上边提到,引入IHydratable是如何做到让我们重归CBO的呢?先说说这个接口的定义及其在CBO的实现形式,该接口提供了一个属性KeyID和方法Fill,如果业务对象实现该接口,那你就可以直接像以前使用CBO类似填充业务对象,同时你不需要忍受.Net反射机制的开销所造成的性能困扰而最终达到你想要的最优,最快的获取数据方式,并可完全的利用到CBO管理DataReader的封装机制.
在CBO是如何利用IHydratable 的呢?CBO在方法CreateObject中会首先判断这个业务对象是否已实现了IHydratable接口,如果是则调用Fill方法填充业务对象(当然你对象必须在实现这个方法里边操作填充方式及其逻辑,详细样例可看下文),相反则调用原来的反射机制.代码如下:
CBO利用IHydratable
  Dim objObject As Object = Activator.CreateInstance(objType)
 
If TypeOf objObject Is IHydratable Then
 'Create Object and Use IHydratable's Fill
  Dim objHydratable As IHydratable = TryCast(objObject, IHydratable)
   If objHydratable IsNot Nothing Then
        objHydratable.Fill(dr)
   End If
 Else
   .... 原来调用发射机制的代码
     End If
Return objObject
既然IHydratable如此神奇,那我们来具体看看是如何做到的?DNN里的IHydratable声明如下:
IHydratable.vb
Namespace DotNetNuke.Entities.Modules
    Public Interface IHydratable
        Property KeyID() As Integer
 
        Sub Fill(ByVal dr As IDataReader)
    End Interface
End Namespace
首先看看KeyID属性和Fill方法是如何被实现的,如果你的业务对象(比如EntryInfo)实现了该接口,那应该有类似的代码如下:
Blog模块的EntryInfo.vb
Namespace DotNetNuke.Modules.Blog
    Public Class EntryInfo
        Implements DotNetNuke.Entities.Modules.IHydratable
        ... local property declarations
    Region "Constructors"
        Public Sub New()
        End Sub
    End Region
       ... Public Properties
    Region "IHydratable Implementation"
        Public Sub Fill(ByVal dr As System.Data.IDataReader) Implements Entities.Modules.IHydratable.Fill
            EntryID = Convert.ToInt32(Null.SetNull(dr.Item("EntryID"), EntryID))
            BlogID = Convert.ToInt32(Null.SetNull(dr.Item("BlogID"), BlogID))
 
            Title = Convert.ToString(Null.SetNull(dr.Item("Title"), Title))
            Description = Convert.ToString(Null.SetNull(dr.Item("Description"), Description))
            Entry = Convert.ToString(Null.SetNull(dr.Item("Entry"), Entry))
            AddedDate = Convert.ToDateTime(Null.SetNull(dr.Item("AddedDate"), AddedDate))
            UserID = Convert.ToInt32(Null.SetNull(dr.Item("UserID"), UserID))
            Published = Convert.ToBoolean(Null.SetNull(dr.Item("Published"), Published))
            ViewCount = Convert.ToInt32(Null.SetNull(dr.Item("ViewCount"), ViewCount))
            CommentCount = Convert.ToInt32(Null.SetNull(dr.Item("CommentCount"), CommentCount))
            AllowComments = Convert.ToBoolean(Null.SetNull(dr.Item("AllowComments"), AllowComments))
            DisplayCopyright = Convert.ToBoolean(Null.SetNull(dr.Item("DisplayCopyright"), DisplayCopyright))
            Copyright = Convert.ToString(Null.SetNull(dr.Item("Copyright"), PermaLink))
            PermaLink = Convert.ToString(Null.SetNull(dr.Item("PermaLink"), PermaLink))
            LastModifiedDate = Convert.ToDateTime(Null.SetNull(dr.Item("LastModifiedDate"), LastModifiedDate))
        End Sub
 
        Public Property KeyID() As Integer Implements Entities.Modules.IHydratable.KeyID
            Get
                Return EntryID
            End Get
            Set(ByVal value As Integer)
                EntryID = value
            End Set
        End Property
    End Region
 
    End Class
End Namespace
就像你所看到,你所需要实现的KeyID属性必须是业务对象在数据库中对应的主键字段,因为这是我们唯一能识别的,CBO会根据你所分配的KeyID来填充每一个业务对象,深入CBO代码,你会发现这是因为CBO在填充实现IHydratable接口的业务对象所使用的是Dictionary,而Dictionary是键值对的集合,在查找对象是直接根据键值的,而CBO的FillDictionary(Of T As IHydratable)就是类似原先返回ArrayLists 或泛型Lists一样,而不同就是这次返回的是Dictionary.
FillDictionary
''' ---------------------------------------------------------------
''' <summary>
'''  根据提供的DataReader自动负责填充特定类型的自定义业务对象
'''  到字典对象(IDictionary)
''' </summary>
''' <typeparam name="T">
''' 业务对象类型 注意: T 必须实现接口IHydratable
''' </typeparam>
''' <param name="dr">用来填充业务对象的IDataReader</param>
''' <returns>包含自定义业务对象的IDictionary</returns>
''' <remarks>
'''  Dictionary对象的键值对应接口的属性KeyID.
''' </remarks>
'''----------------------------------------------------------------
Public Shared Function FillDictionary(Of T As IHydratable)(ByVal dr As IDataReader) As IDictionary(Of Integer, T)
            Dim objFillDictionary As New Dictionary(Of Integer, T)
            Dim objFillObject As T
            ' 遍历datareader
            While dr.Read
                ' 填充业务对象
                objFillObject = CreateObject(Of T)(dr)
                     ' 添加到dictionary
                If objFillObject IsNot Nothing Then
                    objFillDictionary.Add(objFillObject.KeyID, objFillObject)
                End If
            End While
            ' 关闭datareader的连接
            If Not dr Is Nothing Then
                dr.Close()
            End If
            Return objFillDictionary
End Function
最后给出对应EntryInfo的控制类是如何利用IHydratable接口来直接调用CBO的(注释部分为未利用IHydratable之前的代码):
Blog模块的EntryController.vb
Public Shared Function GetEntry(ByVal EntryID As Integer) As EntryInfo
 
   'Return CType(CBO.FillObject(DataProvider.Instance().GetEntry(EntryID), GetType(EntryInfo)), EntryInfo)
    Return CBO.FillObject(Of EntryInfo)(DataProvider.Instance().GetEntry(EntryID))
End Function
Public Shared Function ListAllEntriesByBlog(ByVal BlogID As Integer) As List(Of EntryInfo)
    'Return CBO.FillCollection(DataProvider.Instance().ListAllEntriesByBlog(BlogID), GetType(EntryInfo))
 
    Dim EntryInfolist As List(Of EntryInfo) = New List(Of EntryInfo)
       Using dr As IDataReader = DataProvider.Instance().ListAllEntriesByBlog(BlogID)
           While dr.Read
               EntryInfolist.Add(CBO.FillObject(Of EntryInfo)(dr, False))
           End While
       End Using
    Return EntryInfolist
End Function
Popular tags: CBO, IHydratable
Previous Entry: 加速DNN的新举措
Next Entry: DNN特性之IMC

Comments

Was it good for you, too?Join the discussion » ,but you need to login first before you make comments.
# 1
Posted @ 2007/11/13 22:21 By Ryan
不错,似乎可以真正的利用到了CBO的所有功能了,学习中,谢谢搂主。