diff --git a/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs b/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs index 5bdf3af9087..dc3572b09a7 100644 --- a/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs +++ b/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs @@ -918,7 +918,7 @@ FROM [sys].[views] v { try { - return Convert.ChangeType(defaultValueSql, type); + return Convert.ChangeType(defaultValueSql, type, CultureInfo.InvariantCulture); } catch { diff --git a/src/EFCore.Sqlite.Core/Scaffolding/Internal/SqliteDatabaseModelFactory.cs b/src/EFCore.Sqlite.Core/Scaffolding/Internal/SqliteDatabaseModelFactory.cs index b67f8571b42..15289bf3c9c 100644 --- a/src/EFCore.Sqlite.Core/Scaffolding/Internal/SqliteDatabaseModelFactory.cs +++ b/src/EFCore.Sqlite.Core/Scaffolding/Internal/SqliteDatabaseModelFactory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Data; +using System.Globalization; using System.Text; using System.Text.RegularExpressions; using Microsoft.Data.Sqlite; @@ -429,7 +430,7 @@ private void ParseClrDefaults(DatabaseTable table) { try { - column.DefaultValue = Convert.ChangeType(defaultValueSql, type); + column.DefaultValue = Convert.ChangeType(defaultValueSql, type, CultureInfo.InvariantCulture); } catch { @@ -471,7 +472,7 @@ private void ParseClrDefaults(DatabaseTable table) column.DefaultValue = dateTimeOffset; } else if (type == typeof(decimal) - && decimal.TryParse(defaultValueSql, out var decimalValue)) + && decimal.TryParse(defaultValueSql, CultureInfo.InvariantCulture, out var decimalValue)) { column.DefaultValue = decimalValue; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/SqlServerDatabaseModelFactoryTest.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/SqlServerDatabaseModelFactoryTest.cs index 7038c31e278..531ee80a99b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/SqlServerDatabaseModelFactoryTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/SqlServerDatabaseModelFactoryTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Globalization; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using Microsoft.EntityFrameworkCore.SqlServer.Diagnostics.Internal; @@ -3939,6 +3940,7 @@ CREATE TABLE MyTable ( B decimal DEFAULT (0.0), C decimal DEFAULT (0), D decimal DEFAULT ((CONVERT ( ""decimal"", ( (1.1234) ) ))), + E decimal DEFAULT ((10.0)), );", Enumerable.Empty(), Enumerable.Empty(), @@ -3962,11 +3964,70 @@ D decimal DEFAULT ((CONVERT ( ""decimal"", ( (1.1234) ) ))), Assert.Equal("(CONVERT([decimal],(1.1234)))", column.DefaultValueSql); Assert.Equal((decimal)1.1234, column.DefaultValue); + column = columns.Single(c => c.Name == "E"); + Assert.Equal("((10.0))", column.DefaultValueSql); + Assert.Equal((decimal)10, column.DefaultValue); + var model = scaffoldingFactory.Create(dbModel, new ModelReverseEngineerOptions()); Assert.Equal(1, model.GetEntityTypes().Count()); }, "DROP TABLE MyTable;"); + [ConditionalFact] + public void Simple_decimal_literals_are_parsed_for_HasDefaultValue_with_Danish_locale() + { + var currentCulture = CultureInfo.CurrentCulture; + + try + { + CultureInfo.CurrentCulture = new CultureInfo("da-DK"); + Test( + @" +CREATE TABLE MyTable ( + Id int, + A decimal DEFAULT -1.1111, + B decimal DEFAULT (0.0), + C decimal DEFAULT (0), + D decimal DEFAULT ((CONVERT ( ""decimal"", ( (1.1234) ) ))), + E decimal DEFAULT ((10.0)), +);", + Enumerable.Empty(), + Enumerable.Empty(), + (dbModel, scaffoldingFactory) => + { + var columns = dbModel.Tables.Single().Columns; + + var column = columns.Single(c => c.Name == "A"); + Assert.Equal("((-1.1111))", column.DefaultValueSql); + Assert.Equal((decimal)-1.1111, column.DefaultValue); + + column = columns.Single(c => c.Name == "B"); + Assert.Equal("((0.0))", column.DefaultValueSql); + Assert.Equal((decimal)0, column.DefaultValue); + + column = columns.Single(c => c.Name == "C"); + Assert.Equal("((0))", column.DefaultValueSql); + Assert.Equal((decimal)0, column.DefaultValue); + + column = columns.Single(c => c.Name == "D"); + Assert.Equal("(CONVERT([decimal],(1.1234)))", column.DefaultValueSql); + Assert.Equal((decimal)1.1234, column.DefaultValue); + + column = columns.Single(c => c.Name == "E"); + Assert.Equal("((10.0))", column.DefaultValueSql); + Assert.Equal((decimal)10, column.DefaultValue); + + var model = scaffoldingFactory.Create(dbModel, new ModelReverseEngineerOptions()); + Assert.Equal(1, model.GetEntityTypes().Count()); + }, + "DROP TABLE MyTable;"); + } + finally + { + CultureInfo.CurrentCulture = currentCulture; + } + } + [ConditionalFact] public void Simple_bool_literals_are_parsed_for_HasDefaultValue() => Test( diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/SqliteDatabaseModelFactoryTest.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/SqliteDatabaseModelFactoryTest.cs index 23152fbf7cb..23d23c12294 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/SqliteDatabaseModelFactoryTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/SqliteDatabaseModelFactoryTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Globalization; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; @@ -850,9 +851,10 @@ CREATE TABLE MyTable ( Id int, A decimal DEFAULT '-1.1111', B decimal DEFAULT ('0.0'), - C decimal DEFAULT ('0')); + C decimal DEFAULT ('0'), + D decimal DEFAULT ('10.0')); -INSERT INTO MyTable VALUES (1, '1.1', '1.2', '1.3');", +INSERT INTO MyTable VALUES (1, '1.1', '1.2', '1.3', '1.4');", Enumerable.Empty(), Enumerable.Empty(), dbModel => @@ -870,9 +872,62 @@ B decimal DEFAULT ('0.0'), column = columns.Single(c => c.Name == "C"); Assert.Equal("'0'", column.DefaultValueSql); Assert.Equal((decimal)0, column.DefaultValue); + + column = columns.Single(c => c.Name == "D"); + Assert.Equal("'10.0'", column.DefaultValueSql); + Assert.Equal((decimal)10, column.DefaultValue); }, "DROP TABLE MyTable;"); + [ConditionalFact] + public void Simple_decimal_literals_are_parsed_for_HasDefaultValue_with_Danish_locale() + { + var culture = CultureInfo.CurrentCulture; + + try + { + CultureInfo.CurrentCulture = new CultureInfo("da-DK"); + + Test( + @" +CREATE TABLE MyTable ( + Id int, + A decimal DEFAULT '-1.1111', + B decimal DEFAULT ('0.0'), + C decimal DEFAULT ('0'), + D decimal DEFAULT ('10.0')); + +INSERT INTO MyTable VALUES (1, '1.1', '1.2', '1.3', '1.4');", + Enumerable.Empty(), + Enumerable.Empty(), + dbModel => + { + var columns = dbModel.Tables.Single().Columns; + + var column = columns.Single(c => c.Name == "A"); + Assert.Equal("'-1.1111'", column.DefaultValueSql); + Assert.Equal((decimal)-1.1111, column.DefaultValue); + + column = columns.Single(c => c.Name == "B"); + Assert.Equal("'0.0'", column.DefaultValueSql); + Assert.Equal((decimal)0, column.DefaultValue); + + column = columns.Single(c => c.Name == "C"); + Assert.Equal("'0'", column.DefaultValueSql); + Assert.Equal((decimal)0, column.DefaultValue); + + column = columns.Single(c => c.Name == "D"); + Assert.Equal("'10.0'", column.DefaultValueSql); + Assert.Equal((decimal)10, column.DefaultValue); + }, + "DROP TABLE MyTable;"); + } + finally + { + CultureInfo.CurrentCulture = culture; + } + } + [ConditionalFact] public void Simple_bool_literals_are_parsed_for_HasDefaultValue() => Test(