Generated code - Adding your own code to the generated classes

Preface

Generated code is great, but sometimes you want to add your own functionality to it, use it as a base to build upon. Adding your own code to generated classes is risky as when you re-generate the code into the same folder, your changes will be overwritten. LLBLGen Pro offers several ways to add your own code to the generated code:

This section describes in detail the user code regions and the include templates in greater detail. For include templates it's recommended you use the Template Studio application, the LLBLGen Pro template editor IDE, which is available free of charge for customers, and read the LLBLGen Pro SDK documentation.

Using partial classes is straight forward and therefore it's discussed briefly in this section.

User code regions

User code regions are regions which are marked by a start marker and an end marker, both prefixed by the comment operator of the language used ("//" for C# and "'" for VB.NET). The start marker also contains the name of the user code region. The LLBLGen Pro code generator engine is able to handle multiple user code regions per code file in various scopes. To be able to do this the regions have to be declared in the templates used. This means that you can't add your own user code regions to the generated code, though as there are a lot of user code regions defined, in general you won't run into the need for other user code regions.

The start marker is __LLBLGENPRO_USER_CODE_REGION_START. The end marker is __LLBLGENPRO_USER_CODE_REGION_END. So a typical example of a user code region is:

// C#
// __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
// __LLBLGENPRO_USER_CODE_REGION_END
' VB.NET
' __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
' __LLBLGENPRO_USER_CODE_REGION_END

This user code region has the name AdditionalNamespaces. To add your own code to a region, place it on lines between the markers. The markers have to be on separate lines. So an addition to the example above would be:

// C#
// __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
using System.Data;
// __LLBLGENPRO_USER_CODE_REGION_END
' VB.NET
' __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
Imports System.Data
' __LLBLGENPRO_USER_CODE_REGION_END

The code generator engines for TDL (CodeEmitter) and .lpt templates both can handle user code regions so the concepts to use them are the same. Both code generator engines use the user code region name to find back a region in an existing file with the same name. This means that if you generate code into an empty folder each time you generate code, your additions are not preserved as the code generator can't read the current code file and can't find your additions which have to be preserved.
Defined user code regions
To locate the defined user code regions in the generated code you can use the following table. Per generated code file, the regions defined are specified with their name and a suggested purpose. You can of course use the regions for other purposes, though the suggestions can help you decide where to place which code. The following user code regions are added to the TDL templates. The class is given, the name of the region and an example purpose.

Class(es) Region name Purpose
constantsEnums.cs/vb CustomUserContstants Additional user constants added to the generated code project. Has namespace scope.
*Entity.cs/vb (Adapter / SelfServicing + general preset), *EntityBase.cs/vb (2 class scenario) DeserializationConstructor Additional code for deserialization, for example deserializing own added properties. Has method scope.
*Entity.cs/vb (Adapter / SelfServicing + general preset), *EntityBase.cs/vb (2 class scenario) PrivateMembers Additional members can be declared here. Has class scope
*Entity.cs/vb (Adapter / SelfServicing + general preset), *EntityBase.cs/vb (2 class scenario) GetObjectInfo Additional code for serialization of own member variables. Has method scope.
*Entity.cs/vb (Adapter / SelfServicing + general preset), *EntityBase.cs/vb (2 class scenario) InitClassMembers Additional initialization code for own member variables. Has method scope.
*Entity.cs/vb (Adapter / SelfServicing + general preset), *EntityBase.cs/vb (2 class scenario) InitClassEmpty Additional initialization code for an empty entity. Has method scope.
*Entity.cs/vb, *EntityBase.cs/vb CustomEntityCode General area for adding new code to the entity. It has class scope. Has class scope.
*Entity.cs/vb, *EntityBase.cs/vb AdditionalInterfaces Region right after the entity class header which allows for adding additional interfaces.
*Entity.cs/vb (SelfServicing + general preset), *EntityBase.cs/vb (SelfServicing + TwoClasses preset) InitClassFetch Additional initialization code for an entity which is directly fetched using the constructor. Has method scope
*Collection.cs/vb (SelfServicing), EntityCollection (Adapter) CustomEntityCollectionCode General area for adding new code to the entity collection class. Has class scope.
*DAO.cs/vb CustomDaoCode General area for adding new code to the dao class. Has class scope.
EntityFactories.cs/vb (Adapter) CreateNewentityname Region in the Create method of the entity factory which can hold extra initialization code. Has method scope
EntityFactories.cs/vb (Adapter) CreateNewentitynameUsingFields Region in the Create method of the entity factory which accepts fields, which can hold extra initialization code. Has method scope
EntityFactories.cs/vb (Selfservicing) CreateNewentityname Region in the Create method of the entity factory which can hold extra initialization code. Has method scope.

note Note:
This region is implemented in the entityfactory include template: entityFactoryInclude.template

*Validator.cs/vb ValidationLogic Region to which custom field validation logic can be added.
DataAccessAdapter.cs/vb CustomDataAccessAdapterCode Region for general code added to a DataAccessAdapter class. Has class scope
DataAccessAdapter.cs/vb InsertPersistenceInfoObjectsPredicate Region for persistence info insertion for custom predicate classes.
*TypedList.cs/vb AdditionalRelations Region for adding new relations to the typed list in code.
*TypedList.cs/vb, *TypedView.cs/vb AdditionalFields Region for adding new fields to the typed list in code, for example by adding an expression field. Use the ResultsetFields.Expand(int) method to increase the size of the resultset fields collection.
*TypedList.cs/vb AdditionalInterfacesList Region for additional interface definitions to implement by the TypedList main class. Has class scope.
*TypedList.cs/vb AdditionalInterfacesView Region for additional interface definitions to implement by the TypedView main class. Has class scope.
*TypedList.cs/vb, *TypedView.cs/vb AdditionalInterfacesRow Region for additional interface definitions to implement by the TypedList / TypedView row class. Has class scope.
All classes which have a user code region AdditionalNamespaces To declare additional namespace using (imports) statements for namespaces referenced in the code added to the user code regions. In C# these regions are added inside the namespace declaration, in VB.NET they're added at the bottom of the Imports list.
*TypedList.cs/vb, *TypedView.cs/vb PrivateMembers Additional members can be declared here. Has class scope
*TypedList.cs/vb, *TypedView.cs/vb InitClass Additional initialization code for adding own columns. Has method scope.
*TypedList.cs/vb, *TypedView.cs/vb InitMembers Additional initialization code for initializing own member variables. Has method scope.
*TypedList.cs/vb, *TypedList.cs/vb AdditionalColumnProperties Region to declare additional internal column properties which return columns added in code. Has class scope.
*TypedList.cs/vb CustomTypedListCode Region for additional code for the Typedlist class. Has class scope.
*TypedView.cs/vb CustomTypedViewCode Region for additional code for the TypedView class. Has class scope.
*TypedList.cs/vb, *TypedView.cs/vb CustomTypedListRowCode Region for additional code for the TypedlistRow / TypedViewRow class. Has class scope.
If you need additional user code regions added to the generated code, feel free to request these by mailing to support@llblgen.com.

note Note:
If you're adding custom code to user code regions which are inside Init methods and which receive an EntityFields(2) object, be sure to first test the State property of that fields object to see if it's equal to EntityState.New. If not, e.g. it's EntityState.Fetched, you shouldn't set any field values to initialize these fields, because the passed in EntityFields(2) object is already filled with data from the database. Setting fields to a value in that particular situation will overwrite the values from the database, which could lead to unpredictable results.

.NET 2.0 and higher: Partial classes

In .NET 2.0, partial classes are introduced and LLBLGen Pro generates all classes for .NET 2.0 and CF.NET 2.0 as partial classes. For VB.NET 2005 this doesn't make a difference as any class can be extended by another code file with a partial class definition with the same name, though in C#, all classes are generated as partial classes. To extend any class in the generated code, just define in the same namespace and assembly a new definition of an existing class and specify the keyword partial (C#) or Partial (VB.NET). For example, consider an entity CustomerEntity being generated by LLBLGen Pro. You can then extend this class by adding a new file to the generated VS.NET 2005 project and add the following code to that file: (the rootnamespace used for this project was 'Northwind')

// C#
namespace Northwind.EntityClasses
{
	public partial class CustomerEntity
	{
		// your code here
	}
}
' VB.NET
Namespace Northwind.EntityClasses
	Public Partial Class CustomerEntity
		' your code here
	End Class
End Namespace

You can then add your code to this class which will then be compiled into the class with the same name in the same project by VS.NET 2005. Be aware that you're not inheriting a class, so you can't specify a method or property with a name already in the generated code's class

Include templates


note Note:
Include templates is an advanced topic for which it's recommended you've read the the LLBLGen Pro SDK (available to customers) documentation. It is possible to get started without the SDK, but it is recommended to consult the SDK for further details.

LLBLGen Pro's code generator engines can handle include templates, which means that in a template, a template include statement can be added and the contents of the template bound to the template id specified in the template include statement will replace the template include statement. This is similar to the well known include tags for ASP pages. The includes can be used recursively, which means an included template can again contain include statements. At various places in the templates of the SelfServicing and Adapter template groups, include statements are added. Furthermore, several templates have been broken into several templates to make it easier to adjust the generated code through include templates.

As include templates work with template id's, using a template bindings file which binds a different code file to a template id can make the generated code look different: your template will be included into the standard template and executed together with the standard template. Please also see Concepts - Templates and Template groups and Designer - Generating code for more information about templatebindings files and how to use them in the designer, for example how to make your template overrule a standard template.

To easily create templatebindings files, please use the templateBindingsDefinition.xsd file in the Tasks\XSDs folder in the LLBLGen Pro installation folder. If you first open the .xsd in VS.NET 2005 and then your templatebindings file, you have intellisense on the xml you write in your templatebindings file.

Below is a list of template id's you can add to your own templatebindings file and which will make the contents of the file bound to the template id be inserted into the template the template is included in. There are more template ids defined for this purpose, though beginners should start with this list. The full list is available in the SDK documentation.

TemplateID Description Included in
Custom_CommonEntityBaseTemplate Custom include template ID for the template which is used for the CommonEntityBase class, which is the class sitting in between the EntityBase(2) classes and the generated entity classes. The CommonEntityBase class.
Custom_ConstantsEnumsTemplate Custom include template ID for the template which is used for the ConstantsEnums codefile. The Root namespace specification of SD_ConstantsEnumsTemplate
Custom_DataAccessAdapterTemplate Custom include template ID for the general data access adapter object. Database specific. Adapter specific. The DataAccessAdapter class
Custom_DbUtilsTemplate Custom include template ID for the template which is used for the DbUtils helper class. The DbUtils class
Custom_EntityAdapterTemplate Custom include template ID for entity classes. Adapter specific. The [EntityName]Entity classes.
Custom_EntityBaseTemplate Custom include template ID for the template which is used for the entity base classes in a scenario where two classes per entity are generated. The [EntityName]EntityBase classes
Custom_EntityCollectionAdapterTemplate Custom include template ID for the general collection class for all entities. Adapter specific The EntityCollection class
Custom_EntityCollectionTemplate Custom include template ID for the template which is used for the Entity Collection classes. The [EntityName]Collection classes
Custom_EntityDAOTemplate Custom include template ID for the template which is used for the Dao classes in selfservicing. The [EntityName]DAO classes
Custom_EntityInitializationTemplate Custom include template ID which is used for templates which are inserted into the InitClass* methods of an entity, at the end of the init class method. All entity classes (selfservicing/adapter)
Custom_EntityTemplate Custom include template ID for the template which is used for the Entity classes. The [EntityName]Entity classes.
Custom_EntityUsingEntityBaseTemplate Custom include template ID for the template which is used for the entity classes in a scenario where two classes per entity are generated. The [EntityName]Entity classes.
Custom_EntityValidatorTemplate Custom include template ID for the template which is used for the Validator classes per entity, used for per field validation. This template is included in the class, not in the method. For injection of custom validation code into the Validate method, bind SD_EntityValidatorIncludeTemplate to your custom template. The [EntityName]Validator classes.
Custom_ResultsetFieldsAdapterTemplate Custom include template ID for the resultsets class, used in typed lists. Adapter specific. The ResultsetFields class
Custom_ResultsetFieldsTemplate Custom include template ID for the template which is used for the ResultsetFields helper class. The ResultsetFields class
Custom_TypedListAdapterTemplate Custom include template ID for the typed list classes. Adapter specific. The [TypedListName]TypedList class. No include is specified for the [TypedListName]TypedListRow class.
Custom_TypedListDAOTemplate Custom include template ID for the template which is used for the TypedList DAO class, which is also used by Typed Views. The TypedListDAO class
Custom_TypedListTemplate Custom include template ID for the template which is used for the TypedList classes. The [TypedListName]TypedList class. No include is specified for the [TypedListName]TypedListRow class.
Custom_TypedViewAdapterTemplate Custom include template ID for the typed view classes. Adapter specific. The [TypedViewName]TypedView class. No include is specified for the [TypedViewName]TypedViewRow class.
Custom_TypedViewTemplate Custom include template ID for the template which is used for the TypedView classes. The [TypedViewName]TypedView class. No include is specified for the [TypedViewName]TypedViewRow class.

A good place to start is adding a template binding to Custom_EntityInitializationTemplate. The contents of the template bound to that template id will then be inserted into the InitClass methods of the entity classes. This template can for example be used to set the ConcurrencyPredicateFactoryToUse property of every entity to an instance of a generic IConcurrencyPredicateFactory implementation. As it will be code which will be generated into the generated code, you don't have to worry about losing your additions: they're always there. Keep your include templates with your .lgp project file so you'll always have them available with the .lgp project file. You can specify in the .lgp file an additional Templates folder where you can store the templatebindings files and templates you've created.

Include templates can be either written using Template Definition Language (TDL, which is LLBLGenPro's native template language) or using C# or VB.NET in .lpt templates (which use the <% %> syntaxis for code blocks, similar to asp syntaxis).

The tutorial below is a small tutorial to write an include template using a simple text editor or VS.NET 2005, as is used below.
Adding code to an entity
We will first create a new templatebindings file for our template. The template file and the templatebindings file are stored in the default folder for templates: LLBLGen Pro installation folder\Templates.

After creating the templatebindings file, we're now set to write the actual template so we can use it in the code generation process. The example above bound the template id Custom_EntityUsingEntityBaseTemplate to the template we will write in next steps. This means it will be used in SelfServicing TwoClasses scenario's. If you're using Adapter, you should specify Custom_EntityAdapterTemplate instead in the templatebindings above.

Writing the actual template takes a few steps. You can use any text editor you want.
Using .lpt templates as include templates
As discussed briefly in the previous section, LLBLGen Pro supports two kinds of templates: TDL templates and .lpt templates. The .lpt templates are templates which have the template code in <% %> brackets, similar to various code generators out there, and the template code is able to access every element in the LLBLGen Pro project object graph. Starting from v1.0.2005.1, you can bind a .lpt template to a template ID which is used for including another template, so you can use .lpt templates as include templates. TDL templates are interpreted, .lpt templates are compiled into an assembly, though this is handled by the TDL interpreter for you and it integrates transparently.

As discussed in the LLBLGen Pro SDK, each .lpt template results in a class which implement ITemplateClass. In your template you have acces to three main parameters: In your .lpt template you can access these objects and the data they contain in your script blocks. We'll see how this works by rewriting the previous example in an .lpt include template below. When a .lpt template is used as an include template, the TDL interpreter will pass on its complete state to the .lpt template in the _activeObject, which will represent a Hashtable. The following list shows which object is stored under which key in the _activeObject's Hashtable. It contains the current scope of the TDL interpreter at the point when the template include statement was found:

Keys are strings, values are objects or null if not set.

With this knowledge we can rewrite previous section's tutorial a little to use a .lpt include template instead: You should then again generate code as previously stated. It should give you the same code as before.

LLBLGen Pro v2.6 documentation. ©2002-2008 Solutions Design