Skip to content

Commit fcce943

Browse files
nikitamKirillKurdyukov
authored andcommitted
fix bug #531
1 parent fd8a26a commit fcce943

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed
Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
1+
using System;
2+
using System.Data;
13
using System.Diagnostics.CodeAnalysis;
4+
using EntityFrameworkCore.Ydb.Storage.Internal.Mapping;
25
using Microsoft.EntityFrameworkCore.Query;
36
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
47
using Microsoft.EntityFrameworkCore.Storage;
5-
68
namespace EntityFrameworkCore.Ydb.Query.Internal;
79

810
public class YdbSqlExpressionFactory(SqlExpressionFactoryDependencies dependencies) : SqlExpressionFactory(dependencies)
911
{
1012
[return: NotNullIfNotNull("sqlExpression")]
1113
public override SqlExpression? ApplyTypeMapping(SqlExpression? sqlExpression, RelationalTypeMapping? typeMapping) =>
1214
base.ApplyTypeMapping(sqlExpression, typeMapping);
15+
16+
public override SqlExpression Coalesce(SqlExpression left, SqlExpression right,
17+
RelationalTypeMapping? typeMapping = null)
18+
{
19+
// For .Sum(x => x.Decimal) EF generates coalesce(sum(x.Decimal), 0.0)) because SUM must have value
20+
var funcExpression = left as SqlFunctionExpression;
21+
var constExpression = right as SqlConstantExpression;
22+
23+
if (funcExpression != null && constExpression != null && constExpression.TypeMapping != null
24+
&&
25+
funcExpression.Name.Equals("SUM", StringComparison.OrdinalIgnoreCase)
26+
&&
27+
constExpression.TypeMapping.DbType == DbType.Decimal
28+
&&
29+
constExpression.Value != null)
30+
{
31+
var correctRight = new SqlConstantExpression(constExpression.Value,
32+
YdbDecimalTypeMapping.WithMaxPrecision); // in the feature change static max precision/scale to
33+
// to dynamically created correct precision/scale
34+
// it depends on db scheme and can not correctly define only in code
35+
36+
return base.Coalesce(left, correctRight, typeMapping);
37+
}
38+
39+
return base.Coalesce(left, right, typeMapping);
40+
}
1341
}

src/EFCore.Ydb/src/Storage/Internal/Mapping/YdbDecimalTypeMapping.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,32 @@ public class YdbDecimalTypeMapping : DecimalTypeMapping
77
{
88
private const byte DefaultPrecision = 22;
99
private const byte DefaultScale = 9;
10+
11+
private const byte MaxPrecision = 35;
1012

1113
public new static YdbDecimalTypeMapping Default => new();
1214

15+
static YdbDecimalTypeMapping()
16+
{
17+
WithMaxPrecision = GetWithMaxPrecision();
18+
}
19+
20+
public static YdbDecimalTypeMapping WithMaxPrecision { get; }
21+
22+
private static YdbDecimalTypeMapping GetWithMaxPrecision()
23+
{
24+
var result = new YdbDecimalTypeMapping(new RelationalTypeMappingParameters(
25+
new CoreTypeMappingParameters(
26+
typeof(decimal)),
27+
storeType: "Decimal",
28+
dbType: System.Data.DbType.Decimal,
29+
precision: MaxPrecision,
30+
scale: DefaultScale)
31+
);
32+
33+
return result;
34+
}
35+
1336
public YdbDecimalTypeMapping() : this(
1437
new RelationalTypeMappingParameters(
1538
new CoreTypeMappingParameters(typeof(decimal)),
@@ -41,4 +64,9 @@ protected override void ConfigureParameter(DbParameter parameter)
4164
if (Scale is { } s)
4265
parameter.Scale = (byte)s;
4366
}
67+
68+
protected override string GenerateNonNullSqlLiteral(object value)
69+
{
70+
return $"Decimal('{base.GenerateNonNullSqlLiteral(value)}', {this.Precision ?? MaxPrecision}, {this.Scale ?? DefaultScale})";
71+
}
4472
}

0 commit comments

Comments
 (0)