Alachisoft.com

VB.NET Code Generation Overview

Author: Iqbal M. Khan

TierDeveloper generates .NET components in three layers. These are:

  • Business Layer: Contains two .NET components for each data object defined in a TierDeveloper project. They are:
    • Domain Object: This .NET component contains only the data members with "get" and "set" methods.
    • Business Interface: This is a "stateless" component; meaning that it does not have any state information (data members) in it.
    • Collection Object: This .Net component is used to return a collection of Domain Objects from a query, or passing same to an operation.
  • Data Layer: Contains implementation of data persistence (in factory classes) and definition of hooks. 
    • Standard Methods: These are "Load", "Insert", "Delete", and "Update".
    • Operations: These have custom names and are customized versions of "Insert", "Load", or "Update" methods. The difference here is that these methods may not access all the attributes of the data object. The reason for these methods is to allow custom "Load" or "Update" functions for performance optimization purposes.
    • Query Methods: These usually return a Collection Object for the corresponding component.
    • Related Query Methods: These end up calling a Query method in a related data object and return a collection of DomainObject2 components where DomainObject2 is the related data object.
    • Stored Procedures: These methods make stored procedure calls and return output parameters of the stored procedure and/or a collection of objects if the stored procedure returns a rowset.
    • Bulk Operation Methods: These are either "Bulk Update" or "Bulk Delete" methods defined in the TierDeveloper project. These methods do not return any data.
    • Custom Hooks: If the user has specified that certain methods in a data object should call custom hooks that the user will implement, the corresponding code for it is also generated. Hooks allow you to modify the behavior of data objects without changing the actual data object code.
  • Integration Layer: The Integration layer works as a Service Provider to the client. It contains a Service Provider class, which contains static methods to instantiate the factory interface objects.

Domain Object Component

In our example, the namespace is "Northwind" and the Domain Object is "Customers". Below is the code:

Namespace Northwind.Business.Domain


< Serializable()> _

Public Class Customers _

Inherits PersistentObject _

Implements IComparable



Private _Orders As OrdersCollection = Nothing

Public Sub New()

SetupFields()

End Sub

' <summary>

' Gets or sets the <c>CustomerID</c> attribute value.

' </summary>

' <value>The <c>CustomerID</c> attribute value.</value>

Public Property CustomerID() As String 

Get

If (Not me("CustomerID").Null) Then

Return CType(me("CustomerID").Value, String)

Else

Return Nothing

End If

End Get

Set(ByVal Value As String)

me("CustomerID").Value = Value

End Set

End Property

' <summary>

' Gets or sets the <c>CompanyName</c> attribute value.

' </summary>

' <value>The <c>CompanyName</c> attribute value.</value>

Public Property CompanyName() As String 

Get

If (Not me("CompanyName").Null) Then

Return CType(me("CompanyName").Value, String)

Else

Return Nothing

End If

End Get

Set(ByVal Value As String)

me("CompanyName").Value = Value

End Set

End Property

' <summary>

' Gets or sets the <c>ContactName</c> attribute value.

' </summary>

' <value>The <c>ContactName</c> attribute value.</value>

Public Property ContactName() As String 

Get

If (Not me("ContactName").Null) Then

Return CType(me("ContactName").Value, String)

Else

Return Nothing

End If

End Get

Set(ByVal Value As String)

me("ContactName").Value = Value

End Set

End Property

' <summary>

' Gets or sets the <c>ContactTitle</c> attribute value.

' </summary>

' <value>The <c>ContactTitle</c> attribute value.</value>

Public Property ContactTitle() As String 

Get

If (Not me("ContactTitle").Null) Then

Return CType(me("ContactTitle").Value, String)

Else

Return Nothing

End If

End Get

Set(ByVal Value As String)

me("ContactTitle").Value = Value

End Set

End Property

' <summary>

' Gets or sets the <c>Address</c> attribute value.

' </summary>

' <value>The <c>Address</c> attribute value.</value>

Public Property Address() As String 

Get

If (Not me("Address").Null) Then

Return CType(me("Address").Value, String)

Else

Return Nothing

