BooleanNumeric TypeConverter not showing

Posts   
 
    
jovball
User
Posts: 435
Joined: 23-Jan-2005
# Posted on: 04-Jul-2023 17:26:20   

I have a database field that is an Int16 in the database model. It's an Oracle ODP.NET Number(1,0) data type. It should be mapped to a .NET Boolean on the entity model side. I have added the BooleanNumericConverter in the project settings but the designer still shows that I don't have any available type converters. Do I need a custom type converter for this?

I have attached screenshots showing the mappings and the project setttings.

Attachments
Filename File size Added on Approval
TypeConverter.zip 35,247 04-Jul-2023 17:26.33 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 05-Jul-2023 06:01:11   

That's because the .NET type is set to Int16, so it matches the DBType.

TypeConverters only show up when there is a mismatch between the .NET Type and the DBType, and there is a TypeConverter set in the project settings that can correct this specific type mismatch.

So please go to the Fields tab and change the field .NET Type from Int16 to Boolean.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39615
Joined: 17-Aug-2003
# Posted on: 05-Jul-2023 09:38:58   

Also to have this more automated, define a filter on the type converter in project settings so it matches with NUMBER (1)

Frans Bouma | Lead developer LLBLGen Pro
jovball
User
Posts: 435
Joined: 23-Jan-2005
# Posted on: 05-Jul-2023 13:48:24   

It looks like when I define the filter and then change the field type, the converter is being applied to the field behind the scenes. I have to close and reopen the entity mapping first but then the error goes away. The typeconverter column is blank in the mappings.

I'm attaching screenshots for each of these steps.

  • In project settings, add the BooleanNumericConverter and set a filter on Precision for a value of 1.
  • On the entity, Edit Mappings (the error shows up here)
  • Go to fields tab and change the .NET type to Boolean
  • Switch back to the mappings tab, the error still shows and the converter is not available.
  • Close the entity mapping and re-open it. The error is gone but the converter column is blank.

Is that what I should be expecting?

I have more than 300 of them and that's a lot of point and click work so my next task will be to use Element Search to find these invalid fields and change the data type. Element Search has become a very good friend in the last several weeks although I'm just starting to understand how much is in there.

Attachments
Filename File size Added on Approval
TypeConverter-v2.zip 154,990 05-Jul-2023 13:48.52 Approved
jovball
User
Posts: 435
Joined: 23-Jan-2005
# Posted on: 05-Jul-2023 20:55:09   

I'm working on the Element Search query to change the field types but I don't see how I can do it. All of the fields I need appear to be read only. What I wanted to do is below but RepresentedType is read only. Looking at IFieldType (https://www.llblgen.com/Documentation/5.10/ReferenceManuals/Designer/html/27DD23F6.htm), nothing there seems like it helps me either.

How can I change the field type in Element Search? I see Length, Precision, Scale but nothing for the type.

//change the field type to Boolean
//this doesn't work because it's read-only
entityField.FieldType.RepresentedType = Type.GetType("System.Boolean");

//same here
entityField.FieldType.FieldTypeForXml = "bool";
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39615
Joined: 17-Aug-2003
# Posted on: 06-Jul-2023 11:41:56   

FieldType is an object, which can either be a ValueTypeDefinition or a TypeShortcut. TypeShortcuts defined in the project are available through the Project object's TypeShortcuts property. This is a TypeShortcutList class which is derives from List<T>, and you can grab the TypeShortcut instances for a type from there (e.g. create a dictionary for easy lookup from that first to avoid looping it a lot). So to set a field's FieldType, grab the typeshortcut object from the TypeShortcuts list and assign it.

To have the designer auto-assign the type converter, it's best to first make sure the types of the fields you want to assign it to are set to the right type. Then define the filter in the TypeConversions in the project. If the setting 'Auto-assign type converters to field mappings' is checked (this is the default, but just in case, under Entity model -> General check it) it should auto-walk all mappings after that and assign the type converter. Because you're changing the field types after changing the filter, you have to do this manually in the GUI... disappointed

To do this in code, you can follow what the designer does too: it calls Project.UpdateEditedTypeConversionDefinitions(Dictionary<string, List<TypeConversionDefinition>> editedConversions) after you click 'Ok' on the settings dialog and you changed a typeconversion. This walks all mappings and tries to assign the type converter if the mapping matches the filter.

Frans Bouma | Lead developer LLBLGen Pro
jovball
User
Posts: 435
Joined: 23-Jan-2005
# Posted on: 07-Jul-2023 12:58:31   

Well, I have had this completely backwards in my head from the start and now I'm completely confused as to what I should be doing.

The database is a Number(1,0). The current T4 generated code from the EDMX is treating this as a short (Int16) so that is what I need to generate for now. The field mapping shows this as a short for the .NET type but then the target element type shows the .NET type as Boolean.

If I add relational model data directly from the database the field mapping creates a bool (and generates code for a bool).

<Field Name="Active" Type="bool" Precision="1" />

With my EDMX import, the field mapping is a short and creates a validation error so I can't generate any code unless I change it to a bool.

  <Field Name="Active" Type="short" />

My question is why LLBLGen is representing this as System.Boolean based on the database type when it actually IS a short? Logically, that is correct but it's not actually what the database is. Can I create a TypeConverter to handle this? I attempted to do this but my first attempts haven't worked (code below)

My only idea for now is to change all of the fields to bool and add an attribute for [ActualType("short")] so I could handle it at generation time and turn it back into a short. That's really ugly so I'd prefer a better solution.

TypeConverter attempt

public class Int16BooleanConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType.FullName == "System.Int16";
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType.FullName == "System.Boolean";
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return Convert.ToBoolean(value) == true ? 1 : 0;
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        return Convert.ToInt16(value) == 1;
    }

    public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
    {
        return (Int16)1;
    }
}
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39615
Joined: 17-Aug-2003
# Posted on: 10-Jul-2023 11:33:22   

NUMBER(1,0)is defined as a bool at the driver level, as you can see the field has as .net type in the mappings type boolean so no type converter is needed. The Oracle provider for EF Core provided by Oracle themselves use NUMBER(1) for boolean (https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3/odpnt/EFCoreDataTypeMapping.html#GUID-484E9D3A-8E42-417F-9591-F2E7305E3F6A) so we do that too. There's an implicit conversion between bool and number(1) built-in the Oracle provider for EF Core from Oracle so we utilize that.

Does your table field contain values 0-9 or just 0 or 1 as a boolean? If it's the latter, why not use the boolean as they're a boolean? If the former, then I understand your requirement and there's a small problem as the conversion is specified at the driver level. (OracleDBDriver.cs, ConvertDbTypeToNetTypeEFCore, line 547)

This isn't that big tho, you can change it but it requires you to use a custom built driver, which isn't ideal either.

Frans Bouma | Lead developer LLBLGen Pro
jovball
User
Posts: 435
Joined: 23-Jan-2005
# Posted on: 12-Jul-2023 12:15:21   

Got it, that makes sense now. I'll have to see how much of the consuming code needs to be changed to use the boolean. It's obviously the correct thing to do but we'll need to do some testing to understand the ramifications.