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.
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.