End If

End Get

Set(ByVal Value As String)

me("Address").Value = Value

End Set

End Property

' <summary>

' Gets or sets the collection of <c>Orders</c> objects.

' </summary>

' <value>The <c>OrdersCollection</c> object.</value>

Public Property Orders() As OrdersCollection 

Get

If Not _Orders Is Nothing Then

Return _Orders

Else

_Orders = New OrdersCollection()

Return _Orders

End If

End Get

Set(ByVal Value As OrdersCollection)

_Orders = Value

End Set

End Property 



Public Sub SetNull(ByVal szFieldName As String ,ByVal bNull As Boolean)

me(szFieldName).Null = bNull

End Sub 

Public Function IsNull(ByVal szFieldName As String) As Boolean

Return me(szFieldName).Null

End Function 

Public Overloads Function CompareTo(ByVal obj As Object) As Integer _
Implements IComparable.CompareTo

If TypeOf obj Is Customers Then

Dim cmpCustomers As Customers = CType(obj, Customers)

Dim compareToValue As Int16 = 0

If (me("CustomerID").Null) Then

Return -1

End If

compareToValue = CustomerID.CompareTo(cmpCustomers.CustomerID)

If compareToValue <> 0

Return compareToValue

End If

Return 0

End If

Throw New ArgumentException("object is not an instance of Customers")

End Function 

Public Overrides Function ToString() As String

Return "[Customers: " & _

" CustomerID = " + CustomerID & _ 

" CompanyName = " + CompanyName & _ 

" ContactName = " + ContactName & _ 

" ContactTitle = " + ContactTitle & _ 

" Address = " + Address & _ 

"]"

End Function 

Private Sub SetupFields()

AddField(New PersistentField("CustomerID", True, False, _
TDevFramework.EDataType.eVarWChar, Nothing))

AddField(New PersistentField("CompanyName", True, False, _
TDevFramework.EDataType.eVarWChar, Nothing))

AddField(New PersistentField("ContactName", False, False, _
TDevFramework.EDataType.eVarWChar, Nothing))

AddField(New PersistentField("ContactTitle", False, False, _
TDevFramework.EDataType.eVarWChar, Nothing))

AddField(New PersistentField("Address", False, False, _
TDevFramework.EDataType.eVarWChar, Nothing))

End Sub 

End Class

End Namespace

Data Persistance Interface Definition

The interface definition below defines all the methods that the user has specified for this data object in TierDeveloper. The implementation of some of these methods is shown on this page.

Namespace Northwind.Business.Interfaces



Public Interface ICustomersFactory

Sub Load(ByVal objInfo As Customers, ByVal nDepth As Int32)

Sub Insert(ByVal objInfo As Customers, ByVal nDepth As Int32)

Sub Update(ByVal objInfo As Customers, ByVal nDepth As Int32)

Sub Delete(ByVal objInfo As Customers, ByVal nDepth As Int32)

Sub Save(ByVal objList As CustomersCollection, ByVal nDepth As Int32)

Sub DeleteColl(ByVal objList As CustomersCollection, ByVal nDepth As Int32)

Function AllCustomers() As CustomersCollection

Function AllCustomersCount() As Int32

Function AllCustomersPR(nSP As Int32 ,nRecords As Int32) As CustomersCollection

Function AllCustomersDS() As DataSet

Function CustomersByCity(ByVal strprmCity As String) As CustomersCollection

Function CustomersByCityDS(ByVal strprmCity As String) As DataSet

Function CustomersByCriteria(where As String, orderBy As String )
As CustomersCollection

Function UpdatePostalCodeByCity(ByVal strPostalCode As String ,
ByVal strprmCity As String) _
As Integer

Function DeleteCustomersByTitle(ByVal strprmContactTitle As String)
As Integer

Sub InsertShortProfile(ByVal objInfo As Customers)

Sub UpdateAddress(ByVal objInfo As Customers)

Sub LoadShortProfile(ByVal objInfo As Customers)

Sub CustOrderHist(ByVal strCustomerID As String , ByRef
returnValue As ArrayList)

