Using partial methods

One of the best things about code generation is that you can keep generating your code while preserving your custom changes. You implement custom logic, and still change your database and pick up template changes whenever you like. The CSLA templates give you many partial methods for this. Implement them in the non-generated partial class of the business object.

Note

The partial method names are the same as in the CSLA Contrib templates, so code written for those templates works with the CSLA templates.

The partial methods are listed at the bottom of every generated partial class. For example:

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

Example: customize a fetch

In this example, you generate a DynamicListBase business object called CalendarList, which holds a list of EditableRoot Calendar business objects. By default, the generated code selects all the calendar entries that match the criteria. The example uses this Calendar table:

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

This is the code 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

Suppose you only want the calendar entries from the first day of the current month onward. Implement the OnFetching partial method with a modified SQL statement, in the non-generated partial class (CalendarList.cs or CalendarList.vb):

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:

#Region "Custom Data Access"

Private Sub OnFetching(ByVal criteria As CalendarCriteria, 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

All it takes is implementing OnFetching and replacing the SQL query sent to the database server. You can do anything you want in a partial method.

The cancel parameter controls what happens after the partial method returns:

cancel Result
true The generated code after the partial method call is skipped. This example uses true, because it replaces the generated query.
false The generated code runs too. Use this when you want to do some processing before the database is accessed.

If you need a partial method that doesn't exist, request it in the CSLA templates issue tracker.