From f3fe3d2a17ef1f3f9c4f4843e363308cc3c99790 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Tue, 14 May 2024 23:51:45 -0400 Subject: [PATCH 01/54] GH3530: Add locale specific tests to check for invalid type conversions. --- .../NHSpecificTest/GH3530/Entities.cs | 17 ++++ .../NHSpecificTest/GH3530/Fixture.cs | 91 +++++++++++++++++++ .../NHSpecificTest/GH3530/Mappings.hbm.xml | 10 ++ 3 files changed, 118 insertions(+) create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs new file mode 100644 index 0000000000..503e9a3945 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHibernate.Test.NHSpecificTest.GH3530 +{ + public class LocaleEntity + { + public virtual Guid Id { get; set; } + public virtual int IntegerValue { get; set; } + public virtual DateTime DateTimeValue { get; set; } + public virtual double DoubleValue { get; set; } + public virtual decimal DecimalValue { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs new file mode 100644 index 0000000000..c9b16b1653 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -0,0 +1,91 @@ +using System; +using System.Globalization; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3530 +{ + [TestFixture] + public class Fixture : BugTestCase + { + private CultureInfo initialCulture; + + [OneTimeSetUp] + public void FixtureSetup() + { + initialCulture = CurrentCulture; + } + + [OneTimeTearDown] + public void FixtureTearDown() + { + CurrentCulture = initialCulture; + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [TestCaseSource(nameof(GetTestCases))] + public void TestLocales(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + double doubleValue = 12.3f; + int intValue = 4; + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = new LocaleEntity() + { + DateTimeValue = leapDay, + DoubleValue = doubleValue, + IntegerValue = intValue, + }; + + id = session.Save(entity); + tx.Commit(); + } + + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = session.Get(id); + + Assert.AreEqual(leapDay, entity.DateTimeValue); + Assert.AreEqual(intValue, entity.IntegerValue); + Assert.True(doubleValue - entity.DoubleValue < double.Epsilon); + } + } + + private CultureInfo CurrentCulture + { + get + { + return CultureInfo.CurrentCulture; + } + set + { + CultureInfo.CurrentCulture = value; + } + } + + public static object[][] GetTestCases() + { + return [ + [new CultureInfo("en-US"), new CultureInfo("de-DE")], + [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], + [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], + ]; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml new file mode 100644 index 0000000000..1882105089 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -0,0 +1,10 @@ + + + + + + + + + From 2c8adc1728b1f48c83e162cb21be21aeca760c6f Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 09:52:37 -0400 Subject: [PATCH 02/54] GH-3530: Change id type in preparation for manually creating the schema. --- src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs | 2 +- src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 503e9a3945..0fe3ac2b0b 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -8,7 +8,7 @@ namespace NHibernate.Test.NHSpecificTest.GH3530 { public class LocaleEntity { - public virtual Guid Id { get; set; } + public virtual int Id { get; set; } public virtual int IntegerValue { get; set; } public virtual DateTime DateTimeValue { get; set; } public virtual double DoubleValue { get; set; } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 1882105089..e5047f4fd5 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -2,9 +2,10 @@ - + + From 1a29463a5bd6c8bcec5705f0d91ea6124e87e18e Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 10:36:56 -0400 Subject: [PATCH 03/54] GH-3530: Attempt to manually create the schema using the current dialect. --- .../NHSpecificTest/GH3530/Fixture.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index c9b16b1653..1126ef09ee 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -1,5 +1,9 @@ using System; +using System.Data; using System.Globalization; +using System.Reflection; +using System.Text; +using NHibernate.SqlTypes; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.GH3530 @@ -32,6 +36,76 @@ protected override void OnTearDown() } } + protected override void CreateSchema() + { + var sb = new StringBuilder(); + var intType = Dialect.GetTypeName(SqlTypeFactory.Int32); + var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); + + var catalog = GetQuotedDefaultCatalog(); + var schema = GetQuotedDefaultSchema(); + var table = GetQualifiedName(catalog, schema, "LocaleEntity"); + + sb.Append($"{Dialect.CreateTableString} {table} ("); + sb.Append($"Id "); + + if (Dialect.HasDataTypeInIdentityColumn) + { + sb.Append($"{intType}"); + } + sb.Append($" {Dialect.GetIdentityColumnString(DbType.Int32)}"); + + // Generate columns + sb.Append($"IntegerValue {stringType}, "); + sb.Append($"DateTimeValue {stringType}, "); + sb.Append($"DoubleValue {stringType}, "); + sb.Append($"DecimalValue {stringType}"); + + // Add the primary key contraint for the identity column + if (Dialect.GenerateTablePrimaryKeyConstraintForIdentityColumn) + { + sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); + } + sb.Append(")"); + + using (var cn = Sfi.ConnectionProvider.GetConnection()) + { + try + { + using (var cmd = cn.CreateCommand()) + { + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); + } + } + finally + { + Sfi.ConnectionProvider.CloseConnection(cn); + } + } + } + + private string GetQuotedDefaultCatalog() + { + var t = cfg.GetType(); + var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); + + return (string)getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + } + + private string GetQuotedDefaultSchema() + { + var t = cfg.GetType(); + var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); + + return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + } + + private string GetQualifiedName(string catalog, string schema, string name) + { + return Dialect.Qualify(catalog, schema, name); + } + [TestCaseSource(nameof(GetTestCases))] public void TestLocales(CultureInfo from, CultureInfo to) { From af82e9648c2daf76cd38b8508ec0e43026da68e5 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 10:48:18 -0400 Subject: [PATCH 04/54] GH-3530: Add missing comma and space after Id field. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 1126ef09ee..865b87378a 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -53,7 +53,7 @@ protected override void CreateSchema() { sb.Append($"{intType}"); } - sb.Append($" {Dialect.GetIdentityColumnString(DbType.Int32)}"); + sb.Append($" {Dialect.GetIdentityColumnString(DbType.Int32)}, "); // Generate columns sb.Append($"IntegerValue {stringType}, "); From c62a7e834a3b9b310ff623f4b755855479410b8d Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 11:02:40 -0400 Subject: [PATCH 05/54] GH-3530: Use the same syntax as Table.SqlCreateString for the identity column. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 865b87378a..3f49747816 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -47,13 +47,13 @@ protected override void CreateSchema() var table = GetQualifiedName(catalog, schema, "LocaleEntity"); sb.Append($"{Dialect.CreateTableString} {table} ("); - sb.Append($"Id "); + sb.Append("Id "); if (Dialect.HasDataTypeInIdentityColumn) { sb.Append($"{intType}"); } - sb.Append($" {Dialect.GetIdentityColumnString(DbType.Int32)}, "); + sb.Append(" ").Append(Dialect.GetIdentityColumnString(DbType.Int32)).Append(", "); // Generate columns sb.Append($"IntegerValue {stringType}, "); From 13944924dcb823d1fc5f70c606197b53171752e5 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 11:12:15 -0400 Subject: [PATCH 06/54] GH-3530: Break up the tests by type so we can see which types fail where. --- .../NHSpecificTest/GH3530/Fixture.cs | 96 +++++++++++++++++-- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 3f49747816..9387ef8725 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -106,12 +106,10 @@ private string GetQualifiedName(string catalog, string schema, string name) return Dialect.Qualify(catalog, schema, name); } - [TestCaseSource(nameof(GetTestCases))] - public void TestLocales(CultureInfo from, CultureInfo to) + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDateTime(CultureInfo from, CultureInfo to) { DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - double doubleValue = 12.3f; - int intValue = 4; object id; CurrentCulture = from; @@ -120,9 +118,7 @@ public void TestLocales(CultureInfo from, CultureInfo to) { var entity = new LocaleEntity() { - DateTimeValue = leapDay, - DoubleValue = doubleValue, - IntegerValue = intValue, + DateTimeValue = leapDay }; id = session.Save(entity); @@ -136,11 +132,95 @@ public void TestLocales(CultureInfo from, CultureInfo to) var entity = session.Get(id); Assert.AreEqual(leapDay, entity.DateTimeValue); - Assert.AreEqual(intValue, entity.IntegerValue); + } + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDecimal(CultureInfo from, CultureInfo to) + { + decimal decimalValue = 12.3m; + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = new LocaleEntity() + { + DecimalValue = decimalValue + }; + + id = session.Save(entity); + tx.Commit(); + } + + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = session.Get(id); + + Assert.AreEqual(decimalValue, entity.DecimalValue); + } + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDouble(CultureInfo from, CultureInfo to) + { + double doubleValue = 12.3d; + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = new LocaleEntity() + { + DoubleValue = doubleValue + }; + + id = session.Save(entity); + tx.Commit(); + } + + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = session.Get(id); + Assert.True(doubleValue - entity.DoubleValue < double.Epsilon); } } + public void TestInteger(CultureInfo from, CultureInfo to) + { + int integerValue = 123; + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = new LocaleEntity() + { + IntegerValue = integerValue + }; + + id = session.Save(entity); + tx.Commit(); + } + + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = session.Get(id); + + Assert.AreEqual(integerValue, entity.IntegerValue); + } + } + private CultureInfo CurrentCulture { get From 72367b278e0a602e587a9244cc3fb6a72ab98aac Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 11:29:35 -0400 Subject: [PATCH 07/54] GH-3530: Fix incorrect test for Double types. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 9387ef8725..b5d53ded5f 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -189,7 +189,7 @@ public void TestDouble(CultureInfo from, CultureInfo to) { var entity = session.Get(id); - Assert.True(doubleValue - entity.DoubleValue < double.Epsilon); + Assert.True(Math.Abs(doubleValue - entity.DoubleValue) < double.Epsilon); } } From e66e1c6bba78bf066c930fb3dad4fad09031534a Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 11:45:01 -0400 Subject: [PATCH 08/54] GH-3530: Add a meaningful message when TestDouble fails. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index b5d53ded5f..d776731780 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -189,7 +189,7 @@ public void TestDouble(CultureInfo from, CultureInfo to) { var entity = session.Get(id); - Assert.True(Math.Abs(doubleValue - entity.DoubleValue) < double.Epsilon); + Assert.True(Math.Abs(doubleValue - entity.DoubleValue) < double.Epsilon, $"Expected: {doubleValue}\nBut was: {entity.DoubleValue}\n"); } } From a9b0910fb4ba9ab2f9ce8fcb26c1d63229d5a3c8 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 12:12:33 -0400 Subject: [PATCH 09/54] GH-3530: Attempt to switch to a guid Id as some databases do not support the identity generator. --- src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs | 2 +- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 6 +++--- src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 0fe3ac2b0b..503e9a3945 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -8,7 +8,7 @@ namespace NHibernate.Test.NHSpecificTest.GH3530 { public class LocaleEntity { - public virtual int Id { get; set; } + public virtual Guid Id { get; set; } public virtual int IntegerValue { get; set; } public virtual DateTime DateTimeValue { get; set; } public virtual double DoubleValue { get; set; } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index d776731780..1a40d65440 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -39,7 +39,7 @@ protected override void OnTearDown() protected override void CreateSchema() { var sb = new StringBuilder(); - var intType = Dialect.GetTypeName(SqlTypeFactory.Int32); + var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); var catalog = GetQuotedDefaultCatalog(); @@ -51,9 +51,9 @@ protected override void CreateSchema() if (Dialect.HasDataTypeInIdentityColumn) { - sb.Append($"{intType}"); + sb.Append($"{guidType}"); } - sb.Append(" ").Append(Dialect.GetIdentityColumnString(DbType.Int32)).Append(", "); + sb.Append(" ").Append(Dialect.GetIdentityColumnString(DbType.Guid)).Append(", "); // Generate columns sb.Append($"IntegerValue {stringType}, "); diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index e5047f4fd5..d5e70752cd 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -2,7 +2,7 @@ - + From 5282ab3c96849ad41c27bee733cdc3bbdb3a6892 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 12:30:09 -0400 Subject: [PATCH 10/54] GH-3530: Guid key's are not identity columns and are defined like all other columns. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 1a40d65440..38c36f957f 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -47,15 +47,9 @@ protected override void CreateSchema() var table = GetQualifiedName(catalog, schema, "LocaleEntity"); sb.Append($"{Dialect.CreateTableString} {table} ("); - sb.Append("Id "); - - if (Dialect.HasDataTypeInIdentityColumn) - { - sb.Append($"{guidType}"); - } - sb.Append(" ").Append(Dialect.GetIdentityColumnString(DbType.Guid)).Append(", "); // Generate columns + sb.Append($"Id {guidType}, "); sb.Append($"IntegerValue {stringType}, "); sb.Append($"DateTimeValue {stringType}, "); sb.Append($"DoubleValue {stringType}, "); From 11d645e47bd36c634d61ec1a6e090693fd56a9bb Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 12:35:07 -0400 Subject: [PATCH 11/54] GH-3530: Correctly add the primary key constraint for the Id column. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 38c36f957f..aa942f5390 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -56,10 +56,7 @@ protected override void CreateSchema() sb.Append($"DecimalValue {stringType}"); // Add the primary key contraint for the identity column - if (Dialect.GenerateTablePrimaryKeyConstraintForIdentityColumn) - { - sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); - } + sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); sb.Append(")"); using (var cn = Sfi.ConnectionProvider.GetConnection()) From aa7cd998132091dd106733ff937a77620fdfaa25 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 12:50:31 -0400 Subject: [PATCH 12/54] GH-3530: Allow all properties of the LocaleEntity to be nullable. --- src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 503e9a3945..1b0bd0aeec 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -9,9 +9,9 @@ namespace NHibernate.Test.NHSpecificTest.GH3530 public class LocaleEntity { public virtual Guid Id { get; set; } - public virtual int IntegerValue { get; set; } - public virtual DateTime DateTimeValue { get; set; } - public virtual double DoubleValue { get; set; } - public virtual decimal DecimalValue { get; set; } + public virtual int? IntegerValue { get; set; } + public virtual DateTime? DateTimeValue { get; set; } + public virtual double? DoubleValue { get; set; } + public virtual decimal? DecimalValue { get; set; } } } From 2666a4439eacccae7f092ce7201f7f405a6d723a Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 13:27:06 -0400 Subject: [PATCH 13/54] GH-3530: Separate the types into different tables to avoid failure on default values. --- .../NHSpecificTest/GH3530/Entities.cs | 18 ++- .../NHSpecificTest/GH3530/Fixture.cs | 112 ++++++------------ .../NHSpecificTest/GH3530/Mappings.hbm.xml | 19 ++- 3 files changed, 60 insertions(+), 89 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 1b0bd0aeec..52de3445d1 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -3,15 +3,23 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using NHibernate.SqlCommand; namespace NHibernate.Test.NHSpecificTest.GH3530 { - public class LocaleEntity + public abstract class Entity { public virtual Guid Id { get; set; } - public virtual int? IntegerValue { get; set; } - public virtual DateTime? DateTimeValue { get; set; } - public virtual double? DoubleValue { get; set; } - public virtual decimal? DecimalValue { get; set; } } + + public abstract class Entity:Entity where T : struct + { + public virtual T Value { get; set; } + } + + public class IntegerEntity : Entity { } + public class DateTimeEntity : Entity { } + + public class DoubleEntity : Entity { } + public class DecimalEntity : Entity { } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index aa942f5390..0651eeb534 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -37,6 +37,14 @@ protected override void OnTearDown() } protected override void CreateSchema() + { + CreateTable("Integer"); + CreateTable("DateTime"); + CreateTable("Double"); + CreateTable("Decimal"); + } + + private void CreateTable(string name) { var sb = new StringBuilder(); var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); @@ -44,16 +52,13 @@ protected override void CreateSchema() var catalog = GetQuotedDefaultCatalog(); var schema = GetQuotedDefaultSchema(); - var table = GetQualifiedName(catalog, schema, "LocaleEntity"); + var table = GetQualifiedName(catalog, schema, $"{name}Entity"); sb.Append($"{Dialect.CreateTableString} {table} ("); // Generate columns sb.Append($"Id {guidType}, "); - sb.Append($"IntegerValue {stringType}, "); - sb.Append($"DateTimeValue {stringType}, "); - sb.Append($"DoubleValue {stringType}, "); - sb.Append($"DecimalValue {stringType}"); + sb.Append($"Value {stringType}, "); // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); @@ -81,7 +86,7 @@ private string GetQuotedDefaultCatalog() var t = cfg.GetType(); var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); - return (string)getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); } private string GetQuotedDefaultSchema() @@ -97,19 +102,19 @@ private string GetQualifiedName(string catalog, string schema, string name) return Dialect.Qualify(catalog, schema, name); } - [Test, TestCaseSource(nameof(GetTestCases))] - public void TestDateTime(CultureInfo from, CultureInfo to) + private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue, Action assert) + where T : struct + where U : Entity, new() { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); object id; CurrentCulture = from; using (var session = OpenSession()) using (var tx = session.BeginTransaction()) { - var entity = new LocaleEntity() + var entity = new U() { - DateTimeValue = leapDay + Value = expectedValue }; id = session.Save(entity); @@ -120,96 +125,45 @@ public void TestDateTime(CultureInfo from, CultureInfo to) using (var session = OpenSession()) using (var tx = session.BeginTransaction()) { - var entity = session.Get(id); + var entity = session.Get(id); - Assert.AreEqual(leapDay, entity.DateTimeValue); + assert(expectedValue, entity.Value); } } [Test, TestCaseSource(nameof(GetTestCases))] - public void TestDecimal(CultureInfo from, CultureInfo to) + public void TestDateTime(CultureInfo from, CultureInfo to) { - decimal decimalValue = 12.3m; - object id; - - CurrentCulture = from; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = new LocaleEntity() - { - DecimalValue = decimalValue - }; + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - id = session.Save(entity); - tx.Commit(); - } + PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); + } - CurrentCulture = to; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = session.Get(id); + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDecimal(CultureInfo from, CultureInfo to) + { + decimal decimalValue = 12.3m; - Assert.AreEqual(decimalValue, entity.DecimalValue); - } + PerformTest(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual)); } [Test, TestCaseSource(nameof(GetTestCases))] public void TestDouble(CultureInfo from, CultureInfo to) { double doubleValue = 12.3d; - object id; - CurrentCulture = from; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = new LocaleEntity() - { - DoubleValue = doubleValue - }; - - id = session.Save(entity); - tx.Commit(); - } - - CurrentCulture = to; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = session.Get(id); - - Assert.True(Math.Abs(doubleValue - entity.DoubleValue) < double.Epsilon, $"Expected: {doubleValue}\nBut was: {entity.DoubleValue}\n"); - } + PerformTest(from, to, doubleValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + ); } + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestInteger(CultureInfo from, CultureInfo to) { int integerValue = 123; - object id; - CurrentCulture = from; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = new LocaleEntity() - { - IntegerValue = integerValue - }; - - id = session.Save(entity); - tx.Commit(); - } - - CurrentCulture = to; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = session.Get(id); - - Assert.AreEqual(integerValue, entity.IntegerValue); - } + PerformTest(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual)); } private CultureInfo CurrentCulture diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index d5e70752cd..10621a5867 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -1,11 +1,20 @@ - + - - - - + + + + + + + + + + + + + From d10c4d85eb4463796a133c26c5ec43bbae92c2f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 May 2024 17:35:07 +0000 Subject: [PATCH 14/54] Generate async files --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs new file mode 100644 index 0000000000..67c9c3a3be --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -0,0 +1,202 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Data; +using System.Globalization; +using System.Reflection; +using System.Text; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3530 +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class FixtureAsync : BugTestCase + { + private CultureInfo initialCulture; + + [OneTimeSetUp] + public void FixtureSetup() + { + initialCulture = CurrentCulture; + } + + [OneTimeTearDown] + public void FixtureTearDown() + { + CurrentCulture = initialCulture; + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + protected override void CreateSchema() + { + CreateTable("Integer"); + CreateTable("DateTime"); + CreateTable("Double"); + CreateTable("Decimal"); + } + + private void CreateTable(string name) + { + var sb = new StringBuilder(); + var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); + var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); + + var catalog = GetQuotedDefaultCatalog(); + var schema = GetQuotedDefaultSchema(); + var table = GetQualifiedName(catalog, schema, $"{name}Entity"); + + sb.Append($"{Dialect.CreateTableString} {table} ("); + + // Generate columns + sb.Append($"Id {guidType}, "); + sb.Append($"Value {stringType}, "); + + // Add the primary key contraint for the identity column + sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); + sb.Append(")"); + + using (var cn = Sfi.ConnectionProvider.GetConnection()) + { + try + { + using (var cmd = cn.CreateCommand()) + { + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); + } + } + finally + { + Sfi.ConnectionProvider.CloseConnection(cn); + } + } + } + + private string GetQuotedDefaultCatalog() + { + var t = cfg.GetType(); + var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); + + return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + } + + private string GetQuotedDefaultSchema() + { + var t = cfg.GetType(); + var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); + + return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + } + + private string GetQualifiedName(string catalog, string schema, string name) + { + return Dialect.Qualify(catalog, schema, name); + } + + private async Task PerformTestAsync(CultureInfo from, CultureInfo to, T expectedValue, Action assert, CancellationToken cancellationToken = default(CancellationToken)) + where T : struct + where U : Entity, new() + { + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = new U() + { + Value = expectedValue + }; + + id = await (session.SaveAsync(entity, cancellationToken)); + await (tx.CommitAsync(cancellationToken)); + } + + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var entity = await (session.GetAsync(id, cancellationToken)); + + assert(expectedValue, entity.Value); + } + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDateTimeAsync(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + + await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDecimalAsync(CultureInfo from, CultureInfo to) + { + decimal decimalValue = 12.3m; + + await (PerformTestAsync(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual))); + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDoubleAsync(CultureInfo from, CultureInfo to) + { + double doubleValue = 12.3d; + + await (PerformTestAsync(from, to, doubleValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + )); + } + + [Test, TestCaseSource(nameof(GetTestCases))] + + public async Task TestIntegerAsync(CultureInfo from, CultureInfo to) + { + int integerValue = 123; + + await (PerformTestAsync(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual))); + } + + private CultureInfo CurrentCulture + { + get + { + return CultureInfo.CurrentCulture; + } + set + { + CultureInfo.CurrentCulture = value; + } + } + + public static object[][] GetTestCases() + { + return [ + [new CultureInfo("en-US"), new CultureInfo("de-DE")], + [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], + [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], + ]; + } + } +} From fd4f95c86a7c3d5ff46362d7e3869f721acc9274 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 13:49:05 -0400 Subject: [PATCH 15/54] GH-3530: Remove trailing comma and space from last column in table generation. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 0651eeb534..3b405d3a25 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -58,7 +58,7 @@ private void CreateTable(string name) // Generate columns sb.Append($"Id {guidType}, "); - sb.Append($"Value {stringType}, "); + sb.Append($"Value {stringType}"); // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); From 956219f2f297b6ac1e6f9dca7ce9d84c5b36ed14 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 May 2024 17:51:28 +0000 Subject: [PATCH 16/54] Generate async files --- src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 67c9c3a3be..04a62d04b1 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -70,7 +70,7 @@ private void CreateTable(string name) // Generate columns sb.Append($"Id {guidType}, "); - sb.Append($"Value {stringType}, "); + sb.Append($"Value {stringType}"); // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); From 7ec4e5826520db3d778ae505d658f809f99fc82c Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 15 May 2024 14:13:22 -0400 Subject: [PATCH 17/54] GH-3530: Rename the Value column to DataValue to avoid conflicts with reserved words. --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 4 ++-- src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs | 2 +- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 6 +++--- .../NHSpecificTest/GH3530/Mappings.hbm.xml | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 04a62d04b1..7e69d18781 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -126,7 +126,7 @@ private string GetQualifiedName(string catalog, string schema, string name) { var entity = new U() { - Value = expectedValue + DataValue = expectedValue }; id = await (session.SaveAsync(entity, cancellationToken)); @@ -139,7 +139,7 @@ private string GetQualifiedName(string catalog, string schema, string name) { var entity = await (session.GetAsync(id, cancellationToken)); - assert(expectedValue, entity.Value); + assert(expectedValue, entity.DataValue); } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 52de3445d1..b863779998 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -14,7 +14,7 @@ public abstract class Entity public abstract class Entity:Entity where T : struct { - public virtual T Value { get; set; } + public virtual T DataValue { get; set; } } public class IntegerEntity : Entity { } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 3b405d3a25..27cf07849e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -58,7 +58,7 @@ private void CreateTable(string name) // Generate columns sb.Append($"Id {guidType}, "); - sb.Append($"Value {stringType}"); + sb.Append($"DataValue {stringType}"); // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); @@ -114,7 +114,7 @@ private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue { var entity = new U() { - Value = expectedValue + DataValue = expectedValue }; id = session.Save(entity); @@ -127,7 +127,7 @@ private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue { var entity = session.Get(id); - assert(expectedValue, entity.Value); + assert(expectedValue, entity.DataValue); } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 10621a5867..5693d5ccbe 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -3,18 +3,18 @@ namespace="NHibernate.Test.NHSpecificTest.GH3530"> - + - + - + - + From 6461dddc7b1d87a5ded05a47b9e49066c9d31127 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 May 2024 18:15:50 +0000 Subject: [PATCH 18/54] Generate async files --- src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 7e69d18781..93a06f4ae8 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -70,7 +70,7 @@ private void CreateTable(string name) // Generate columns sb.Append($"Id {guidType}, "); - sb.Append($"Value {stringType}"); + sb.Append($"DataValue {stringType}"); // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); From e09ffe6e1a285d896d78f31d19cdd98bf3f9d8ad Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 08:06:53 -0400 Subject: [PATCH 19/54] GH-3530: Add additional test that uses the DateTime type with the dilect's suggested type. Perform some minor cleanup recommended by the DeepSource analysis. --- .../NHSpecificTest/GH3530/Entities.cs | 1 + .../NHSpecificTest/GH3530/Fixture.cs | 26 +++++++++++++------ .../NHSpecificTest/GH3530/Mappings.hbm.xml | 22 +++++++++++++--- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index b863779998..17c59faa87 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -22,4 +22,5 @@ public class DateTimeEntity : Entity { } public class DoubleEntity : Entity { } public class DecimalEntity : Entity { } + public class NHDateTimeEntity : Entity { } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 27cf07849e..21bfef3b78 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -42,8 +42,16 @@ protected override void CreateSchema() CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + + base.CreateSchema(); } + /// + /// This function creates the schema for our custom entities. + /// If the SchemaExporter provided a mechanism to override the database + /// type, this method would not be required. + /// + /// private void CreateTable(string name) { var sb = new StringBuilder(); @@ -131,6 +139,14 @@ private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue } } + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestNHDateTime(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + + PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); + } + [Test, TestCaseSource(nameof(GetTestCases))] public void TestDateTime(CultureInfo from, CultureInfo to) { @@ -168,14 +184,8 @@ public void TestInteger(CultureInfo from, CultureInfo to) private CultureInfo CurrentCulture { - get - { - return CultureInfo.CurrentCulture; - } - set - { - CultureInfo.CurrentCulture = value; - } + get => CultureInfo.CurrentCulture; + set => CultureInfo.CurrentCulture = value; } public static object[][] GetTestCases() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 5693d5ccbe..9de8d6eb69 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -1,19 +1,33 @@ - + + - + - + - + + + + + + + From c2c7bd5101543a3ce4c013ee635a5b584d9e9cde Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 May 2024 12:09:18 +0000 Subject: [PATCH 20/54] Generate async files --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 93a06f4ae8..510d269ae6 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -54,8 +54,16 @@ protected override void CreateSchema() CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + + base.CreateSchema(); } + /// + /// This function creates the schema for our custom entities. + /// If the SchemaExporter provided a mechanism to override the database + /// type, this method would not be required. + /// + /// private void CreateTable(string name) { var sb = new StringBuilder(); @@ -143,6 +151,14 @@ private string GetQualifiedName(string catalog, string schema, string name) } } + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestNHDateTimeAsync(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + + await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); + } + [Test, TestCaseSource(nameof(GetTestCases))] public async Task TestDateTimeAsync(CultureInfo from, CultureInfo to) { @@ -180,14 +196,8 @@ public async Task TestIntegerAsync(CultureInfo from, CultureInfo to) private CultureInfo CurrentCulture { - get - { - return CultureInfo.CurrentCulture; - } - set - { - CultureInfo.CurrentCulture = value; - } + get => CultureInfo.CurrentCulture; + set => CultureInfo.CurrentCulture = value; } public static object[][] GetTestCases() From ea8146444c616cbeb01cf48d902ac32d5e3bf9b7 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 08:42:13 -0400 Subject: [PATCH 21/54] GH-3530: Let the SchemaExporter drop and create tables before attempting to create them manually. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 5 +++-- .../NHSpecificTest/GH3530/Mappings.hbm.xml | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 21bfef3b78..cfdda67434 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -38,12 +38,13 @@ protected override void OnTearDown() protected override void CreateSchema() { + // Let the SchemaExporter drop and create tables if needed. + base.CreateSchema(); + CreateTable("Integer"); CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); - - base.CreateSchema(); } /// diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 9de8d6eb69..542410eafd 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -7,19 +7,19 @@ not provide a mechanism of doing this, hence they have a schema-action of 'none'. --> - + - + - + - + From 06edc33253151554dcbe7577bd17379fdeec81d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 May 2024 12:46:15 +0000 Subject: [PATCH 22/54] Generate async files --- src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 510d269ae6..4a4f61bdbd 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -50,12 +50,13 @@ protected override void OnTearDown() protected override void CreateSchema() { + // Let the SchemaExporter drop and create tables if needed. + base.CreateSchema(); + CreateTable("Integer"); CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); - - base.CreateSchema(); } /// From 91f2599d271bdacd5b3b6b9b3de9e79c1aae0f95 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 09:04:41 -0400 Subject: [PATCH 23/54] GH-3530: Add exception handler to handle cases when the table already exists. Partially revert part of the previous commit which changed the responisbility of the SchemaExporter. Hopefully this fixes failing tests due to schema issues. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 9 ++++++--- .../NHSpecificTest/GH3530/Mappings.hbm.xml | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index cfdda67434..1e194b9917 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -38,13 +38,12 @@ protected override void OnTearDown() protected override void CreateSchema() { - // Let the SchemaExporter drop and create tables if needed. - base.CreateSchema(); - CreateTable("Integer"); CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + + base.CreateSchema(); } /// @@ -83,6 +82,10 @@ private void CreateTable(string name) cmd.ExecuteNonQuery(); } } + catch (Exception ex) + { + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); + } finally { Sfi.ConnectionProvider.CloseConnection(cn); diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 542410eafd..9de8d6eb69 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -7,19 +7,19 @@ not provide a mechanism of doing this, hence they have a schema-action of 'none'. --> - + - + - + - + From f9575cb5b24a24a1472fbb69f42585edf8697199 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 May 2024 13:14:37 +0000 Subject: [PATCH 24/54] Generate async files --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 4a4f61bdbd..69962e8bd2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -50,13 +50,12 @@ protected override void OnTearDown() protected override void CreateSchema() { - // Let the SchemaExporter drop and create tables if needed. - base.CreateSchema(); - CreateTable("Integer"); CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + + base.CreateSchema(); } /// @@ -95,6 +94,10 @@ private void CreateTable(string name) cmd.ExecuteNonQuery(); } } + catch (Exception ex) + { + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); + } finally { Sfi.ConnectionProvider.CloseConnection(cn); From a2cf98c4a132af6f32be4222670d6bbcccac854a Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:15:28 -0400 Subject: [PATCH 25/54] GH-5350: Rename Entity to DataEntity to address Deepsource issue. --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 4 ++-- .../NHSpecificTest/GH3530/Entities.cs | 12 ++++++------ src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 69962e8bd2..33eef091b2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by AsyncGenerator. // @@ -128,7 +128,7 @@ private string GetQualifiedName(string catalog, string schema, string name) private async Task PerformTestAsync(CultureInfo from, CultureInfo to, T expectedValue, Action assert, CancellationToken cancellationToken = default(CancellationToken)) where T : struct - where U : Entity, new() + where U : DataEntity, new() { object id; diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 17c59faa87..9cede004a2 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -12,15 +12,15 @@ public abstract class Entity public virtual Guid Id { get; set; } } - public abstract class Entity:Entity where T : struct + public abstract class DataEntity:Entity where T : struct { public virtual T DataValue { get; set; } } - public class IntegerEntity : Entity { } - public class DateTimeEntity : Entity { } + public class IntegerEntity : DataEntity { } + public class DateTimeEntity : DataEntity { } - public class DoubleEntity : Entity { } - public class DecimalEntity : Entity { } - public class NHDateTimeEntity : Entity { } + public class DoubleEntity : DataEntity { } + public class DecimalEntity : DataEntity { } + public class NHDateTimeEntity : DataEntity { } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 1e194b9917..6439f63e4e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -116,7 +116,7 @@ private string GetQualifiedName(string catalog, string schema, string name) private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue, Action assert) where T : struct - where U : Entity, new() + where U : DataEntity, new() { object id; From f1661ebb77526455cef8384f9873ba7bd78dae8a Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:17:03 -0400 Subject: [PATCH 26/54] GH-5350: Use StringBuilder.Append(char) for appending a single character. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 6439f63e4e..94db4899c1 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -70,7 +70,7 @@ private void CreateTable(string name) // Add the primary key contraint for the identity column sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); - sb.Append(")"); + sb.Append(')'); using (var cn = Sfi.ConnectionProvider.GetConnection()) { From 36b951e147f4baabf15868629d18b204d533e071 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:19:25 -0400 Subject: [PATCH 27/54] GH-3530: Switch to simple using statements per Deepsource. --- .../NHSpecificTest/GH3530/Fixture.cs | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 94db4899c1..0894a85b67 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -27,13 +27,12 @@ public void FixtureTearDown() protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - transaction.Commit(); - } + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); } protected override void CreateSchema() @@ -72,24 +71,21 @@ private void CreateTable(string name) sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); sb.Append(')'); - using (var cn = Sfi.ConnectionProvider.GetConnection()) + using var cn = Sfi.ConnectionProvider.GetConnection(); + try { - try - { - using (var cmd = cn.CreateCommand()) - { - cmd.CommandText = sb.ToString(); - cmd.ExecuteNonQuery(); - } - } - catch (Exception ex) - { - Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); - } - finally - { - Sfi.ConnectionProvider.CloseConnection(cn); - } + using var cmd = cn.CreateCommand(); + + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); + } + finally + { + Sfi.ConnectionProvider.CloseConnection(cn); } } From 2e3206f7c5a19c949b109283953f7dd33dae3ea7 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:20:36 -0400 Subject: [PATCH 28/54] GH-3530: Switch to file scoped namespacing per Deepsource. --- .../NHSpecificTest/GH3530/Fixture.cs | 297 +++++++++--------- 1 file changed, 148 insertions(+), 149 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 0894a85b67..1d5427b7a9 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -6,195 +6,194 @@ using NHibernate.SqlTypes; using NUnit.Framework; -namespace NHibernate.Test.NHSpecificTest.GH3530 -{ - [TestFixture] - public class Fixture : BugTestCase - { - private CultureInfo initialCulture; - - [OneTimeSetUp] - public void FixtureSetup() - { - initialCulture = CurrentCulture; - } +namespace NHibernate.Test.NHSpecificTest.GH3530; - [OneTimeTearDown] - public void FixtureTearDown() - { - CurrentCulture = initialCulture; - } +[TestFixture] +public class Fixture : BugTestCase +{ + private CultureInfo initialCulture; - protected override void OnTearDown() - { - using var session = OpenSession(); - using var transaction = session.BeginTransaction(); + [OneTimeSetUp] + public void FixtureSetup() + { + initialCulture = CurrentCulture; + } - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + [OneTimeTearDown] + public void FixtureTearDown() + { + CurrentCulture = initialCulture; + } - transaction.Commit(); - } + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - protected override void CreateSchema() - { - CreateTable("Integer"); - CreateTable("DateTime"); - CreateTable("Double"); - CreateTable("Decimal"); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - base.CreateSchema(); - } + transaction.Commit(); + } - /// - /// This function creates the schema for our custom entities. - /// If the SchemaExporter provided a mechanism to override the database - /// type, this method would not be required. - /// - /// - private void CreateTable(string name) - { - var sb = new StringBuilder(); - var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); - var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); + protected override void CreateSchema() + { + CreateTable("Integer"); + CreateTable("DateTime"); + CreateTable("Double"); + CreateTable("Decimal"); - var catalog = GetQuotedDefaultCatalog(); - var schema = GetQuotedDefaultSchema(); - var table = GetQualifiedName(catalog, schema, $"{name}Entity"); + base.CreateSchema(); + } - sb.Append($"{Dialect.CreateTableString} {table} ("); + /// + /// This function creates the schema for our custom entities. + /// If the SchemaExporter provided a mechanism to override the database + /// type, this method would not be required. + /// + /// + private void CreateTable(string name) + { + var sb = new StringBuilder(); + var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); + var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); - // Generate columns - sb.Append($"Id {guidType}, "); - sb.Append($"DataValue {stringType}"); + var catalog = GetQuotedDefaultCatalog(); + var schema = GetQuotedDefaultSchema(); + var table = GetQualifiedName(catalog, schema, $"{name}Entity"); - // Add the primary key contraint for the identity column - sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); - sb.Append(')'); + sb.Append($"{Dialect.CreateTableString} {table} ("); - using var cn = Sfi.ConnectionProvider.GetConnection(); - try - { - using var cmd = cn.CreateCommand(); + // Generate columns + sb.Append($"Id {guidType}, "); + sb.Append($"DataValue {stringType}"); - cmd.CommandText = sb.ToString(); - cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); - } - finally - { - Sfi.ConnectionProvider.CloseConnection(cn); - } - } + // Add the primary key contraint for the identity column + sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); + sb.Append(')'); - private string GetQuotedDefaultCatalog() + using var cn = Sfi.ConnectionProvider.GetConnection(); + try { - var t = cfg.GetType(); - var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); + using var cmd = cn.CreateCommand(); - return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); } - - private string GetQuotedDefaultSchema() + catch (Exception ex) { - var t = cfg.GetType(); - var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); - - return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); } - - private string GetQualifiedName(string catalog, string schema, string name) + finally { - return Dialect.Qualify(catalog, schema, name); + Sfi.ConnectionProvider.CloseConnection(cn); } + } - private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue, Action assert) - where T : struct - where U : DataEntity, new() - { - object id; + private string GetQuotedDefaultCatalog() + { + var t = cfg.GetType(); + var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); - CurrentCulture = from; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = new U() - { - DataValue = expectedValue - }; - - id = session.Save(entity); - tx.Commit(); - } - - CurrentCulture = to; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = session.Get(id); + return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + } - assert(expectedValue, entity.DataValue); - } - } + private string GetQuotedDefaultSchema() + { + var t = cfg.GetType(); + var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); - [Test, TestCaseSource(nameof(GetTestCases))] - public void TestNHDateTime(CultureInfo from, CultureInfo to) - { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + } - PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); - } + private string GetQualifiedName(string catalog, string schema, string name) + { + return Dialect.Qualify(catalog, schema, name); + } - [Test, TestCaseSource(nameof(GetTestCases))] - public void TestDateTime(CultureInfo from, CultureInfo to) + private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue, Action assert) + where T : struct + where U : DataEntity, new() + { + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + var entity = new U() + { + DataValue = expectedValue + }; - PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); + id = session.Save(entity); + tx.Commit(); } - [Test, TestCaseSource(nameof(GetTestCases))] - public void TestDecimal(CultureInfo from, CultureInfo to) + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) { - decimal decimalValue = 12.3m; + var entity = session.Get(id); - PerformTest(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual)); + assert(expectedValue, entity.DataValue); } + } - [Test, TestCaseSource(nameof(GetTestCases))] - public void TestDouble(CultureInfo from, CultureInfo to) - { - double doubleValue = 12.3d; + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestNHDateTime(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - PerformTest(from, to, doubleValue, - (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") - ); - } + PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); + } - [Test, TestCaseSource(nameof(GetTestCases))] + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDateTime(CultureInfo from, CultureInfo to) + { + DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - public void TestInteger(CultureInfo from, CultureInfo to) - { - int integerValue = 123; + PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); + } - PerformTest(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual)); - } + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDecimal(CultureInfo from, CultureInfo to) + { + decimal decimalValue = 12.3m; - private CultureInfo CurrentCulture - { - get => CultureInfo.CurrentCulture; - set => CultureInfo.CurrentCulture = value; - } + PerformTest(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual)); + } - public static object[][] GetTestCases() - { - return [ - [new CultureInfo("en-US"), new CultureInfo("de-DE")], - [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], - [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], - ]; - } + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestDouble(CultureInfo from, CultureInfo to) + { + double doubleValue = 12.3d; + + PerformTest(from, to, doubleValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + ); + } + + [Test, TestCaseSource(nameof(GetTestCases))] + + public void TestInteger(CultureInfo from, CultureInfo to) + { + int integerValue = 123; + + PerformTest(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual)); + } + + private CultureInfo CurrentCulture + { + get => CultureInfo.CurrentCulture; + set => CultureInfo.CurrentCulture = value; + } + + public static object[][] GetTestCases() + { + return [ + [new CultureInfo("en-US"), new CultureInfo("de-DE")], + [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], + [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], + ]; } } From 8625f25d3f669efb4703209adf64133d3a80fb1e Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:23:30 -0400 Subject: [PATCH 29/54] GH-3530: Replace explicit type with var to avoid type duplication. --- src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 1d5427b7a9..0f53187c51 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -142,7 +142,7 @@ private void PerformTest(CultureInfo from, CultureInfo to, T expectedValue [Test, TestCaseSource(nameof(GetTestCases))] public void TestNHDateTime(CultureInfo from, CultureInfo to) { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + var leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); } @@ -150,7 +150,7 @@ public void TestNHDateTime(CultureInfo from, CultureInfo to) [Test, TestCaseSource(nameof(GetTestCases))] public void TestDateTime(CultureInfo from, CultureInfo to) { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + var leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); PerformTest(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual)); } From 58fe6c7419cff2716f4e7c8fbe585c5595b2da97 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 May 2024 18:26:34 +0000 Subject: [PATCH 30/54] Generate async files --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 307 +++++++++--------- 1 file changed, 151 insertions(+), 156 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index 33eef091b2..db63b5d4cf 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by AsyncGenerator. // @@ -16,201 +16,196 @@ using NHibernate.SqlTypes; using NUnit.Framework; -namespace NHibernate.Test.NHSpecificTest.GH3530 +namespace NHibernate.Test.NHSpecificTest.GH3530; +using System.Threading.Tasks; +using System.Threading; + +[TestFixture] +public class FixtureAsync : BugTestCase { - using System.Threading.Tasks; - using System.Threading; - [TestFixture] - public class FixtureAsync : BugTestCase - { - private CultureInfo initialCulture; + private CultureInfo initialCulture; - [OneTimeSetUp] - public void FixtureSetup() - { - initialCulture = CurrentCulture; - } + [OneTimeSetUp] + public void FixtureSetup() + { + initialCulture = CurrentCulture; + } - [OneTimeTearDown] - public void FixtureTearDown() - { - CurrentCulture = initialCulture; - } + [OneTimeTearDown] + public void FixtureTearDown() + { + CurrentCulture = initialCulture; + } - protected override void OnTearDown() - { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - transaction.Commit(); - } - } + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - protected override void CreateSchema() - { - CreateTable("Integer"); - CreateTable("DateTime"); - CreateTable("Double"); - CreateTable("Decimal"); + transaction.Commit(); + } - base.CreateSchema(); - } + protected override void CreateSchema() + { + CreateTable("Integer"); + CreateTable("DateTime"); + CreateTable("Double"); + CreateTable("Decimal"); - /// - /// This function creates the schema for our custom entities. - /// If the SchemaExporter provided a mechanism to override the database - /// type, this method would not be required. - /// - /// - private void CreateTable(string name) - { - var sb = new StringBuilder(); - var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); - var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); + base.CreateSchema(); + } - var catalog = GetQuotedDefaultCatalog(); - var schema = GetQuotedDefaultSchema(); - var table = GetQualifiedName(catalog, schema, $"{name}Entity"); + /// + /// This function creates the schema for our custom entities. + /// If the SchemaExporter provided a mechanism to override the database + /// type, this method would not be required. + /// + /// + private void CreateTable(string name) + { + var sb = new StringBuilder(); + var guidType = Dialect.GetTypeName(SqlTypeFactory.Guid); + var stringType = Dialect.GetTypeName(SqlTypeFactory.GetAnsiString(255)); - sb.Append($"{Dialect.CreateTableString} {table} ("); + var catalog = GetQuotedDefaultCatalog(); + var schema = GetQuotedDefaultSchema(); + var table = GetQualifiedName(catalog, schema, $"{name}Entity"); - // Generate columns - sb.Append($"Id {guidType}, "); - sb.Append($"DataValue {stringType}"); + sb.Append($"{Dialect.CreateTableString} {table} ("); - // Add the primary key contraint for the identity column - sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); - sb.Append(")"); + // Generate columns + sb.Append($"Id {guidType}, "); + sb.Append($"DataValue {stringType}"); - using (var cn = Sfi.ConnectionProvider.GetConnection()) - { - try - { - using (var cmd = cn.CreateCommand()) - { - cmd.CommandText = sb.ToString(); - cmd.ExecuteNonQuery(); - } - } - catch (Exception ex) - { - Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); - } - finally - { - Sfi.ConnectionProvider.CloseConnection(cn); - } - } - } + // Add the primary key contraint for the identity column + sb.Append($", {Dialect.PrimaryKeyString} ( Id )"); + sb.Append(')'); - private string GetQuotedDefaultCatalog() + using var cn = Sfi.ConnectionProvider.GetConnection(); + try { - var t = cfg.GetType(); - var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); + using var cmd = cn.CreateCommand(); - return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); } - - private string GetQuotedDefaultSchema() + catch (Exception ex) { - var t = cfg.GetType(); - var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); - - return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); } - - private string GetQualifiedName(string catalog, string schema, string name) + finally { - return Dialect.Qualify(catalog, schema, name); + Sfi.ConnectionProvider.CloseConnection(cn); } + } - private async Task PerformTestAsync(CultureInfo from, CultureInfo to, T expectedValue, Action assert, CancellationToken cancellationToken = default(CancellationToken)) - where T : struct - where U : DataEntity, new() - { - object id; + private string GetQuotedDefaultCatalog() + { + var t = cfg.GetType(); + var getQuotedDefaultCatalog = t.GetMethod("GetQuotedDefaultCatalog", BindingFlags.Instance | BindingFlags.NonPublic); - CurrentCulture = from; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = new U() - { - DataValue = expectedValue - }; - - id = await (session.SaveAsync(entity, cancellationToken)); - await (tx.CommitAsync(cancellationToken)); - } - - CurrentCulture = to; - using (var session = OpenSession()) - using (var tx = session.BeginTransaction()) - { - var entity = await (session.GetAsync(id, cancellationToken)); + return (string) getQuotedDefaultCatalog.Invoke(cfg, [Dialect]); + } - assert(expectedValue, entity.DataValue); - } - } + private string GetQuotedDefaultSchema() + { + var t = cfg.GetType(); + var getQuotedDefaultSchema = t.GetMethod("GetQuotedDefaultSchema", BindingFlags.Instance | BindingFlags.NonPublic); - [Test, TestCaseSource(nameof(GetTestCases))] - public async Task TestNHDateTimeAsync(CultureInfo from, CultureInfo to) - { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + return (string) getQuotedDefaultSchema.Invoke(cfg, [Dialect]); + } - await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); - } + private string GetQualifiedName(string catalog, string schema, string name) + { + return Dialect.Qualify(catalog, schema, name); + } - [Test, TestCaseSource(nameof(GetTestCases))] - public async Task TestDateTimeAsync(CultureInfo from, CultureInfo to) + private async Task PerformTestAsync(CultureInfo from, CultureInfo to, T expectedValue, Action assert, CancellationToken cancellationToken = default(CancellationToken)) + where T : struct + where U : DataEntity, new() + { + object id; + + CurrentCulture = from; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) { - DateTime leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); + var entity = new U() + { + DataValue = expectedValue + }; - await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); + id = await (session.SaveAsync(entity, cancellationToken)); + await (tx.CommitAsync(cancellationToken)); } - [Test, TestCaseSource(nameof(GetTestCases))] - public async Task TestDecimalAsync(CultureInfo from, CultureInfo to) + CurrentCulture = to; + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) { - decimal decimalValue = 12.3m; + var entity = await (session.GetAsync(id, cancellationToken)); - await (PerformTestAsync(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual))); + assert(expectedValue, entity.DataValue); } + } - [Test, TestCaseSource(nameof(GetTestCases))] - public async Task TestDoubleAsync(CultureInfo from, CultureInfo to) - { - double doubleValue = 12.3d; + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestNHDateTimeAsync(CultureInfo from, CultureInfo to) + { + var leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - await (PerformTestAsync(from, to, doubleValue, - (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") - )); - } + await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); + } - [Test, TestCaseSource(nameof(GetTestCases))] + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDateTimeAsync(CultureInfo from, CultureInfo to) + { + var leapDay = new DateTime(2024, 2, 29, new GregorianCalendar(GregorianCalendarTypes.USEnglish)); - public async Task TestIntegerAsync(CultureInfo from, CultureInfo to) - { - int integerValue = 123; + await (PerformTestAsync(from, to, leapDay, (expected, actual) => Assert.AreEqual(expected, actual))); + } - await (PerformTestAsync(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual))); - } + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDecimalAsync(CultureInfo from, CultureInfo to) + { + decimal decimalValue = 12.3m; - private CultureInfo CurrentCulture - { - get => CultureInfo.CurrentCulture; - set => CultureInfo.CurrentCulture = value; - } + await (PerformTestAsync(from, to, decimalValue, (expected, actual) => Assert.AreEqual(expected, actual))); + } - public static object[][] GetTestCases() - { - return [ - [new CultureInfo("en-US"), new CultureInfo("de-DE")], - [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], - [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], - ]; - } + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestDoubleAsync(CultureInfo from, CultureInfo to) + { + double doubleValue = 12.3d; + + await (PerformTestAsync(from, to, doubleValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + )); + } + + [Test, TestCaseSource(nameof(GetTestCases))] + + public async Task TestIntegerAsync(CultureInfo from, CultureInfo to) + { + int integerValue = 123; + + await (PerformTestAsync(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual))); + } + + private CultureInfo CurrentCulture + { + get => CultureInfo.CurrentCulture; + set => CultureInfo.CurrentCulture = value; + } + + public static object[][] GetTestCases() + { + return [ + [new CultureInfo("en-US"), new CultureInfo("de-DE")], + [new CultureInfo("en-US"), new CultureInfo("ar-SA", false)], + [new CultureInfo("en-US"), new CultureInfo("th-TH", false)], + ]; } } From 2be793d5537a2c509dc83a3e1d35952defa254f6 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 16 May 2024 14:32:36 -0400 Subject: [PATCH 31/54] GH-3530: Switch to file scoped namespace per DeepSource. --- .../NHSpecificTest/GH3530/Entities.cs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index 9cede004a2..ef740ce446 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -1,26 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using NHibernate.SqlCommand; -namespace NHibernate.Test.NHSpecificTest.GH3530 +namespace NHibernate.Test.NHSpecificTest.GH3530; + +public abstract class Entity { - public abstract class Entity - { - public virtual Guid Id { get; set; } - } + public virtual Guid Id { get; set; } +} - public abstract class DataEntity:Entity where T : struct - { - public virtual T DataValue { get; set; } - } +public abstract class DataEntity:Entity where T : struct +{ + public virtual T DataValue { get; set; } +} - public class IntegerEntity : DataEntity { } - public class DateTimeEntity : DataEntity { } +public class IntegerEntity : DataEntity { } +public class DateTimeEntity : DataEntity { } - public class DoubleEntity : DataEntity { } - public class DecimalEntity : DataEntity { } - public class NHDateTimeEntity : DataEntity { } -} +public class DoubleEntity : DataEntity { } +public class DecimalEntity : DataEntity { } +public class NHDateTimeEntity : DataEntity { } From ac708f6461dbc90f3e8f00eb5b79dfbf4359abad Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 29 May 2024 09:58:03 -0400 Subject: [PATCH 32/54] GH-5350: Add global setting for specifying the locale of the database. --- src/NHibernate/Cfg/Environment.cs | 2 ++ src/NHibernate/Cfg/Settings.cs | 2 ++ src/NHibernate/Cfg/SettingsFactory.cs | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/src/NHibernate/Cfg/Environment.cs b/src/NHibernate/Cfg/Environment.cs index c052cd6426..ca8b577b04 100644 --- a/src/NHibernate/Cfg/Environment.cs +++ b/src/NHibernate/Cfg/Environment.cs @@ -92,6 +92,8 @@ public static string Version /// A default database catalog name to use for unqualified tablenames public const string DefaultCatalog = "default_catalog"; + public const string Locale = "locale"; + // Since v5 [Obsolete("DefaultEntityMode is deprecated.")] public const string DefaultEntityMode = "default_entity_mode"; diff --git a/src/NHibernate/Cfg/Settings.cs b/src/NHibernate/Cfg/Settings.cs index 633133450a..2eda1996be 100644 --- a/src/NHibernate/Cfg/Settings.cs +++ b/src/NHibernate/Cfg/Settings.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq.Expressions; using NHibernate.AdoNet; using NHibernate.AdoNet.Util; @@ -228,5 +229,6 @@ internal string GetFullCacheRegionName(string name) public BatchFetchStyle BatchFetchStyle { get; internal set; } public BatchingEntityLoaderBuilder BatchingEntityLoaderBuilder { get; internal set; } public BatchingCollectionInitializerBuilder BatchingCollectionInitializationBuilder { get; internal set; } + public CultureInfo Locale { get; internal set; } } } diff --git a/src/NHibernate/Cfg/SettingsFactory.cs b/src/NHibernate/Cfg/SettingsFactory.cs index 4babe5afb9..a09e513703 100644 --- a/src/NHibernate/Cfg/SettingsFactory.cs +++ b/src/NHibernate/Cfg/SettingsFactory.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Data; +using System.Globalization; using NHibernate.AdoNet; using NHibernate.AdoNet.Util; using NHibernate.Cache; @@ -354,6 +355,9 @@ public Settings BuildSettings(IDictionary properties) settings.BatchFetchStyle = PropertiesHelper.GetEnum(Environment.BatchFetchStyle, properties, BatchFetchStyle.Legacy); settings.BatchingEntityLoaderBuilder = GetBatchingEntityLoaderBuilder(settings.BatchFetchStyle); settings.BatchingCollectionInitializationBuilder = GetBatchingCollectionInitializationBuilder(settings.BatchFetchStyle); + + string locale = PropertiesHelper.GetString(Environment.Locale, properties, CultureInfo.InvariantCulture.Name); + settings.Locale = CultureInfo.GetCultureInfo(locale); return settings; } From bb38501112b4aaa2e715e886d875eed85200e188 Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 29 May 2024 10:29:57 -0400 Subject: [PATCH 33/54] GH-3530: Use type specific methods of DbDataReader where possible and use Convert with the user provided locale if necessary. --- .../AdoNet/DbDataReaderExtensions.cs | 243 ++++++++++++++++++ .../Async/Type/AbstractDateTimeType.cs | 1 + src/NHibernate/Async/Type/ByteType.cs | 1 + src/NHibernate/Async/Type/Int16Type.cs | 1 + src/NHibernate/Async/Type/Int32Type.cs | 1 + src/NHibernate/Async/Type/Int64Type.cs | 1 + src/NHibernate/Async/Type/TicksType.cs | 1 + .../Async/Type/TimeAsTimeSpanType.cs | 1 + src/NHibernate/Async/Type/TimeSpanType.cs | 1 + src/NHibernate/Async/Type/UInt16Type.cs | 1 + src/NHibernate/Async/Type/UInt32Type.cs | 1 + src/NHibernate/Async/Type/UInt64Type.cs | 1 + src/NHibernate/Async/Type/UriType.cs | 1 + src/NHibernate/Async/Type/XDocType.cs | 1 + src/NHibernate/Async/Type/XmlDocType.cs | 1 + src/NHibernate/Type/AbstractCharType.cs | 19 +- src/NHibernate/Type/AbstractDateTimeType.cs | 10 +- src/NHibernate/Type/AbstractStringType.cs | 12 +- src/NHibernate/Type/BooleanType.cs | 10 +- src/NHibernate/Type/ByteType.cs | 11 +- src/NHibernate/Type/CharBooleanType.cs | 13 +- src/NHibernate/Type/DecimalType.cs | 10 +- src/NHibernate/Type/DoubleType.cs | 10 +- src/NHibernate/Type/GuidType.cs | 14 +- src/NHibernate/Type/Int16Type.cs | 10 +- src/NHibernate/Type/Int32Type.cs | 10 +- src/NHibernate/Type/Int64Type.cs | 10 +- src/NHibernate/Type/SByteType.cs | 10 +- src/NHibernate/Type/SingleType.cs | 10 +- src/NHibernate/Type/TicksType.cs | 1 + src/NHibernate/Type/TimeAsTimeSpanType.cs | 24 +- src/NHibernate/Type/TimeSpanType.cs | 10 +- src/NHibernate/Type/TimeType.cs | 27 +- src/NHibernate/Type/UInt16Type.cs | 10 +- src/NHibernate/Type/UInt32Type.cs | 10 +- src/NHibernate/Type/UInt64Type.cs | 10 +- src/NHibernate/Type/UriType.cs | 10 +- src/NHibernate/Type/XDocType.cs | 15 +- src/NHibernate/Type/XmlDocType.cs | 15 +- 39 files changed, 494 insertions(+), 54 deletions(-) create mode 100644 src/NHibernate/AdoNet/DbDataReaderExtensions.cs diff --git a/src/NHibernate/AdoNet/DbDataReaderExtensions.cs b/src/NHibernate/AdoNet/DbDataReaderExtensions.cs new file mode 100644 index 0000000000..9f900fe909 --- /dev/null +++ b/src/NHibernate/AdoNet/DbDataReaderExtensions.cs @@ -0,0 +1,243 @@ +using System; +using System.Data.Common; + +namespace NHibernate.AdoNet +{ + internal static class DbDataReaderExtensions + { + public static bool TryGetBoolean(this DbDataReader rs, int ordinal, out bool value) + { + try + { + value = rs.GetBoolean(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetByte(this DbDataReader rs, int ordinal, out byte value) + { + try + { + value = rs.GetByte(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetChar(this DbDataReader rs, int ordinal, out char value) + { + try + { + value = rs.GetChar(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetDecimal(this DbDataReader rs, int ordinal, out decimal value) + { + try + { + value = rs.GetDecimal(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetDouble(this DbDataReader rs, int ordinal, out double value) + { + try + { + value = rs.GetDouble(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetDateTime(this DbDataReader rs, int ordinal, out DateTime value) + { + try + { + value = rs.GetDateTime(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + public static bool TryGetFloat(this DbDataReader rs, int ordinal, out float value) + { + try + { + value = rs.GetFloat(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + public static bool TryGetGuid(this DbDataReader rs, int ordinal, out Guid value) + { + try + { + value = rs.GetGuid(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetUInt16(this DbDataReader rs, int ordinal, out ushort value) + { + var dbValue = rs[ordinal]; + + if (dbValue is ushort) + { + value = (ushort) dbValue; + return true; + } + + value = default; + return false; + } + + public static bool TryGetInt16(this DbDataReader rs, int ordinal, out short value) + { + try + { + value = rs.GetInt16(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + public static bool TryGetInt32(this DbDataReader rs, int ordinal, out int value) + { + try + { + value = rs.GetInt32(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetUInt32(this DbDataReader rs, int ordinal, out uint value) + { + var dbValue = rs[ordinal]; + + if (dbValue is uint) + { + value = (uint) dbValue; + return true; + } + + value = default; + return false; + } + + public static bool TryGetInt64(this DbDataReader rs, int ordinal, out long value) + { + try + { + value = rs.GetInt64(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetUInt64(this DbDataReader rs, int ordinal, out ulong value) + { + var dbValue = rs[ordinal]; + + if (dbValue is ulong) + { + value = (ulong) dbValue; + return true; + } + + value = default; + return false; + } + + public static bool TryGetSByte(this DbDataReader rs, int ordinal, out sbyte value) + { + var dbValue = rs[ordinal]; + + if (dbValue is sbyte) + { + value = (sbyte) rs[ordinal]; + return true; + } + + value = default; + return false; + } + + public static bool TryGetString(this DbDataReader rs, int ordinal, out string value) + { + try + { + value = rs.GetString(ordinal); + return true; + } + catch (InvalidCastException) + { + value = default; + return false; + } + } + + public static bool TryGetTimeSpan(this DbDataReader rs, int ordinal, out TimeSpan value) + { + var dbValue = rs[ordinal]; + + if (dbValue is TimeSpan) + { + value = (TimeSpan) dbValue; + return true; + } + + value = default; + return false; + } + } +} diff --git a/src/NHibernate/Async/Type/AbstractDateTimeType.cs b/src/NHibernate/Async/Type/AbstractDateTimeType.cs index 827ac03499..2265da3191 100644 --- a/src/NHibernate/Async/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Async/Type/AbstractDateTimeType.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Globalization; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/ByteType.cs b/src/NHibernate/Async/Type/ByteType.cs index 0d38fdf1a7..bc2c01e193 100644 --- a/src/NHibernate/Async/Type/ByteType.cs +++ b/src/NHibernate/Async/Type/ByteType.cs @@ -13,6 +13,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/Int16Type.cs b/src/NHibernate/Async/Type/Int16Type.cs index 598f83c5aa..3f35f525f6 100644 --- a/src/NHibernate/Async/Type/Int16Type.cs +++ b/src/NHibernate/Async/Type/Int16Type.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using NHibernate.AdoNet; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/Int32Type.cs b/src/NHibernate/Async/Type/Int32Type.cs index 3b4217968d..43f736e3a9 100644 --- a/src/NHibernate/Async/Type/Int32Type.cs +++ b/src/NHibernate/Async/Type/Int32Type.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using NHibernate.AdoNet; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/Int64Type.cs b/src/NHibernate/Async/Type/Int64Type.cs index e1b07967cb..4ed4d25cbb 100644 --- a/src/NHibernate/Async/Type/Int64Type.cs +++ b/src/NHibernate/Async/Type/Int64Type.cs @@ -14,6 +14,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/TicksType.cs b/src/NHibernate/Async/Type/TicksType.cs index 0ffb06b37f..c239faf2c8 100644 --- a/src/NHibernate/Async/Type/TicksType.cs +++ b/src/NHibernate/Async/Type/TicksType.cs @@ -11,6 +11,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs index 185baa88eb..08aedfa938 100644 --- a/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs @@ -15,6 +15,7 @@ using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using NHibernate.AdoNet; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/TimeSpanType.cs b/src/NHibernate/Async/Type/TimeSpanType.cs index 0917413671..b5d7339ef7 100644 --- a/src/NHibernate/Async/Type/TimeSpanType.cs +++ b/src/NHibernate/Async/Type/TimeSpanType.cs @@ -15,6 +15,7 @@ using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using NHibernate.AdoNet; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/UInt16Type.cs b/src/NHibernate/Async/Type/UInt16Type.cs index cfd05ee60f..7d3a63d3a5 100644 --- a/src/NHibernate/Async/Type/UInt16Type.cs +++ b/src/NHibernate/Async/Type/UInt16Type.cs @@ -14,6 +14,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/UInt32Type.cs b/src/NHibernate/Async/Type/UInt32Type.cs index 2fa37d0116..5ff4642c8d 100644 --- a/src/NHibernate/Async/Type/UInt32Type.cs +++ b/src/NHibernate/Async/Type/UInt32Type.cs @@ -14,6 +14,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/UInt64Type.cs b/src/NHibernate/Async/Type/UInt64Type.cs index d2db5e47c9..629f981f4c 100644 --- a/src/NHibernate/Async/Type/UInt64Type.cs +++ b/src/NHibernate/Async/Type/UInt64Type.cs @@ -14,6 +14,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/UriType.cs b/src/NHibernate/Async/Type/UriType.cs index ff7e316ffd..49013ef70c 100644 --- a/src/NHibernate/Async/Type/UriType.cs +++ b/src/NHibernate/Async/Type/UriType.cs @@ -10,6 +10,7 @@ using System; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/XDocType.cs b/src/NHibernate/Async/Type/XDocType.cs index 72da2d2b27..2c1c6191a0 100644 --- a/src/NHibernate/Async/Type/XDocType.cs +++ b/src/NHibernate/Async/Type/XDocType.cs @@ -11,6 +11,7 @@ using System; using System.Data.Common; using System.Xml.Linq; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/XmlDocType.cs b/src/NHibernate/Async/Type/XmlDocType.cs index 87da089118..9a0e550d4a 100644 --- a/src/NHibernate/Async/Type/XmlDocType.cs +++ b/src/NHibernate/Async/Type/XmlDocType.cs @@ -11,6 +11,7 @@ using System; using System.Data.Common; using System.Xml; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Type/AbstractCharType.cs b/src/NHibernate/Type/AbstractCharType.cs index ba2ad5bb76..879640bf3b 100644 --- a/src/NHibernate/Type/AbstractCharType.cs +++ b/src/NHibernate/Type/AbstractCharType.cs @@ -1,5 +1,6 @@ using System; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -20,12 +21,24 @@ public AbstractCharType(SqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - string dbValue = Convert.ToString(rs[index]); + if (rs.TryGetChar(index, out var dbValue)) + { + return dbValue; + } + + if (!rs.TryGetString(index, out var strValue)) + { + var locale = session.Factory.Settings.Locale; + + strValue = Convert.ToString(rs[index], locale); + } + // The check of the Length is a workaround see NH-2340 - if (dbValue.Length > 0) + if (strValue.Length > 0) { - return dbValue[0]; + return strValue[0]; } + return '\0'; // This line should never be executed } diff --git a/src/NHibernate/Type/AbstractDateTimeType.cs b/src/NHibernate/Type/AbstractDateTimeType.cs index 9deb2273d3..bf57167de0 100644 --- a/src/NHibernate/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Type/AbstractDateTimeType.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Globalization; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -64,7 +65,14 @@ protected virtual DateTime GetDateTime(DbDataReader rs, int index, ISessionImple { try { - return AdjustDateTime(Convert.ToDateTime(rs[index])); + if (!rs.TryGetDateTime(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToDateTime(rs[index], locale); + } + + return AdjustDateTime(dbValue); } catch (Exception ex) { diff --git a/src/NHibernate/Type/AbstractStringType.cs b/src/NHibernate/Type/AbstractStringType.cs index e5c073b7df..bbecbb24e0 100644 --- a/src/NHibernate/Type/AbstractStringType.cs +++ b/src/NHibernate/Type/AbstractStringType.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Data.Common; using System.Globalization; +using NHibernate.AdoNet; using NHibernate.Driver; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -73,7 +74,14 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return Convert.ToString(rs[index]); + if (!rs.TryGetString(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToString(rs[index], locale); + } + + return dbValue; } public override bool IsEqual(object x, object y) diff --git a/src/NHibernate/Type/BooleanType.cs b/src/NHibernate/Type/BooleanType.cs index d93e23e038..423fb0fca6 100644 --- a/src/NHibernate/Type/BooleanType.cs +++ b/src/NHibernate/Type/BooleanType.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using System.Runtime.CompilerServices; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -40,7 +41,14 @@ public BooleanType(AnsiStringFixedLengthSqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return GetBooleanAsObject(Convert.ToBoolean(rs[index])); + if (!rs.TryGetBoolean(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToBoolean(rs[index], locale); + } + + return GetBooleanAsObject(dbValue); } public override System.Type PrimitiveClass => typeof(bool); diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index f52071890f..ba76f2acd3 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -3,6 +3,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -24,11 +25,17 @@ public ByteType() : base(SqlTypeFactory.Byte) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return rs[index] switch + if (rs.TryGetByte(index, out var dbValue)) { + return dbValue; + } + + var locale = session.Factory.Settings.Locale; + return rs[index] switch + { BigInteger bi => (byte) bi, - var c => Convert.ToByte(c) + var c => Convert.ToByte(c, locale) }; } diff --git a/src/NHibernate/Type/CharBooleanType.cs b/src/NHibernate/Type/CharBooleanType.cs index 1224fb363d..e4db1b4106 100644 --- a/src/NHibernate/Type/CharBooleanType.cs +++ b/src/NHibernate/Type/CharBooleanType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -29,14 +30,20 @@ protected CharBooleanType(AnsiStringFixedLengthSqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - string code = Convert.ToString(rs[index]); - if (code == null) + if (!rs.TryGetString(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToString(rs[index], locale); + } + + if (dbValue == null) { return null; } else { - return GetBooleanAsObject(code.Equals(TrueString, StringComparison.InvariantCultureIgnoreCase)); + return GetBooleanAsObject(dbValue.Equals(TrueString, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/NHibernate/Type/DecimalType.cs b/src/NHibernate/Type/DecimalType.cs index e2398ec4ce..3ef69f9a4d 100644 --- a/src/NHibernate/Type/DecimalType.cs +++ b/src/NHibernate/Type/DecimalType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,7 +29,14 @@ public DecimalType(SqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return Convert.ToDecimal(rs[index]); + if (!rs.TryGetDecimal(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToDecimal(rs[index], locale); + } + + return dbValue; } public override System.Type ReturnedClass => typeof(Decimal); diff --git a/src/NHibernate/Type/DoubleType.cs b/src/NHibernate/Type/DoubleType.cs index 45b5713f52..07cd50c0f0 100644 --- a/src/NHibernate/Type/DoubleType.cs +++ b/src/NHibernate/Type/DoubleType.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,10 +29,17 @@ public DoubleType(SqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetDouble(index, out var dbValue)) + { + return dbValue; + } + + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (double) bi, - var v => Convert.ToDouble(v) + var v => Convert.ToDouble(v, locale) }; } diff --git a/src/NHibernate/Type/GuidType.cs b/src/NHibernate/Type/GuidType.cs index 2dc627d5d0..fc96faf9d4 100644 --- a/src/NHibernate/Type/GuidType.cs +++ b/src/NHibernate/Type/GuidType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -22,9 +23,9 @@ public GuidType() : base(SqlTypeFactory.Guid) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - if (rs.GetFieldType(index) == typeof (Guid)) + if (rs.TryGetGuid(index, out var dbValue)) { - return rs.GetGuid(index); + return dbValue; } if (rs.GetFieldType(index) == typeof(byte[])) @@ -32,7 +33,14 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return new Guid((byte[])(rs[index])); } - return new Guid(Convert.ToString(rs[index])); + if (!rs.TryGetString(index, out var dbString)) + { + var locale = session.Factory.Settings.Locale; + + dbString = Convert.ToString(rs[index], locale); + } + + return new Guid(dbString); } /// diff --git a/src/NHibernate/Type/Int16Type.cs b/src/NHibernate/Type/Int16Type.cs index cfd2190846..b090fe153b 100644 --- a/src/NHibernate/Type/Int16Type.cs +++ b/src/NHibernate/Type/Int16Type.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using NHibernate.AdoNet; namespace NHibernate.Type { @@ -28,12 +29,19 @@ public Int16Type() : base(SqlTypeFactory.Int16) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetInt16(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (short) bi, - var c => Convert.ToInt16(c) + var c => Convert.ToInt16(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index f19fb1148f..3c8cbf7ff2 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using NHibernate.AdoNet; namespace NHibernate.Type { @@ -28,12 +29,19 @@ public Int32Type() : base(SqlTypeFactory.Int32) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetInt32(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (int) bi, - var c => Convert.ToInt32(c) + var c => Convert.ToInt32(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/Int64Type.cs b/src/NHibernate/Type/Int64Type.cs index b86cb61944..4e2b3deb6b 100644 --- a/src/NHibernate/Type/Int64Type.cs +++ b/src/NHibernate/Type/Int64Type.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,12 +29,19 @@ public Int64Type() : base(SqlTypeFactory.Int64) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetInt64(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (long) bi, - var c => Convert.ToInt64(c) + var c => Convert.ToInt64(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/SByteType.cs b/src/NHibernate/Type/SByteType.cs index 513cacb6e7..817c714a31 100644 --- a/src/NHibernate/Type/SByteType.cs +++ b/src/NHibernate/Type/SByteType.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,12 +29,19 @@ public SByteType() : base(SqlTypeFactory.SByte) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetSByte(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (sbyte) bi, - var c => Convert.ToSByte(c) + var c => Convert.ToSByte(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/SingleType.cs b/src/NHibernate/Type/SingleType.cs index a5d56ce9ad..d5fffec0d8 100644 --- a/src/NHibernate/Type/SingleType.cs +++ b/src/NHibernate/Type/SingleType.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -34,12 +35,19 @@ public SingleType(SqlType sqlType) : base(sqlType) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetFloat(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (float) bi, - var v => Convert.ToSingle(v) + var v => Convert.ToSingle(v, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/TicksType.cs b/src/NHibernate/Type/TicksType.cs index 4fc18a007c..f21d534365 100644 --- a/src/NHibernate/Type/TicksType.cs +++ b/src/NHibernate/Type/TicksType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Type/TimeAsTimeSpanType.cs index f5218c0775..2d47923e26 100644 --- a/src/NHibernate/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Type/TimeAsTimeSpanType.cs @@ -1,10 +1,11 @@ -using System; +using System; using System.Collections; using System.Data.Common; using NHibernate.Engine; using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using NHibernate.AdoNet; namespace NHibernate.Type { @@ -35,14 +36,19 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi { try { - var value = rs[index]; - if (value is TimeSpan time) //For those dialects where DbType.Time means TimeSpan. - return time; - - // Todo: investigate if this convert should be made culture invariant, here and in other NHibernate types, - // such as AbstractDateTimeType and TimeType, or even in all other places doing such converts in NHibernate. - var dbValue = Convert.ToDateTime(value); - return dbValue.TimeOfDay; + if (rs.TryGetTimeSpan(index, out var dbTimeSpan)) + { + return dbTimeSpan; + } + + if (!rs.TryGetDateTime(index, out var dbDateTime)) + { + var locale = session.Factory.Settings.Locale; + + dbDateTime = Convert.ToDateTime(rs[index], locale); + } + + return dbDateTime.TimeOfDay; } catch (Exception ex) { diff --git a/src/NHibernate/Type/TimeSpanType.cs b/src/NHibernate/Type/TimeSpanType.cs index ed37b4629d..08d80399b1 100644 --- a/src/NHibernate/Type/TimeSpanType.cs +++ b/src/NHibernate/Type/TimeSpanType.cs @@ -5,6 +5,7 @@ using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using NHibernate.AdoNet; namespace NHibernate.Type { @@ -27,7 +28,14 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi { try { - return new TimeSpan(Convert.ToInt64(rs[index])); + if (!rs.TryGetInt64(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToInt64(rs[index], locale); + } + + return new TimeSpan(dbValue); } catch (Exception ex) { diff --git a/src/NHibernate/Type/TimeType.cs b/src/NHibernate/Type/TimeType.cs index c095ef0c0d..14a53e97c0 100644 --- a/src/NHibernate/Type/TimeType.cs +++ b/src/NHibernate/Type/TimeType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -50,20 +51,26 @@ public override string Name public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - try + if (rs.TryGetTimeSpan(index, out var dbTimeSpan)) { - if (rs[index] is TimeSpan time) //For those dialects where DbType.Time means TimeSpan. - { - return BaseDateValue.AddTicks(time.Ticks); - } - - DateTime dbValue = Convert.ToDateTime(rs[index]); - return BaseDateValue.Add(dbValue.TimeOfDay); + return BaseDateValue.AddTicks(dbTimeSpan.Ticks); } - catch (Exception ex) + + if (!rs.TryGetDateTime(index, out var dbDateTime)) { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[index]), ex); + try + { + var locale = session.Factory.Settings.Locale; + + dbDateTime = Convert.ToDateTime(rs[index], locale); + } + catch (Exception ex) + { + throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[index]), ex); + } } + + return BaseDateValue.Add(dbDateTime.TimeOfDay); } public override System.Type ReturnedClass diff --git a/src/NHibernate/Type/UInt16Type.cs b/src/NHibernate/Type/UInt16Type.cs index c37bbfaca7..398ad3818b 100644 --- a/src/NHibernate/Type/UInt16Type.cs +++ b/src/NHibernate/Type/UInt16Type.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,12 +29,19 @@ public UInt16Type() : base(SqlTypeFactory.UInt16) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetUInt16(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (ushort) bi, - var c => Convert.ToUInt16(c) + var c => Convert.ToUInt16(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/UInt32Type.cs b/src/NHibernate/Type/UInt32Type.cs index e0e30b65f2..6f95f96942 100644 --- a/src/NHibernate/Type/UInt32Type.cs +++ b/src/NHibernate/Type/UInt32Type.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -28,12 +29,19 @@ public UInt32Type() : base(SqlTypeFactory.UInt32) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetUInt32(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (uint) bi, - var c => Convert.ToUInt32(c) + var c => Convert.ToUInt32(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/UInt64Type.cs b/src/NHibernate/Type/UInt64Type.cs index 8d0c05d20b..abc4d86dfa 100644 --- a/src/NHibernate/Type/UInt64Type.cs +++ b/src/NHibernate/Type/UInt64Type.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Numerics; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -27,12 +28,19 @@ public UInt64Type() : base(SqlTypeFactory.UInt64) public override object Get(DbDataReader rs, int index, ISessionImplementor session) { + if (rs.TryGetUInt64(index, out var dbValue)) + { + return dbValue; + } + try { + var locale = session.Factory.Settings.Locale; + return rs[index] switch { BigInteger bi => (ulong)bi, - var c => Convert.ToUInt64(c) + var c => Convert.ToUInt64(c, locale) }; } catch (Exception ex) diff --git a/src/NHibernate/Type/UriType.cs b/src/NHibernate/Type/UriType.cs index 48fbe91a9c..f1b1752701 100644 --- a/src/NHibernate/Type/UriType.cs +++ b/src/NHibernate/Type/UriType.cs @@ -1,5 +1,6 @@ using System; using System.Data.Common; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -51,7 +52,14 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return StringToObject(Convert.ToString(rs[index])); + if (!rs.TryGetString(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + dbValue = Convert.ToString(rs[index], locale); + } + + return StringToObject(dbValue); } /// diff --git a/src/NHibernate/Type/XDocType.cs b/src/NHibernate/Type/XDocType.cs index 69912c8ec7..197123d76b 100644 --- a/src/NHibernate/Type/XDocType.cs +++ b/src/NHibernate/Type/XDocType.cs @@ -1,6 +1,7 @@ using System; using System.Data.Common; using System.Xml.Linq; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -38,12 +39,18 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme /// public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - // according to documentation, GetValue should return a string, at least for MsSQL - // hopefully all DataProvider has the same behaviour - string xmlString = Convert.ToString(rs.GetValue(index)); + if (!rs.TryGetString(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + // according to documentation, GetValue should return a string, at least for MsSQL + // hopefully all DataProvider has the same behaviour + dbValue = Convert.ToString(rs.GetValue(index), locale); + } + // 6.0 TODO: inline the call. #pragma warning disable 618 - return FromStringValue(xmlString); + return FromStringValue(dbValue); #pragma warning restore 618 } diff --git a/src/NHibernate/Type/XmlDocType.cs b/src/NHibernate/Type/XmlDocType.cs index d4b26317f2..f66bd08b2c 100644 --- a/src/NHibernate/Type/XmlDocType.cs +++ b/src/NHibernate/Type/XmlDocType.cs @@ -1,6 +1,7 @@ using System; using System.Data.Common; using System.Xml; +using NHibernate.AdoNet; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -37,12 +38,18 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme /// public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - // according to documentation, GetValue should return a string, at least for MsSQL - // hopefully all DataProvider has the same behaviour - string xmlString = Convert.ToString(rs.GetValue(index)); + if (!rs.TryGetString(index, out var dbValue)) + { + var locale = session.Factory.Settings.Locale; + + // according to documentation, GetValue should return a string, at least for MsSQL + // hopefully all DataProvider has the same behaviour + dbValue = Convert.ToString(rs.GetValue(index), locale); + } + // 6.0 TODO: inline the call. #pragma warning disable 618 - return FromStringValue(xmlString); + return FromStringValue(dbValue); #pragma warning restore 618 } From 6dbd4f01741927d52333ef4711ccd4ee747000fe Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 29 May 2024 12:45:08 -0400 Subject: [PATCH 34/54] GH-3530: Fix failing BooleanType test due to changed behavior of the BooleanType. --- src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs index 2c394a4247..1106e7f525 100644 --- a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs @@ -59,6 +59,9 @@ public void GetByIndex(bool expected) BooleanType type = NHibernateUtil.Boolean; var session = Substitute.For(); var reader = Substitute.For(); + + reader.GetBoolean(index0).Returns(expected); + reader.GetBoolean(index1).Returns(expected); reader[index0].Returns(expected); reader[index1].Returns(expected); @@ -78,8 +81,11 @@ public void GetByName(bool expected) var type = NHibernateUtil.Boolean; var session = Substitute.For(); var reader = Substitute.For(); + reader.GetOrdinal(name0).Returns(0); reader.GetOrdinal(name1).Returns(1); + reader.GetBoolean(0).Returns(expected); + reader.GetBoolean(1).Returns(expected); reader[0].Returns(expected); reader[1].Returns(expected); From 97a516d6eacbd7bff2959c86aacf6f514059dcca Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Wed, 29 May 2024 13:29:34 -0400 Subject: [PATCH 35/54] GH-3530: Fix failing CharBooleanType test due to change in behavior of the CharBooleanType. --- src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs index d07c2856aa..ccfacb9e2a 100644 --- a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data.Common; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -19,6 +19,9 @@ public void GetByIndex(bool expected) CharBooleanType type =new CharBooleanTypeStub(); var session = Substitute.For(); var reader = Substitute.For(); + + reader.GetString(index0).Returns(expected.ToString()); + reader.GetString(index1).Returns(expected.ToString()); reader[index0].Returns(expected.ToString()); reader[index1].Returns(expected.ToString()); From f8eb2a6e5d5eb4d8dfb5cabfa5c71776c20e9e7f Mon Sep 17 00:00:00 2001 From: David Ellingsworth Date: Thu, 30 May 2024 11:10:51 -0400 Subject: [PATCH 36/54] GH-3530: Add tests for float type. --- .../Async/NHSpecificTest/GH3530/Fixture.cs | 13 ++++++++++++- .../NHSpecificTest/GH3530/Entities.cs | 1 + .../NHSpecificTest/GH3530/Fixture.cs | 13 ++++++++++++- .../NHSpecificTest/GH3530/Mappings.hbm.xml | 4 ++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs index db63b5d4cf..bd726ebed1 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3530/Fixture.cs @@ -53,6 +53,7 @@ protected override void CreateSchema() CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + CreateTable("Float"); base.CreateSchema(); } @@ -181,7 +182,7 @@ public async Task TestDoubleAsync(CultureInfo from, CultureInfo to) double doubleValue = 12.3d; await (PerformTestAsync(from, to, doubleValue, - (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected {expected} but was {actual}\n") )); } @@ -194,6 +195,16 @@ public async Task TestIntegerAsync(CultureInfo from, CultureInfo to) await (PerformTestAsync(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual))); } + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task TestFloatAsync(CultureInfo from, CultureInfo to) + { + float floatValue = 12.3f; + + await (PerformTestAsync(from, to, floatValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < float.Epsilon, $"Expected {expected} but was {actual}\n") + )); + } + private CultureInfo CurrentCulture { get => CultureInfo.CurrentCulture; diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs index ef740ce446..c521c48831 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Entities.cs @@ -17,4 +17,5 @@ public class DateTimeEntity : DataEntity { } public class DoubleEntity : DataEntity { } public class DecimalEntity : DataEntity { } +public class FloatEntity : DataEntity { } public class NHDateTimeEntity : DataEntity { } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs index 0f53187c51..175dd9e03b 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Fixture.cs @@ -41,6 +41,7 @@ protected override void CreateSchema() CreateTable("DateTime"); CreateTable("Double"); CreateTable("Decimal"); + CreateTable("Float"); base.CreateSchema(); } @@ -169,7 +170,7 @@ public void TestDouble(CultureInfo from, CultureInfo to) double doubleValue = 12.3d; PerformTest(from, to, doubleValue, - (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected: {expected}\nBut was: {actual}\n") + (expected, actual) => Assert.True(Math.Abs(expected - actual) < double.Epsilon, $"Expected {expected} but was {actual}\n") ); } @@ -182,6 +183,16 @@ public void TestInteger(CultureInfo from, CultureInfo to) PerformTest(from, to, integerValue, (expected, actual) => Assert.AreEqual(expected, actual)); } + [Test, TestCaseSource(nameof(GetTestCases))] + public void TestFloat(CultureInfo from, CultureInfo to) + { + float floatValue = 12.3f; + + PerformTest(from, to, floatValue, + (expected, actual) => Assert.True(Math.Abs(expected - actual) < float.Epsilon, $"Expected {expected} but was {actual}\n") + ); + } + private CultureInfo CurrentCulture { get => CultureInfo.CurrentCulture; diff --git a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml index 9de8d6eb69..2053587ed5 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3530/Mappings.hbm.xml @@ -23,6 +23,10 @@ + + + +