Decimal loosing scale.

Posts   
 
    
Ole
User
Posts: 18
Joined: 17-May-2018
# Posted on: 23-Aug-2018 16:49:31   

Version (5.3.1)

I have an entity field "Lemac" specified as Type decimal , Precision 38, Scale 38 . with an Oracle db

In my generated source code () this is translated to:

/// <summary> The Lemac property of the Entity Actypes<br/><br/></summary> /// <remarks>Mapped on table field: "EL_ACTYPES"."LEMAC"<br/> /// Table field type characteristics (type, precision, scale, length): Double, 38, 38, 0<br/> /// Table field behavior characteristics (is nullable, is PK, is identity): false, false, false</remarks> public virtual System.Decimal Lemac { get { return (System.Decimal)GetValue((int)ActypesFieldIndex.Lemac, true); } set { SetValue((int)ActypesFieldIndex.Lemac, value); } }

Then I added an additional DB MSSQL to the project.

now my generated source code () this is translated to:

/// <summary> The Lemac property of the Entity Actypes<br/><br/></summary> /// <remarks>Mapped on table field: "Actypes"."Lemac"<br/> /// Table field type characteristics (type, precision, scale, length): Float, 38, 0, 0<br/> /// Table field behavior characteristics (is nullable, is PK, is identity): false, false, false</remarks> public virtual System.Decimal Lemac { get { return (System.Decimal)GetValue((int)ActypesFieldIndex.Lemac, true); } set { SetValue((int)ActypesFieldIndex.Lemac, value); } }

But now when I set the lemac value,it looses values to the right of decimal aka 18.44 becomes 18 etc this happens for all decimal values when using the OracleDB.

Attachments
Filename File size Added on Approval
lemacdebug.PNG 71,365 23-Aug-2018 17:44.59 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 23-Aug-2018 22:22:51   

Why do you have precision and scale with the same value (In Oracle)? Are you sure about that?

If you want to have values to the left if the decimal point, preceision should be greater than scale.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 24-Aug-2018 09:44:56   

The scale is likely reset to 0 in teh entity field mapping when you added the sqlserver schema. Did you add it through database first (so retrieved the meta-data from the DB) or through model first (so generated the sqlserver schema from the model).

The former will sync the model with the sqlserver schema which has differences with the oracle schema in this case. If you used database first for this schema, you have to make sure the schemas are the same, so that the sqlserver table field has a scale of 38 or at least a scale that can take the fraction you want.

Keep in mind that the .net type 'decimal' doesn't have settings for scale/precision and can contain a precision of 28 max.

Frans Bouma | Lead developer LLBLGen Pro
Ole
User
Posts: 18
Joined: 17-May-2018
# Posted on: 24-Aug-2018 11:20:28   

The field mappings are as follow:

SQL:

.Net type: System.double . Precision: 38 Scale:0 <-- is this the problem ?

DB Type: float

Type converter code for sql.


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Flyware.TypeConverters
{
    /// <summary>
    /// Double numeric converter
    /// </summary>
    public class DoubleNumericConverter : TypeConverter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DoubleNumericConverter"/> class.
        /// </summary>
        public DoubleNumericConverter()
        {
        }

        /// <summary>
        /// Double numeric converter
        /// </summary>
        /// <param name="context">ITypeDescriptorContext</param>
        /// <param name="sourceType">Type of source object</param>
        /// <returns>true if source type is an numberic type</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {       
            switch(sourceType.FullName)
            {
                case "System.Double":
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Converts System values to bool
        /// </summary>
        /// <param name="context">TypeDescriptorContext</param>
        /// <param name="destinationType">Type of destination</param>
        /// <returns>true if destination type is numberic</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            switch (destinationType.FullName)
            {
                case "System.Double":
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Converts values to double values
        /// </summary>
        /// <param name="context">ITypeDescriptorContext</param>
        /// <param name="culture">Language culture</param>
        /// <param name="value">Numeric value to convert from</param>
        /// <returns>Double value from numeric value</returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            try
            {
                return Convert.ToDecimal(value);
            }
            catch (Exception ex)
            {
                throw new NotSupportedException("Conversion from a value of type '" + value.GetType().ToString() + "' to System.Double isn't supported", ex);
            }
        }

        /// <summary>
        /// Converts System.Double values to double values
        /// </summary>
        /// <param name="context">ITypeDescriptorContext</param>
        /// <param name="culture">Language culture</param>
        /// <param name="value">Numeric value to convert from</param>
        /// <param name="destinationType">Numeric destination Type</param>
        /// <returns>Numeric value from double value</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            switch (destinationType.FullName)
            {
                case "System.Double":
                    return Convert.ToDouble(value);
            }
            throw new NotSupportedException(string.Format("Conversion from a value of type '{0}' isn't supported", destinationType.FullName));
        }

        /// <summary>
        /// Creates instance of decimal value
        /// </summary>
        /// <param name="context">ITypeDescriptorContext</param>
        /// <param name="propertyValues">PropertyValues to use.</param>
        /// <returns></returns>
        public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
        {
            return new Decimal(0);
        }
    }
}