Sub LoadChildren(ByVal objInfo As Customers , ByVal nDepth As Int32)

Sub DeleteChildren(ByVal objInfo As Customers , ByVal nDepth As Int32)

Sub LoadOrders(ByVal objInfo As Customers , ByVal nDepth As Int32)

Sub DeleteOrders(ByVal objInfo As Customers , ByVal nDepth As Int32)

End Interface

Standard Load Method for Customers

The Load method loads a single-row from the Customers table and returns a Customers object containing data from it.

' <summary>

' Load (Standard Load Method)

' </summary>

' <remarks>

' Loads a record from the <c>Customers</c> table given by

' the specified primary key.

' </remarks>

' <param name="objInfo">The <c>Customers</c> info
object containing the primary key.</param>

' <param name="nDepth">Specifies depth of children should be loaded.</param>

Public Sub Load(ByVal objInfo As Customers, ByVal nDepth As Int32) _

Implements ICustomersFactory.Load

Try

Dim bRecordsFound As Boolean = False

CheckPrimaryKeyValues(objInfo)

Prepare(STD_LOAD_SQL, USE_STORE_PROC)

BeginTransaction()

Dim status As Integer = 0

Dim hooks As ICustomersHooks = New CustomersHooks()

status = hooks.PreLoad(CType(getConnection(),
TDevFramework.Connection), objInfo)

If (status <> CustomersHooks.SUCCESS_CONTINUE) Then

If (status = CustomersHooks.FAIL_NONCONTINUE) Then

SetStatus(EStatus.eFail)

Else 

SetStatus(EStatus.eSuccess)

End If

ReleaseCommand()

End If

AddCmdParameter("@CustomerID",TDevFramework.EDataType.eVarWChar,
objInfo.CustomerID, _
TDevFramework.EParamDirection.eInput,objInfo.IsNull("CustomerID"))

ExecuteReader()

while (Read())

FillPersistentObject(objInfo)

objInfo.IsNew = False

objInfo.Dirty = False

bRecordsFound = True

End While

status = hooks.PostLoad(CType(getConnection(),
TDevFramework.Connection), objInfo)

If (status <> CustomersHooks.SUCCESS_CONTINUE) Then

If (status = CustomersHooks.FAIL_NONCONTINUE) Then

SetStatus(EStatus.eFail)

Else 

SetStatus(EStatus.eSuccess)

End If

ReleaseCommand()

End If 

ReleaseReader()

If Not bRecordsFound Then 

