The DotNetNuke has long exposed the Common Business Objects (DotNetNuke.Common.Utilities.CBO) class to make it easier for developers to persist and retrieve objects to and from the database. Prior to generics being introduced in ASP.Net 2.0, the following two methods for retrieving either a single object or an ArrayList of multiple objects were most often used to fill or hydrate an object from a passed in DataReader:
Public Shared Function FillObject(ByVal dr As IDataReader, ByVal objType As Type) As Object
Public Shared Function FillCollection(ByVal dr As IDataReader, ByVal objType As Type) As ArrayList
Their generic versions which should be used with ASP.Net 2.0 and above are:
Public Shared Function FillObject(Of TObject)(ByVal dr As IDataReader) As TObject
Public Shared Function FillCollection(Of TItem)(ByVal dr As IDataReader) As List(Of TItem)
Although those methods make the developer's work easier and less prone to error by properly managing and closing the passed in DataReader when finished, they do their "magic" by making use of .Net reflection to discover the properties of the object class being filled and to map property name to corresponding database column name. Reflection is a costly operation performance wise and is best avoided in production code especially if the database is hit each time an object or collections of objects are retrieved.
In DotNetNuke 4.06.00, the IHydratable interface (DotNetNuke.Entities.Modules.IHydratable) was introduced. It defines only two member signatures which must be implemented in your custom object's entity class:
Namespace DotNetNuke.Entities.Modules
Public Interface IHydratable
Property KeyID() As Integer
Sub Fill(ByVal dr As IDataReader)
End Interface
End Namespace
The KeyID property which is used by the CBO class when filling a dictionary is most easily implemented as a wrapper around your entity class' already existing key or identity property. It is not necessary to add a new column named "KeyID" to the object's table in the database. For example, if your class had defined the column "ItemID" in the database and it uniquely identifies each row in the table corresponding to your entity class, the KeyID property may be implemented as follows:
Public Property KeyID() As Integer Implements DotNetNuke.Entities.Modules.IHydratable.KeyID
Get
Return ItemID
End Get
Set (ByVal value As Integer)
ItemID = value
End Set
End Property
The implementation of the Fill method simply retrieves each of your entity class' properties from the passed-in DataReader. For example, in a simple entity class which exposes only the three properties - ItemID, ModuleID, and ItemContent, the implementation of the Fill method would be as follows:
Public Sub Fill (ByVal dr As IDataReader) Implements DotNetNuke.Entities.Modules.IHydratable.Fill
ItemID = Null.SetNullInteger (dr("ItemID"))
ModuleID = Null.SetNullInteger (dr("ModuleID"))
ItemContent = Null.SetNullString(dr("ItemContent"))
DateCreated = Null.SetNullDateTime(dr("DateCreated"))
End Sub
In the above code, the Null class is a utility class (DotNetNuke.Common.Utilities.Null) containing shared methods which help convert between database null objects and the default application null values of common system types. For example, if the database row passed in the DataReader contains a database null for column of type int, Null.SetNullInteger will return -1.
When called upon to fill an object whose class has implemented IHydratable, the various CBO Fillxxxxxxx methods will no longer have to resort to less-performant reflection techniques but will call the object's Fill method implementation instead.
Another advantage of implementing IHydratable is that your entity class may (but does not have to) expose some or all of its properties as ReadOnly properties. The implementation of Fill can simply assign the value of a column retrieved from the DataReader directly to the class property's internal data store. For example:
Private _CreatedDate As DateTime
Public ReadOnly Property CreatedData As DateTime
Get
Return _CreatedDate
End Get
End Property
Public Sub Fill (ByVal dr As IDataReader) Implements DotNetNuke.Entities.Modules.IHydratable.Fill
' . . . Other assignments as in prior example
_CreatedDate = Null.SetNullDateTime(dr("CreatedDate"))
End Sub
The only downside of implementing IHydratable in your entity classes is that should you later add new columns to the corresponding database table and modify your stored procedures to return those values, you must also remember to revise your implementation of IHydratable's Fill method accordingly.
In DotNetNuke 5.00.00, a new base class, DotNetNuke.Entities.BaseEntityInfo, was introduced to include the following standard readonly audit properties: CreatedByUserID, CreatedOnDate, LastModifiedByUserID, and LastModifiedOnDate which correspond to columns of the same name added to the table used to store your enty class objects which inherit from BaseEntityInfo. BaseEntityInfo exposes the following method:
Protected Overridable Sub FillInternal(ByVal dr As System.Data.IDataReader)
When implementing IHydratable.Fill in your custom entity class, don't forget to first call BaseEntityInfo.FillInternal as well to hydrate it's properties:
Public Sub Fill (ByVal dr As IDataReader) Implements DotNetNuke.Entities.Modules.IHydratable.Fill
MyBase.FillInternal(dr)
' . . . Other assignments as in prior example
End Sub
In DotNetNuke 5.04.00, another new base class, DotNetNuke.Entities.Content.ContentItem, from which your entity classes may inherit was introduced. The ContentItem class which itself inherits from BaseEntityInfo paves the way for easily adding support for taxonomy, tagging and other ContentItem dependant features (perhaps in future versions comments, reviews, ratings, etc.) to your DotNetNuke extensions. Because ContentItem already implements IHydratable, you will not do so in your custom entity class. Instead, you will need to create overrides of the KeyID property and the Fill method already implemented in the ContentItem class. Don't forget to call ContentItem's FillInternal method in your Fill method override:
Public Overrides Sub Fill(ByVal dr As System.Data.IDataReader)
MyBase.FillInternal(dr)
'. . . Assignments to other properties as above
End Sub
References
A Sneak Peek 3 IHydratable Part 1A Sneak Peek 4 - IHydratable Part 2IHydratable-Use the CBO Again For Your DotNetNuke ModuleIHydratable-An Interesting Side Effect