Using partial methods

One of the best features of code generation is the reality of being able to actively generate your code while preserving custom changes. This allows you to implement custom logic while constantly making changes to your metadata and getting the latest template changes. The CSLA templates offer many partial method overrides to make your life easier. It is recommended that you place any partial methods that you implement in the non-generated partial class; please see this for more information.

Existing users who were using the CSLA Contrib templates can quickly upgrade the the official CSLA templates. This is possible, because we have kept the partial methods names consistent with the previous templates.

A list of partial methods can be found at the bottom of the every generated partial class. Here is an example of the generated partial methods.

C#

 

#region DataPortal partial methods
 
partial void OnCreating(ref bool cancel);
partial void OnCreated();
partial void OnFetching(CalendarCriteria criteria, ref bool cancel);
partial void OnFetched();
partial void OnMapping(SafeDataReader reader, ref bool cancel);
partial void OnMapped();
partial void OnUpdating(ref bool cancel);
partial void OnUpdated();
partial void OnAddNewCore(ref Calendar item, ref bool cancel);
 
#endregion

 

Visual Basic

 

#Region "DataPortal partial methods"
     
Partial Private Sub OnCreating(ByRef cancel As Boolean)
End Sub
Partial Private Sub OnCreated()
End Sub
Partial Private Sub OnFetching(ByVal criteria As CalendarCriteria, ByRef cancel As Boolean)
End Sub
Partial Private Sub OnFetched()
End Sub
Partial Private Sub OnMapping(ByVal reader As SafeDataReader, ByRef cancel As Boolean)
End Sub
Partial Private Sub OnMapped()
End Sub
Partial Private Sub OnUpdating(ByRef cancel As Boolean)
End Sub
Partial Private Sub OnUpdated()
End Sub
Partial Private Sub OnAddNewCore(ByVal item As Calendar, ByRef cancel As Boolean)
End Sub
     
#End Region

In this example we will be generating a DynamicListBase business object called CalendarList, whose purpose is to hold a list of EditableRoot Calendar business objects. The default generated code will select all calendar entries within a specific criterion. We will be using the Calendar table with the following definition:

CREATE TABLE [dbo].[Calendar](
	[ID] [nvarchar](50) NOT NULL,
	[CalendarName] [nvarchar](50) NOT NULL,
	[Name] [nvarchar](50) NOT NULL,
	[EventStart] [datetime] NOT NULL,
	[EventEnd] [datetime] NOT NULL,
	[Resource] [nvarchar](150) NOT NULL,
 CONSTRAINT [PK_Calendar] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

The code below is the code that is generated in the CalendarList.DataAccess partial class:

C#

 

private void DataPortal_Fetch(CalendarCriteria criteria)
{
    bool cancel = false;
    OnFetching(criteria, ref cancel);
    if (cancel) return;
    RaiseListChangedEvents = false;
    // Fetch Child objects.
    string commandText = String.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0}", ADOHelper.BuildWhereStatement(criteria.StateBag));
    using (var connection = new SqlConnection(ADOHelper.ConnectionString))
    {
        connection.Open();
        using (var command = new SqlCommand(commandText, connection))
        {
            command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag));
            using(var reader = new SafeDataReader(command.ExecuteReader()))
            {
                if(reader.Read())
                {
                    do
                    {
                        this.Add(Calendar.GetCalendar(reader));
                    } while(reader.Read());
                }
            }
        }
    }
    RaiseListChangedEvents = true;
    OnFetched();
}

 

Visual Basic

 

Private Shadows Sub DataPortal_Fetch(ByVal criteria As CalendarCriteria)
    Dim cancel As Boolean = False
    OnFetching(criteria, cancel)
    If (cancel) Then
        Return
    End If
    
    RaiseListChangedEvents = False
    
    ' Fetch Child objects.
    Dim commandText As String = String.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0}", ADOHelper.BuildWhereStatement(criteria.StateBag))
    Using connection As New SqlConnection(ADOHelper.ConnectionString)
        connection.Open()
        Using command As New SqlCommand(commandText, connection)
            command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag))
            Using reader As SafeDataReader = New SafeDataReader(command.ExecuteReader())
                If reader.Read() Then
                    Do
                        Me.Add(Calendar.GetCalendar(reader))
                    Loop While reader.Read()
                End If
            End Using
        End Using
    End Using
    
    RaiseListChangedEvents = True
    
    OnFetched()
End Sub

As you can see, this isn't optimal because we only want to select all Calendar entries from the first of the current month. In the real world we would only want to select maybe a month or two of data... This can easily be done by implementing the partial method for OnFetching and modifying the SQL statement. We will now go to the partial non generated class (CalendarList.cs or CalendarList.vb) and update the code.

C#

 

#region Custom Data Access

partial void OnFetching(CalendarCriteria criteria, ref bool cancel)
{
    RaiseListChangedEvents = false;
    // Fetch Child objects.
    string commandText = string.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0} AND [EventStart] >= CONVERT(varchar,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0),101)", ADOHelper.BuildWhereStatement(criteria.StateBag));
    using (var connection = new SqlConnection(ADOHelper.ConnectionString))
    {
        connection.Open();
        using (var command = new SqlCommand(commandText, connection))
        {
            command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag));
            using (var reader = new SafeDataReader(command.ExecuteReader()))
            {
                if (reader.Read())
                {
                    do
                    {
                        this.Add(Calendar.GetCalendar(reader));
                    } while (reader.Read());
                }
            }
        }
    }
    RaiseListChangedEvents = true;
    // Cancel the existing Dal method.
    cancel = true;
}

#endregion

 

Visual Basic

Private Sub OnFetching(ByVal criteria As CategoryCriteria, ByRef cancel As Boolean)
    RaiseListChangedEvents = False
 
    ' Fetch Child objects.
    Dim commandText As String = String.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0} AND [EventStart] >= CONVERT(varchar,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0),101)", ADOHelper.BuildWhereStatement(criteria.StateBag))
    Using connection As New SqlConnection(ADOHelper.ConnectionString)
        connection.Open()
        Using command As New SqlCommand(commandText, connection)
            command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag))
            Using reader As SafeDataReader = New SafeDataReader(command.ExecuteReader())
                If reader.Read() Then
                    Do
                        Me.Add(Calendar.GetCalendar(reader))
                    Loop While reader.Read()
                End If
            End Using
        End Using
    End Using
 
    RaiseListChangedEvents = True
     'Cancel the existing Dal method.
 
    cancel = True
End Sub
#End Region

As you can see all we needed to do was implement the OnFetching partial method and override the sql query that was then sent to the database server. You can do anything you want in this partial method. The last thing to do is set the reference cancel variable to true if you wish to have everything after the partial method call ignored. If you set this to false, then the existing generated code will also run. In this case, we want to cancel out. A scenario where you would want to return false, is if you wanted to do some processing before accessing the database.

If you come across something that you wish had a partial method, please log it on the CodeSmith Generator template issue tracker.