Throw new RecordNotFoundException("No record found against
given search criteria.")

End If

If (nDepth <> 0) Then

LoadChildren(objInfo, nDepth - 1)

End If

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch e As RecordNotFoundException

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Throw e

Catch e As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw e

End Try

End Sub

Query Method for Customers

This Query Method loads multiple rows from the Customers table and returns a collection of Customers objects with each object containing data from one row.

' <summary>

' AllCustomers (Query Method)

' </summary>

' <remarks>

' 

' </remarks>

' <returns><c>CustomersCollection</c> object containing all the records 

' returned in the resultset.</returns>

Public Function AllCustomers() As CustomersCollection _

Implements ICustomersFactory.AllCustomers

Dim objInfo As Customers

Dim objList As CustomersCollection = New CustomersCollection

Try 

Prepare(AllCustomers_SQL, USE_STORE_PROC)

BeginTransaction()

ExecuteReader()

While (Read())

objInfo = New Customers()

If (Not IsNull("CustomerID")) Then

objInfo.CustomerID = Convert.ToString(getValue("CustomerID"))

End If

If (Not IsNull("CompanyName")) Then

objInfo.CompanyName = Convert.ToString(getValue("CompanyName"))

End If

If (Not IsNull("ContactName")) Then

objInfo.ContactName = Convert.ToString(getValue("ContactName"))

End If

If (Not IsNull("ContactTitle")) Then

objInfo.ContactTitle = Convert.ToString(getValue("ContactTitle"))

End If

If (Not IsNull("Address")) Then

objInfo.Address = Convert.ToString(getValue("Address"))

End If

objInfo.IsNew = False

objInfo.Dirty = False

objList.Add(objInfo)

End While

ReleaseReader()

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch e As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw e

End Try

Return objList

End Function

Bulk Update Method for Customers

Following is the code generated for "UpdatePostalCodeByCity", a bulk method that update the postal code of particular city.

' <summary>

' UpdatePostalCodeByCity (Bulk Update Method)

' </summary>

' <remarks>

' <para>Updates all the record in <c>Customers</c>
table matching the given criteria.</para>

' <para>

' </para>

' </remarks>

' <returns>The number of rows affected.</returns> 

Public Function UpdatePostalCodeByCity (ByVal strPostalCode As String , _
ByVal strprmCity As String) As Integer _

Implements ICustomersFactory.UpdatePostalCodeByCity

Dim result As Integer = 0

Try

Prepare(UpdatePostalCodeByCity_SQL, USE_STORE_PROC)

BeginTransaction()

AddCmdParameter("@PostalCode", TDevFramework.EDataType.eVarWChar,
strPostalCode, _EParamDirection.eInput)

AddCmdParameter("@prmCity", TDevFramework.EDataType.eVarChar,
strprmCity, _EParamDirection.eInput)

result = ExecuteNonQuery()

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch e As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw e

End Try

Return result

End Function

Related Query Method for Customers

The Related Query Method actually returns a collection of related "Orders" object. It does this by calling a query method in the related data object.

' <summary>

' OrdersQuery (Query Method)

' </summary>

' <remarks>

' </remarks>

' <returns><c>OrdersCollection</c> object containing all the records 

' returned in the resultset.</returns>

Public Function OrdersQuery( ByVal strprmCustomerID As String)
As OrdersCollection _

Implements IOrdersFactory.OrdersQuery

Dim objInfo As Orders

Dim objList As OrdersCollection = New OrdersCollection

Try 

Prepare(OrdersQuery_SQL, USE_STORE_PROC)

BeginTransaction()

AddCmdParameter("@prmCustomerID", TDevFramework.EDataType.eVarChar, _
strprmCustomerID, EParamDirection.eInput)

ExecuteReader()

While (Read())

objInfo = New Orders()

If (Not IsNull("OrderID")) Then

objInfo.OrderID = Convert.ToInt32(getValue("OrderID"))

End If

If (Not IsNull("CustomerID")) Then

objInfo.CustomerID = Convert.ToString(getValue("CustomerID"))

End If

If (Not IsNull("EmployeeID")) Then

objInfo.EmployeeID = Convert.ToInt32(getValue("EmployeeID"))

End If

If (Not IsNull("OrderDate")) Then

objInfo.OrderDate = Convert.ToDateTime(getValue("OrderDate"))

End If

If (Not IsNull("RequiredDate")) Then

objInfo.RequiredDate = Convert.ToDateTime(getValue("RequiredDate"))

End If

objInfo.IsNew = False

objInfo.Dirty = False

objList.Add(objInfo)

End While

ReleaseReader()

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch e As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw e

End Try

Return objList

End Function

Stored Procedure Method for Customers

The Stored Procedure Method calls a stored procedure in the database. It passes any IN, IN/OUT, and OUT parameters to this stored procedure. If the stored procedure is returning a rowset then this method returns a collection containing the data.

' <summary>

' CustOrderHist (Stored Procedure Method)

' </summary>

' <remarks>

' <para>Executes the stored procedure <c>CustOrderHist;1</c>.</para>

' <para>

' </para>

' </remarks> 

Public Sub CustOrderHist(ByVal strCustomerID As String ,
ByRef returnValue As ArrayList) _

Implements ICustomersFactory.CustOrderHist

Dim sqlCmd As String = "CustOrderHist;1"

Dim objList As ArrayList = New ArrayList()

Try

Prepare(sqlCmd, True)

AddCmdParameter("@CustomerID", TDevFramework.EDataType.eVarWChar,
strCustomerID, _
TDevFramework.EParamDirection.eInput, 10)

ExecuteReader()

While (Read())

Dim objInfo As ArrayList = New ArrayList()

Dim fieldCount As Integer = getFieldCount()

Dim index As Integer

If (objList.Count = 0) Then

For index = 0 To fieldCount - 1

objInfo.Add(getFieldName(index))

Next index

objList.Add(objInfo)

objInfo = New ArrayList()

End If

For index = 0 To fieldCount - 1

objInfo.Add(getValue(index))

Next index

objList.Add(objInfo)

End While

returnValue = objList

SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch ex As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw ex

End Try

End Sub

Custom Hooks Inside Generated Code

TierDeveloper optionally generates "ObjectName" Hooks classes if the user has selected/specified "Pre" and "Post" hooks for certain methods of data object through data object settings in TierDeveloper. For example in this case TierDeveloper generates CustomersHooks.cs file. The "Pre" and "Post" Hook Methods for "InsertShortProfile" custom operation are shown below:

Public Function PreInsertShortProfile(ByRef Conn As TDevFramework.Connection,
_ByRef objInfo As Customers) As Integer _

Implements ICustomersHooks.PreInsertShortProfile

Return SUCCESS_CONTINUE

End Function



Public Function PostInsertShortProfile(ByRef Conn As TDevFramework.Connection,
_ByRef objInfo As Customers) As Integer _

Implements ICustomersHooks.PostInsertShortProfile

Return SUCCESS_CONTINUE

End Function

Custom Operation Method with Hooks Being Called

This is the generated code for a Custom Insert Operation "InsertShortProfile". The "Pre" and "Post" hook methods (optional) are called before and after the database operation is performed.

' <summary>

' InsertShortProfile (Custom Insert Method)

' </summary>

' <remarks>

' <para>Inserts partial record into <c>Customers</c> table.</para>

' <para>

' </para>

' </remarks>

' <param name="objInfo">The <c>Customers</c> info object to be inserted.</param> 

Public Sub InsertShortProfile(ByVal objInfo As Customers ) _

Implements ICustomersFactory.InsertShortProfile

Try

objInfo.ValidateRequiredFields()

Prepare(InsertShortProfile_SQL, USE_STORE_PROC)

BeginTransaction()

Dim status As Integer = 0

Dim hooks As ICustomersHooks = New CustomersHooks()

status = hooks.PreInsertShortProfile(CType(getConnection(),
TDevFramework.Connection), _objInfo)

If (status <> CustomersHooks.SUCCESS_CONTINUE) Then

If (status = CustomersHooks.FAIL_NONCONTINUE) Then

SetStatus(EStatus.eFail)

Else 

SetStatus(EStatus.eSuccess)

End If

ReleaseCommand()

End If
AddCmdParameter("@CustomerID", TDevFramework.EDataType.eVarWChar,
objInfo.CustomerID, _TDevFramework.EParamDirection.eInput,
objInfo.IsNull("CustomerID"))

AddCmdParameter("@CompanyName", TDevFramework.EDataType.eVarWChar,
objInfo.CompanyName, _TDevFramework.EParamDirection.eInput,
objInfo.IsNull("CompanyName"))

AddCmdParameter("@ContactName", TDevFramework.EDataType.eVarWChar,
objInfo.ContactName, _TDevFramework.EParamDirection.eInput,
objInfo.IsNull("ContactName"))

AddCmdParameter("@ContactTitle", TDevFramework.EDataType.eVarWChar, _
objInfo.ContactTitle, TDevFramework.EParamDirection.eInput, _
objInfo.IsNull("ContactTitle"))

ExecuteNonQuery()

status = hooks.PostInsertShortProfile(CType(getConnection(),
TDevFramework.Connection), _objInfo)

If (status <> CustomersHooks.SUCCESS_CONTINUE) Then

If (status = CustomersHooks.FAIL_NONCONTINUE) Then

SetStatus(EStatus.eFail)

Else 

SetStatus(EStatus.eSuccess)

End If

ReleaseCommand()

End If
SetStatus(EStatus.eSuccess)

ReleaseCommand()

Catch e As Exception

SetStatus(EStatus.eFail)

ReleaseCommand()

Throw e

End Try

End Sub

ObjectCollection Component

The ObjectCollection is mostly used to return a collection of Domain Objects as a result of Queries.

Namespace Northwind.Business.Domain

< Serializable()> _

Public Class CustomersCollection Inherits Collection

Public Sub New()

'--

End Sub

' <summary>

' Gets the <c>Customers</c> object at the specified index.

' </summary>

' <value>The <c>Customers</c> object.</value>

Default Public Property item(ByVal index As Integer) As Customers 

Get

Return CType(List(index), Customers)

End Get

Set

List(index) = value

End Set

End Property

Public Overloads Sub Add(ByRef value As Customers) 

MyBase.Add(value)

End Sub

Public Overloads Sub Remove(ByRef value As Customers) 

MyBase.Remove(value)

End Sub

' <summary>

' If value is not of type object, this will return false.

' </summary>

Public Overloads Function Contains(ByRef value As Customers) As Boolean 

Return MyBase.Contains(value)

End Function

Public Function GetIndexOf(ByVal value As Customers) As Int32

Dim _obj As Customers

Dim index As Int32 = 0

For Each _obj In List

If _obj.CompareTo(value) = 0 Then

Return index

End If

index = index + 1

Next

Return -1

End Function

Public Function ToDataSet() As DataSet 

Dim dSet As DataSet = New DataSet("Customers")

dSet.Tables.Add(CreateTable())

Dim i As Integer = 0

While i < Me.Count

Dim dRow As DataRow = dSet.Tables("Customers").NewRow()

dRow("CustomerID") = Me(i).CustomerID

dRow("CompanyName") = Me(i).CompanyName

dRow("ContactName") = Me(i).ContactName

dRow("ContactTitle") = Me(i).ContactTitle

dRow("Address") = Me(i).Address

i = i + 1

End While

Return dSet

End Function

public Function CreateTable() As DataTable

Dim oDataTable As DataTable = new DataTable("Customers") 

oDataTable.Columns.Add(new DataColumn("CustomerID")) 

oDataTable.Columns.Add(new DataColumn("CompanyName")) 

oDataTable.Columns.Add(new DataColumn("ContactName")) 

oDataTable.Columns.Add(new DataColumn("ContactTitle")) 

oDataTable.Columns.Add(new DataColumn("Address")) 

Return oDataTable

End Function

#Region "Sort Methods"

Public Shadows Sub Sort()

Dim comparer As AttributeComparer = new AttributeComparer()

comparer.AddAttribute("CustomerID")

MyBase.Sort(comparer)

End Sub

Public Shadows Sub Sort (ByRef comparer As AttributeComparer)

MyBase.Sort(comparer)

End Sub

Public Shadows Sub Sort (ByVal index As Int32, ByVal count As Int32, _
ByRef comparer As AttributeComparer)

MyBase.Sort(index, count, comparer)

End Sub

#End Region

End Class

End Namespace

ServiceProvider Component

The ServiceProvider contains static methods to instantiate the factory interface objects.

Namespace Northwind.Integration

Public Class ServiceProvider

#Region "[CustomersFactory]"

Public Shared Function getCustomersFactory() As ICustomersFactory 

Return Persistence.ServiceProvider.getCustomersFactory()

End Function

Public Shared Function getCustomersFactory(ByVal strConn As String )
As ICustomersFactory 

Return Persistence.ServiceProvider.getCustomersFactory(strConn)

End Function

Public Shared Function getCustomersFactory(ByVal tdevConn As
TDevFramework.Connection) _
As ICustomersFactory 

Return Persistence.ServiceProvider.getCustomersFactory(tdevConn)

End Function

Public Shared Function getCustomersFactory(ByVal objConn As Object)
As ICustomersFactory 

Return Persistence.ServiceProvider.getCustomersFactory(objConn)

End Function

#End Region

End Class

End Namespace

Author: Iqbal M. Khan works for Alachisoft, a leading software company providing .NET and Java distributed caching, O/R Mapping and SharePoint Storage Optimization solutions. You can reach him iqbal@alachisoft.com or visit Alachisoft at www.alachisoft.com.