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:
- Through user code regions, which are protected areas in the generated code which contents is preserved when the code is re-generated
- Through include templates, which are templates which are merged at generation time with the standard templates to allow you to merge
your own template code with the standard templates without altering the standard templates
- Through partial classes, which is a .NET 2.0 feature and only available when you generate code for the .NET 2.0 or CF.NET 2.0 platforms.
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:
|
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: |
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:
|
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.
- Create a new textfile in the folder LLBLGen Pro installation folder\Templates and call it MyBindings.templatebindings
- Open VS.NET 2005 and load from the folder LLBLGen Pro installation folder\Tasks\XSDs the file templateBindingsDefinition.xsd
- Open the file MyBindings.templatebindings in VS.NET. If it doesn't open in the XML editor, select Open with... in the VS.NET Open File
dialog to select the XML editor.
- Add the following text
<?xml version="1.0"?>
<templateBindings xmlns="http://sd/llblgen/pro/templateBindingsDefinition.xsd" name="My template bindings"
description ="My include template bindings"
precedenceLevel="11">
<supportedPlatforms>
<platform name=".NET 2.0"/>
<platform name="CF.NET 2.0"/>
</supportedPlatforms>
<language name="C#">
<templateBinding templateID="Custom_EntityUsingEntityBaseTemplate" filename="customEntityCodeInclude.template" />
</language>
<language name="VB.NET">
<!-- If you're using VB.NET, you've should add the binding above here instead. -->
</language>
</templateBindings>
- Verify that everything is as you want it to be, and then save MyBindings.templatebindings.
- If you now load a project into the LLBLGen Pro designer, press F7 and select .NET 2.0 as target platform, you should see your template bindings
on tab 2, at the top of the list.
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:
- _executingGenerator, which is of type IGenerator, your gateway to the Project object and more. IGenerator is defined in the
SD.LLBLGen.Pro.ApplicationCore assembly of the LLBLGen Pro designer.
- _parameters, which is a hashtable with all the parameters defined for the task currently executing, stored with the parameter name as the key.
- _activeObject, of type object
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:
- CurrentEntity, the currently set currentEntity
- CurrentRelatedEntity, the currently set related entity
- CurrentFieldOnRelatedField, the currently set currentfieldOnRelatedField
- CurrentEntityField, the currently set currentEntityField
- CurrentRelatedEntityField, the currently set currentRelatedEntityField
- CurrentEntityFieldRelation, the currently set currentEntityFieldRelation
- CurrentEntityRelation, the currently set currentEntityRelation
- CurrentTypedListRelation, the currently set currentTypedListRelation
- CurrentTypedList, the currently set currenttypedList
- CurrentTypedView, the currently set currenttypedview
- CurrentTypedListField, the currently set currentTypedlistfield
- CurrentSPCall, the currently set currentSPCall
- CurrentSPCallParameter, the currently set currentSPCallParameter
- CurrentTypedViewField, the currently set currentTypedViewField
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.