Oracle:

.Net type: System.Decimal. Precision: 38 Scale:38

DB Type: float

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 24-Aug-2018 13:35:24   

Ole wrote:

The field mappings are as follow:

SQL:

.Net type: System.double . Precision: 38 Scale:0 <-- is this the problem ?

This is the cause of you losing the fraction.

However, the problem is really with the fact the DB Float on oracle isn't a double in your model, while it should.

Are you using MSOracle perhaps? (which maps everything as decimal) ? If so, please consider moving to ODP.NET.

Frans Bouma | Lead developer LLBLGen Pro
Ole
User
Posts: 18
Joined: 17-May-2018
# Posted on: 24-Aug-2018 15:03:12   

Yes I am using MS Oracle.

However I am a bit reluactant to change it to odp.net, since it will affect a lot of code upsteam.

Must the target element details be of the same type for all databases ?.

How can I change Target element details to change the scale ?.

Why? when generating the code is it picking up code that is DBSpecific(sql target element details) when I am referencing the OracleDBSpecific code ?.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 25-Aug-2018 09:30:44   

Ole wrote:

Yes I am using MS Oracle.

However I am a bit reluactant to change it to odp.net, since it will affect a lot of code upsteam.

That's understandable. Thing is, MS has deprecated MS Oracle and you won't get any new features in that provider. E.g. ODP.NET has a managed only library now and within a month .net core support. We added MS Oracle back in the days because ODP.NET was really shit, but nowadays it works OK.

Must the target element details be of the same type for all databases ?. How can I change Target element details to change the scale ?.

the target doesn't need to be the same. The 'float' type results in a double on sqlserver and a decimal on ms oracle (as everything is mapped as a decimal in that provider). When you created the project with Oracle, the scale was set to 38. When you added the sql server part, you again synced the model with a database. It can sync with only 1 at a time of course, so if they are different the last one dictates how the model looks like. The problem here is that the 'float' type results in a double, which has no scale (as it's built into the type) and you convert that to a decimal using a type converter so the scale isn't set.

You basically have to choose which database type is leading your model. If that's oracle, then you should treat SQL Server as being used model first. if it's sqlserver, then you should treat oracle as being used model first. Say you select Oracle. Open the Sync tab and next to 'SQL Server (SqlClient)' you see 'Database' in the sync source column. Change that to 'Model' if you don't have views/storted procs, otherwise set it to 'mixed'. Make sure the schema(s) also have 'mixed' set.

This way you can alter the model fields' 'scale' properties. To do so, I think a refresh with the oracle database is enough. First make sure the project setting: Entity Model -> Database first development -> 'Length precision scale follow dblength precision scale', is checked. Then in the Sync tab, at the bottom you see two tasks, one for sql server and one for oracle, only check the checkbox for the oracle task and click 'Perform tasks'. This will sync the model again with the oracle schema specifics and should set the scale back to 38.

Frans Bouma | Lead developer LLBLGen Pro