How to get type of an Entity field. Check if nullable?

Posts   
 
    
clint
User
Posts: 145
Joined: 15-Nov-2005
# Posted on: 25-Jan-2020 03:58:54   

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?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39568
Joined: 17-Aug-2003
# Posted on: 25-Jan-2020 07:37:05   

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.

Frans Bouma | Lead developer LLBLGen Pro
clint
User
Posts: 145
Joined: 15-Nov-2005
# Posted on: 27-Jan-2020 01:28:33   

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?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39568
Joined: 17-Aug-2003
# Posted on: 27-Jan-2020 10:25:29   

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 simple_smile

Frans Bouma | Lead developer LLBLGen Pro
clint
User
Posts: 145
Joined: 15-Nov-2005
# Posted on: 28-Jan-2020 17:08:03   

Thanks!