- Home
- LLBLGen Pro
- Custom Templates
How to get type of an Entity field. Check if nullable?
Joined: 15-Nov-2005
Using LLBLGen 5.6.1. Using LLBLGen Runtime.
I was trying to make a .lpt template where I cycle through the entity fields and make variables that correspond to those entity fields.
EntityDefinition currentEntity = (EntityDefinition)_activeObject;
foreach(var field in currentEntity.Fields)
{
string camelCaseFieldName = "_" + field.Name.First().ToString().ToLower() + field.Name.Substring(1);
%>
private <%= field.FieldType.RepresentedType%> <%= camelCaseFieldName%>;
<%
}
I was hoping that the variables generated by my template would match the same types as the properties in the generated entity classes. For the most part they do. But mine won't generate nullable types.
For example: LLBLGen generated a ParcelEntity class with this property:
public virtual Nullable<System.DateTime> HistoricalDate
But my template generates a variable for that same field without the Nullable<>:
public System.DateTime _historicalDate
How can I write my template to generate the types the same way as the LLBLGen templates for generating the Entity classes?
Joined: 17-Aug-2003
GeneratorUtils.GetDotNetTypeAsString(representedType, generator, nullablePattern, field.IsOptional);
where representedType is: field.FieldType.RepresentedType;, generator is the IGenerator instance, nullablePattern is e.g. "Nullable<{0}>" and field is the IFieldElementCore instance. GeneratorUtils is a class of the generator system of the designer and available to you in a template.
See for an example the Entity Framework Core templates, which use a function in the generalTemplateUtils.lpt template of entity framework (available in the shared templates of entity framework), as it generates poco classes with .net types in the format you want.
Joined: 15-Nov-2005
Thanks. That worked.
I have some related follow up questions.
I have some fields that are nullable in the database for a table that is used as a target for a hierarchy of Entity classes. For example, I have a Document table that is used as the target for _DocumentEntity _(the base class) and its derived classes: REDocumentEntity, UCCDocumentEntity, etc.
Some of the fields in the _Document _table are only applicable to REDocumentEntity, others are only applicable to UCCDocumentEntity, etc. To do this _Document _class hierarchy, I had to make those fields nullable in the database. For example, the _Document _table has a _TransferFeeDue _field that only applies to REDocument, so I had to make that field nullable in the database because a user adding a _UCCDOcument _would never have a value for it.
However, when setting up the code generation settings for _REDocumentEntity _, I set GenerateAsNullable for the _TransferFeeDue _field to false.
When making my custom template, your suggested change was to call GeneratorUtils.GetDotNetTypeAsString() passing in field.IsOptional for the _wrapInNullableType _ parameter. Apparently, that doesn't know if the _GenerateAsNullable _ setting is false.
So I found some code from a former programmer at our company that checked if a field is generated as nullable. So I used that in conjunction with your suggestion. Here is my new code for generating a field in my template:
<%
IGenerator generator = (IGenerator)_executingGenerator;
foreach(var field in currentEntity.Fields)
{
string generatedFieldName = "_" + GeneratorUtils.CamelCaseString(field.Name);
bool generateAsNullable = field.OutputSettingValues.GetRealBoolSettingValue("GenerateAsNullableType", generator.ProjectDefinition);
bool wrapInNullableType = field.IsOptional && generateAsNullable;
string typeString = GeneratorUtils.GetDotNetTypeAsString(field.FieldType.RepresentedType, generator, nullablePattern, wrapInNullableType);
%>
private <%= typeString%> <%= generatedFieldName%>;
<%
}
%>
My question is, how did he know to use "GenerateAsNullableType" as the first parameter for the GetRealBoolSettingValue() method. Is there documentation that indicates what the possible values for this parameter are?
A second question: There are several places in my template where I needed to get this type string. So I ended up repeating that type string code above in all the places I needed it. Is there a way I can put that type string logic in a function and then simply call that function instead?
Joined: 17-Aug-2003
clint wrote:
Thanks. That worked.
I have some related follow up questions.
I have some fields that are nullable in the database for a table that is used as a target for a hierarchy of Entity classes. For example, I have a Document table that is used as the target for _DocumentEntity _(the base class) and its derived classes: REDocumentEntity, UCCDocumentEntity, etc.
Some of the fields in the _Document _table are only applicable to REDocumentEntity, others are only applicable to UCCDocumentEntity, etc. To do this _Document _class hierarchy, I had to make those fields nullable in the database. For example, the _Document _table has a _TransferFeeDue _field that only applies to REDocument, so I had to make that field nullable in the database because a user adding a _UCCDOcument _would never have a value for it.
However, when setting up the code generation settings for _REDocumentEntity _, I set GenerateAsNullable for the _TransferFeeDue _field to false.
When making my custom template, your suggested change was to call GeneratorUtils.GetDotNetTypeAsString() passing in field.IsOptional for the _wrapInNullableType _ parameter. Apparently, that doesn't know if the _GenerateAsNullable _ setting is false.
So I found some code from a former programmer at our company that checked if a field is generated as nullable. So I used that in conjunction with your suggestion. Here is my new code for generating a field in my template:
<% IGenerator generator = (IGenerator)_executingGenerator; foreach(var field in currentEntity.Fields) { string generatedFieldName = "_" + GeneratorUtils.CamelCaseString(field.Name); bool generateAsNullable = field.OutputSettingValues.GetRealBoolSettingValue("GenerateAsNullableType", generator.ProjectDefinition); bool wrapInNullableType = field.IsOptional && generateAsNullable; string typeString = GeneratorUtils.GetDotNetTypeAsString(field.FieldType.RepresentedType, generator, nullablePattern, wrapInNullableType); %> private <%= typeString%> <%= generatedFieldName%>; <% } %>
My question is, how did he know to use "GenerateAsNullableType" as the first parameter for the GetRealBoolSettingValue() method. Is there documentation that indicates what the possible values for this parameter are?
The value passed in is the setting name. See: https://www.llblgen.com/Documentation/5.6/SDK/definingcustomsettings.htm#consuming-settings
These setting names are defined in the frameworksettings file, which are in the folder <installation folder>\Frameworks. For our framework that's SD.Frameworks.LLBLGenPro.frameworksettings. If you open that in notepad (or drag it onto the designer) you see at line 72, the setting definition. the name is then available at the element it's defined for (which can be multiple elements btw). As settings can be sourced from a default, if you call GetReal*SettingValue() it will obtain the actual value for you, either the overridden value on the element or if it's not changed, the default value.
A second question: There are several places in my template where I needed to get this type string. So I ended up repeating that type string code above in all the places I needed it. Is there a way I can put that type string logic in a function and then simply call that function instead?
Yes, you can define a separate template file (using .lpt that is) and bind it to an ID and call any method in that template. Say you have a template 'MyUtilFunctions.lpt' and you bind it to the templateID MyUtilFunctions. You can then call a method GenerateTypeString() like:
var s = MyUtilFunctions.GenerateTypeString();
in your template. See for an example in the llblgen pro runtime framework templatebindings in template bindings viewer 'SD.TemplateBindings.SharedTemplates', where we defined SD_GeneralUtils as templateID. All methods have to be static and you have to define them inside <~ ~> blocks. As it's a static, no-state class at runtime, you have to pass in an IGenerator or project instance (or other object you need) to the function, as they can't access anything for themselves.
As the templateid isn't used in a task, it won't produce any output