Cómo configurar la precisión decimal en OData

Estoy tratando de redondear la propiedad decimal usando escala, pero no está funcionando

public class Student 
{
    public Guid Id { get; set; }
    public decimal Decimal { get; set; } = 0.000000m;
}

builder.EntitySet("Student");

var student = builder.EntityType();
student.Property(s => s.Decimal).Scale = 2;

Solicitud: https://localhost:44383/OData/Student

Resultado:

{
    "@odata.context": "https://localhost:44383/OData/$metadata#Student",
    "value": [
        {
            "Decimal": 0.000000,
            "Id": "efb93e81-2729-40e2-bd0b-44dc338217f9"
        }
    ]
}

Estoy esperando que el resultado sea

{
    "@odata.context": "https://localhost:44383/OData/$metadata#Student",
    "value": [
        {
            "Decimal": 0.00,
            "Id": "efb93e81-2729-40e2-bd0b-44dc338217f9"
        }
    ]
}

¿Cómo puedo arreglarlo?

EDIT:

Añadiendo Precision Tampoco ayudó:

 builder.EntityType().Property(s => s.Decimal).Precision = 2;

Pregunta hecha hace 3 años, 4 meses, 28 días - Por debugdynamo


3 Respuestas:

  • Parece que es cuestión de código fuente: https://github.com/OData/WebApi/issues/2384. Workarround:

        public static decimal CalculateDecimalPrecision(decimal value, int precision)
        {
            if (ShouldCalculatePrecision(value, precision, out bool shouldRound))
            {
                if (shouldRound)
                {
                    value = Math.Round(value, precision);
                }
                else
                {
                    var calculatedPrecision = decimal.Divide(1, Convert.ToDecimal(Math.Pow(10, precision)));
                    var zeroAfterPoint = calculatedPrecision - calculatedPrecision;
                    value += zeroAfterPoint;
                }
            }
            return value;
        }
    
    public class CustomODataPrimitiveSerializer : ODataPrimitiveSerializer
    {
        /// 
        /// Rewriting decimal value
        /// 
        public override ODataPrimitiveValue CreateODataPrimitiveValue(object graph, IEdmPrimitiveTypeReference primitiveType, ODataSerializerContext writeContext)
        {
            if (graph is decimal decimalValue && primitiveType is EdmDecimalTypeReference decimalTypeReference && decimalTypeReference.Scale != null)
            {
                graph = CalculateDecimalPrecision(decimalValue, decimalTypeReference.Scale.Value);
            }
            return base.CreateODataPrimitiveValue(graph, primitiveType, writeContext);
        }
    }
    

    Respondida el Dec 18, 2020 a las 04:01 - por compilerczar

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás enfrentando es que estás intentando definir la precisión y escala de una propiedad decimal en tu modelo de datos, pero la configuración de precisión y escala en OData no afecta la serialización de los valores decimales en la respuesta. La precisión y escala en OData están relacionadas con la definición de los tipos de datos en el modelo de datos, pero no influyen en la representación de los datos cuando son serializados.

    Por lo tanto, en el ejemplo que proporcionaste, la propiedad Decimal del objeto Student tiene una precisión predeterminada de 6 dígitos y una escala de 6 dígitos decimales, ya que estás inicializándola con 0.000000m.

    Para lograr el resultado que esperas en la serialización de la respuesta en formato OData, tendrás que manipular y formatear el valor de la propiedad Decimal antes de enviar la respuesta. Una forma de hacerlo es creando un ViewModel específico para esta operación.

    Aquí te dejo un ejemplo de cómo podrías implementar un ViewModel y un controlador para modificar la representación de la propiedad decimal en la respuesta:

    • Crea un ViewModel para representar la respuesta con el formato deseado:
    csharp
    public class StudentViewModel
    {
        public Guid Id { get; set; }
        public string DecimalRounded { get; set; }
    }
    
    • En tu controlador, convierte la lista de estudiantes al formato del ViewModel antes de enviar la respuesta:
    csharp
    [HttpGet]
    [EnableQuery]
    public IQueryable GetStudents()
    {
        List students = / Obtener la lista de estudiantes de tu repositorio de datos /;
        var studentViewModels = students.Select(s => new StudentViewModel
        {
            Id = s.Id,
            DecimalRounded = s.Decimal.ToString("0.00")  // Formatear el valor de Decimal con 2 decimales
        });
    
        return studentViewModels.AsQueryable();
    }
    

    Con esto, al realizar la solicitud a tu servicio OData, obtendrás la respuesta con la propiedad DecimalRounded con dos decimales, tal como lo esperas en el resultado. Recuerda ajustar el código según tu estructura y flujo de datos en tu aplicación.

    Respondida el Dec 19, 2020 a las 04:04 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Para configurar la precisión decimal en OData, debes utilizar el atributo Precision y Scale en la clase de entidad. El atributo Precision especifica el número total de dígitos en el valor decimal, mientras que el atributo Scale especifica el número de dígitos después del punto decimal.

    En tu caso, el código correcto sería:

    
    builder.EntityType().Property(s => s.Decimal).HasPrecision(4, 2);
    

    Esto establecerá la precisión del valor decimal en 4 dígitos, con 2 dígitos después del punto decimal.

    Ten en cuenta que también debes asegurarte de que la columna de la base de datos que almacena el valor decimal tenga una precisión y escala adecuadas. Si la columna de la base de datos tiene una precisión o escala menor que la especificada en el modelo de entidad, el valor se truncará o redondeará según corresponda.

    Respondida el Dec 19, 2020 a las 04:10 - por Gemini

    Votos positivos: 0 | Votos negativos: 0