From 770b3650714223669cc629ee4b9d91dee25e5422 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 4 Jul 2023 22:16:12 +0300 Subject: [PATCH 001/128] Fix getting of initialized proxies for no-proxy associations outside of session scope (#3347) Fixes #1267 --- .../GhostProperty/GhostPropertyFixture.cs | 49 +++++++++++++++++++ .../GhostProperty/GhostPropertyFixture.cs | 49 +++++++++++++++++++ .../GhostProperty/Mappings.hbm.xml | 1 + src/NHibernate.Test/GhostProperty/Order.cs | 3 +- .../Intercept/AbstractFieldInterceptor.cs | 48 +++++++++--------- 5 files changed, 127 insertions(+), 23 deletions(-) diff --git a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs index 12ab309a529..281ed163c32 100644 --- a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs @@ -253,5 +253,54 @@ public async Task WillFetchJoinInSingleHqlQueryAsync() Assert.DoesNotThrow(() => { var x = order.Payment; }); } + + [Test(Description = "GH-1267(NH-3047)")] + public async Task WillFetchJoinInAdditionalHqlQueryAsync() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + order = (await (s.CreateQuery("from Order o where o.Id = 1").ListAsync()))[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + // ... then join-fetch the related payment + await (s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").ListAsync()); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } + + [Test(Description = "GH-1267(NH-3047)")] + public async Task WillFetchJoinWithCriteriaAsync() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + + var query = s.CreateCriteria(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = (await (query.ListAsync()))[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + query2.Add(Criterion.Restrictions.Eq("Id", 1)); + query2.Fetch(SelectMode.Fetch, "Payment"); + await (query2.ListAsync()); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } } } diff --git a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs index 13a3c6e0e7b..70e1e21613e 100644 --- a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs @@ -260,5 +260,54 @@ public void WillFetchJoinInSingleHqlQuery() Assert.DoesNotThrow(() => { var x = order.Payment; }); } + + [Test(Description = "GH-1267(NH-3047)")] + public void WillFetchJoinInAdditionalHqlQuery() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + order = s.CreateQuery("from Order o where o.Id = 1").List()[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + // ... then join-fetch the related payment + s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").List(); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } + + [Test(Description = "GH-1267(NH-3047)")] + public void WillFetchJoinWithCriteria() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + + var query = s.CreateCriteria(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = query.List()[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + query2.Add(Criterion.Restrictions.Eq("Id", 1)); + query2.Fetch(SelectMode.Fetch, "Payment"); + query2.List(); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } } } diff --git a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml index 2594f4c5afa..6790652371b 100644 --- a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml +++ b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml @@ -19,6 +19,7 @@ + diff --git a/src/NHibernate.Test/GhostProperty/Order.cs b/src/NHibernate.Test/GhostProperty/Order.cs index a0ef5e9a01b..99c0465c1cc 100644 --- a/src/NHibernate.Test/GhostProperty/Order.cs +++ b/src/NHibernate.Test/GhostProperty/Order.cs @@ -18,8 +18,9 @@ public virtual Payment Payment public abstract class Payment { public virtual int Id { get; set; } + public virtual string Type { get; set; } } public class WireTransfer : Payment{} public class CreditCard : Payment { } -} \ No newline at end of file +} diff --git a/src/NHibernate/Intercept/AbstractFieldInterceptor.cs b/src/NHibernate/Intercept/AbstractFieldInterceptor.cs index 87ede553e0a..898805360d9 100644 --- a/src/NHibernate/Intercept/AbstractFieldInterceptor.cs +++ b/src/NHibernate/Intercept/AbstractFieldInterceptor.cs @@ -128,39 +128,43 @@ public object Intercept(object target, string fieldName, object value, bool sett return InvokeImplementation; } - if (IsInitializedField(fieldName)) + if (IsUninitializedProperty(fieldName)) { - return value; - } + if (session == null) + { + throw new LazyInitializationException(EntityName, null, string.Format("entity with lazy properties is not associated with a session. entity-name:'{0}' property:'{1}'", EntityName, fieldName)); + } + if (!session.IsOpen || !session.IsConnected) + { + throw new LazyInitializationException(EntityName, null, string.Format("session is not connected. entity-name:'{0}' property:'{1}'", EntityName, fieldName)); + } - if (session == null) - { - throw new LazyInitializationException(EntityName, null, string.Format("entity with lazy properties is not associated with a session. entity-name:'{0}' property:'{1}'", EntityName, fieldName)); - } - if (!session.IsOpen || !session.IsConnected) - { - throw new LazyInitializationException(EntityName, null, string.Format("session is not connected. entity-name:'{0}' property:'{1}'", EntityName, fieldName)); + return InitializeField(fieldName, target); } - if (IsUninitializedProperty(fieldName)) + if (!IsUninitializedAssociation(fieldName)) { - return InitializeField(fieldName, target); + return value; } - if (value.IsProxy() && IsUninitializedAssociation(fieldName)) + if (value is INHibernateProxy nhproxy) { - var nhproxy = value as INHibernateProxy; value = InitializeOrGetAssociation(nhproxy, fieldName); - // Set the property value in order to be accessible when the session is closed - var persister = session.Factory.GetEntityPersister(entityName); - persister.SetPropertyValue( - target, - persister.EntityMetamodel.BytecodeEnhancementMetadata.UnwrapProxyPropertiesMetadata.GetUnwrapProxyPropertyIndex(fieldName), - value); + if (session?.Factory.IsClosed == false) + { + // Set the property value in order to be accessible when the session is closed + var persister = session.Factory.GetEntityPersister(entityName); + persister.SetPropertyValue( + target, + persister.EntityMetamodel.GetPropertyIndex(fieldName), + value); + } return value; } - return InvokeImplementation; + + loadedUnwrapProxyFieldNames.Add(fieldName); + return value; } private bool IsUninitializedAssociation(string fieldName) @@ -181,7 +185,7 @@ private object InitializeOrGetAssociation(INHibernateProxy value, string fieldNa value.HibernateLazyInitializer.Unwrap = true; // means that future Load/Get from the session will get the implementation loadedUnwrapProxyFieldNames.Add(fieldName); } - return value.HibernateLazyInitializer.GetImplementation(session); + return value.HibernateLazyInitializer.GetImplementation(); } private object InitializeField(string fieldName, object target) From 1cfead763d32b216abc666e5ce27df5c815d1cce Mon Sep 17 00:00:00 2001 From: dennis-gr Date: Wed, 5 Jul 2023 07:53:37 +0000 Subject: [PATCH 002/128] Added MySQL8Dialect and MySQL8InnoDBDialect (#3236) --- src/NHibernate/Dialect/MySQL8Dialect.cs | 9 +++++++++ src/NHibernate/Dialect/MySQL8InnoDBDialect.cs | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/NHibernate/Dialect/MySQL8Dialect.cs create mode 100644 src/NHibernate/Dialect/MySQL8InnoDBDialect.cs diff --git a/src/NHibernate/Dialect/MySQL8Dialect.cs b/src/NHibernate/Dialect/MySQL8Dialect.cs new file mode 100644 index 00000000000..32462a73a31 --- /dev/null +++ b/src/NHibernate/Dialect/MySQL8Dialect.cs @@ -0,0 +1,9 @@ +using System.Data; + +namespace NHibernate.Dialect +{ + public class MySQL8Dialect : MySQL57Dialect + { + public MySQL8Dialect() => RegisterColumnType(DbType.Boolean, "BOOLEAN"); + } +} diff --git a/src/NHibernate/Dialect/MySQL8InnoDBDialect.cs b/src/NHibernate/Dialect/MySQL8InnoDBDialect.cs new file mode 100644 index 00000000000..5af5465aa40 --- /dev/null +++ b/src/NHibernate/Dialect/MySQL8InnoDBDialect.cs @@ -0,0 +1,11 @@ +namespace NHibernate.Dialect +{ + public class MySQL8InnoDBDialect : MySQL8Dialect + { + public override bool SupportsCascadeDelete => true; + + public override string TableTypeString => " ENGINE=InnoDB"; + + public override bool HasSelfReferentialForeignKeyBug => true; + } +} From e192d4d110c8fb21011347e1c282ba01581b4132 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 21:11:22 +1000 Subject: [PATCH 003/128] Migrate renovate config (#3353) --- .github/renovate.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 689fc32f5d9..98411a821c0 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,7 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "config:recommended" ], "configMigration": true, "pruneStaleBranches": false, @@ -15,9 +15,11 @@ ], "packageRules": [ { - "matchSourceUrls": ["https://github.com/nunit/nunit"], + "matchSourceUrls": [ + "https://github.com/nunit/nunit" + ], "groupName": "NUnit" - }, + }, { "matchPackageNames": [ "Microsoft.AspNetCore", From 2cd54e6a835d9179d7f4bdf38c94d6de846efd65 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 13 Jul 2023 10:57:22 +0300 Subject: [PATCH 004/128] Fix fetching properties from unmapped base class (#3357) Fixes #3352 --- .../FetchFromNotMappedBaseClassFixture.cs | 174 ++++++++++++++++++ .../NHSpecificTest/GH3352/Entity.cs | 31 ++++ .../FetchFromNotMappedBaseClassFixture.cs | 163 ++++++++++++++++ .../ResultOperatorProcessors/ProcessFetch.cs | 16 +- 4 files changed, 378 insertions(+), 6 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs new file mode 100644 index 00000000000..07b1a219f83 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs @@ -0,0 +1,174 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + using System.Threading.Tasks; + [TestFixture] + public class FetchFromNotMappedBaseClassFixtureAsync : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name, m => m.Lazy(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.ManyToOne(x => x.Parent, m => m.ForeignKey("none")); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Component(x => x.Component); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.ManyToOne(x => x.Entity, m => m.ForeignKey("none")); + rc.Lazy(true); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var np = new EntityComponentMapped { Component = new Component { Field = "x" } }; + session.Save(np); + var e = new EntityParentMapped { Parent = np }; + session.Save(e); + var nameMapped = new EntityNameMapped { Name = "lazy" }; + session.Save(nameMapped); + np.Component.Entity = nameMapped; + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task CanFetchLazyComponentFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Component).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [Test] + public async Task CanFetchLazyComponentThenEntityFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query() + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanFetchLazyPropertyFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Name).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Name))); + Assert.That(result.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanThenFetchLazyComponentFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Parent).ThenFetch(x => x.Component).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0].Parent; + Assert.That(NHibernateUtil.IsInitialized(result), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [KnownBug("GH-3356")] + [Test(Description = "GH-3356" )] + public async Task FetchAfterSelectAsync() + { + using var log = new SqlLogSpy(); + + using var s = OpenSession(); + var list = await (s.Query() + .Select(x => x.Parent) + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToListAsync()); + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanFetchEntityFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Parent).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + Assert.That(list[0].Parent, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(list[0].Parent)); + } + + [Test] + public void FetchNotMappedAssociationThrowsAsync() + { + using var session = OpenSession(); + var query = session.Query().Fetch(x => x.Parent); + + Assert.ThrowsAsync(() => query.ToListAsync()); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs new file mode 100644 index 00000000000..dc7800cc977 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs @@ -0,0 +1,31 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual EntityComponentMapped Parent { get; set; } + public virtual Component Component { get; set; } + } + + public class EntityNameMapped : Entity + { + } + + public class EntityParentMapped : Entity + { + } + + public class EntityComponentMapped : Entity + { + } + + public class Component + { + public string Field { get; set; } + + public EntityNameMapped Entity { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs new file mode 100644 index 00000000000..5b66027c963 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs @@ -0,0 +1,163 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + [TestFixture] + public class FetchFromNotMappedBaseClassFixture : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name, m => m.Lazy(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.ManyToOne(x => x.Parent, m => m.ForeignKey("none")); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Component(x => x.Component); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.ManyToOne(x => x.Entity, m => m.ForeignKey("none")); + rc.Lazy(true); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var np = new EntityComponentMapped { Component = new Component { Field = "x" } }; + session.Save(np); + var e = new EntityParentMapped { Parent = np }; + session.Save(e); + var nameMapped = new EntityNameMapped { Name = "lazy" }; + session.Save(nameMapped); + np.Component.Entity = nameMapped; + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void CanFetchLazyComponentFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Component).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [Test] + public void CanFetchLazyComponentThenEntityFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query() + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanFetchLazyPropertyFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Name).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Name))); + Assert.That(result.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanThenFetchLazyComponentFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Parent).ThenFetch(x => x.Component).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0].Parent; + Assert.That(NHibernateUtil.IsInitialized(result), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [KnownBug("GH-3356")] + [Test(Description = "GH-3356" )] + public void FetchAfterSelect() + { + using var log = new SqlLogSpy(); + + using var s = OpenSession(); + var list = s.Query() + .Select(x => x.Parent) + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToList(); + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanFetchEntityFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Parent).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + Assert.That(list[0].Parent, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(list[0].Parent)); + } + + [Test] + public void FetchNotMappedAssociationThrows() + { + using var session = OpenSession(); + var query = session.Query().Fetch(x => x.Parent); + + Assert.Throws(() => query.ToList()); + } + } +} diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs index 31401f7df81..7c18f9476f4 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using NHibernate.Hql.Ast; +using NHibernate.Persister.Entity; using NHibernate.Type; using Remotion.Linq.EagerFetching; @@ -54,15 +55,18 @@ private void Process( .GetClassMetadata(resultOperator.RelationMember.ReflectedType); if (metadata == null) { - var entityName = queryModelVisitor.VisitorParameters.SessionFactory.GetImplementors( - resultOperator.RelationMember.ReflectedType.FullName).FirstOrDefault(); - if (!string.IsNullOrEmpty(entityName)) + foreach (var entityName in queryModelVisitor.VisitorParameters.SessionFactory + .GetImplementors(resultOperator.RelationMember.ReflectedType.FullName)) { - metadata = queryModelVisitor.VisitorParameters.SessionFactory.GetClassMetadata(entityName); + if (queryModelVisitor.VisitorParameters.SessionFactory.GetClassMetadata(entityName) is IPropertyMapping propertyMapping + && propertyMapping.TryToType(resultOperator.RelationMember.Name, out propType)) + break; } } - - propType = metadata?.GetPropertyType(resultOperator.RelationMember.Name); + else + { + propType = metadata.GetPropertyType(resultOperator.RelationMember.Name); + } } if (propType != null && !propType.IsAssociationType) From 8c0a664ee5bde1de2e496aebdc3ec64abcc59f77 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 13 Jul 2023 16:42:14 +0300 Subject: [PATCH 005/128] Fix exception accessing indexer property for field interceptor proxy (#3358) Fixes #3354 --- .../Async/LazyProperty/LazyPropertyFixture.cs | 3 +++ src/NHibernate.Test/LazyProperty/Book.cs | 6 ++++++ src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs | 3 +++ src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs | 4 ++-- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs b/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs index f99b79e5420..78ff4a50a16 100644 --- a/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs +++ b/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs @@ -230,6 +230,9 @@ public async Task CanGetValueForNonLazyPropertyAsync() Assert.That(book.Name, Is.EqualTo("some name")); Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?")); Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False); + //GH-3354 Exception accessing indexer property + Assert.That(book[0], Is.EqualTo(0)); + Assert.DoesNotThrow(() => book[0] = 0); } } diff --git a/src/NHibernate.Test/LazyProperty/Book.cs b/src/NHibernate.Test/LazyProperty/Book.cs index 3dcfe73c567..10eb7d241f2 100644 --- a/src/NHibernate.Test/LazyProperty/Book.cs +++ b/src/NHibernate.Test/LazyProperty/Book.cs @@ -28,5 +28,11 @@ public virtual byte[] NoSetterImage public virtual string FieldInterceptor { get; set; } public virtual IList Words { get; set; } + + public virtual int this[int i] + { + get { return i;} + set { } + } } } diff --git a/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs b/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs index 302271f41a3..1b588dee440 100644 --- a/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs +++ b/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs @@ -225,6 +225,9 @@ public void CanGetValueForNonLazyProperty() Assert.That(book.Name, Is.EqualTo("some name")); Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?")); Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False); + //GH-3354 Exception accessing indexer property + Assert.That(book[0], Is.EqualTo(0)); + Assert.DoesNotThrow(() => book[0] = 0); } } diff --git a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs index 9e1326c3b2a..f3255a2aaab 100644 --- a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs +++ b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs @@ -94,11 +94,11 @@ public static TypeInfo CreateProxyType(System.Type baseType) private static void CreateProxiedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo fieldInterceptorField) { - if (ReflectHelper.IsPropertyGet(method)) + if (ReflectHelper.IsPropertyGet(method) && method.GetParameters().Length == 0) { ImplementGet(typeBuilder, method, fieldInterceptorField); } - else if (ReflectHelper.IsPropertySet(method)) + else if (ReflectHelper.IsPropertySet(method) && method.GetParameters().Length == 1) { ImplementSet(typeBuilder, method, fieldInterceptorField); } From 9302ad467bba443176f2bfb6b85855c1d1e1e504 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 13 Jul 2023 22:45:24 +0300 Subject: [PATCH 006/128] Update NHibernate.props Enable 5.4.4 dev builds --- build-common/NHibernate.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 62b650cb650..87df1acdbd8 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,9 +3,9 @@ 5.4 - 3 + 4 - + dev 9.0 $(NhVersion).$(VersionPatch) From 5e1ff9f3d443dc6448e890ff3ecab8a607858ef1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 17:09:20 +0300 Subject: [PATCH 007/128] Update NUnit to v3.13.3 (#3088) --- .../NHibernate.Test.VisualBasic.vbproj | 4 ++-- src/NHibernate.Test/NHibernate.Test.csproj | 4 ++-- .../NHibernate.TestDatabaseSetup.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index 95d2047bc2b..6859ccff6d7 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -27,11 +27,11 @@ - + - + diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 95f20cc3e32..f2535b6d1a5 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -62,7 +62,7 @@ - + @@ -86,7 +86,7 @@ - + diff --git a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj index 12c33643f9a..6d6174c26ee 100644 --- a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj +++ b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj @@ -15,11 +15,11 @@ - + - + From 04c4d5225bdc107e0965542ddb1005da64121f2c Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sun, 16 Jul 2023 17:56:37 +0000 Subject: [PATCH 008/128] Fix incorrect parameter length for char types in MicrosoftDataSqlClientDriver (#3360) * Run tests for MicrosoftDataSqlClientDriver * Fix character parameter lengths for MicrosoftDataSqlClientDriver --- .github/workflows/NetCoreTests.yml | 4 ++++ appveyor.yml | 4 ++++ psake.ps1 | 13 +++++++++++++ .../TestDatabaseSetup.cs | 1 + .../Driver/MicrosoftDataSqlClientDriver.cs | 16 ++++++++++++++-- src/NHibernate/Driver/SqlClientDriver.cs | 4 ++-- teamcity.build | 11 +++++++++++ 7 files changed, 49 insertions(+), 4 deletions(-) diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index c88177b97e9..478eabf8f9a 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -12,6 +12,10 @@ jobs: CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" DB_INIT: | docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; + - DB: SqlServer2008-MicrosoftDataSqlClientDriver + CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" + DB_INIT: | + docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; - DB: PostgreSQL CONNECTION_STRING: "Host=localhost;Username=nhibernate;Password=nhibernate;Database=nhibernate;Enlist=true;" DB_INIT: | diff --git a/appveyor.yml b/appveyor.yml index a73e841f7e6..cf5da450722 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,8 @@ environment: matrix: - DB: SqlServer2008 CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; + - DB: SqlServer2008-MicrosoftDataSqlClientDriver + CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; - DB: PostgreSQL CONNECTION_STRING: Host=localhost;Port=5432;Username=postgres;Password=Password12!;Database=nhibernate;Enlist=true; - DB: Firebird @@ -73,7 +75,9 @@ before_test: Start-Service 'postgresql-x64-10' } 'SqlServer2008' { Start-Service 'MSSQL$SQL2017' } + 'SqlServer2008-MicrosoftDataSqlClientDriver' { Start-Service 'MSSQL$SQL2017' } 'SqlServer2012' { Start-Service 'MSSQL$SQL2017' } + 'SqlServer2012-MicrosoftDataSqlClientDriver' { Start-Service 'MSSQL$SQL2017' } 'SQLite' { } } test_script: diff --git a/psake.ps1 b/psake.ps1 index 34fa3e2ea37..16f7a267f14 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -63,9 +63,22 @@ Task Set-Configuration { }; 'SqlServer2008' = @{ 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;' + 'connection.driver_class' = 'NHibernate.Driver.Sql2008ClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2008Dialect' }; 'SqlServer2012' = @{ 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;'; + 'connection.driver_class' = 'NHibernate.Driver.Sql2008ClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2012Dialect' + }; + 'SqlServer2008-MicrosoftDataSqlClientDriver' = @{ + 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;' + 'connection.driver_class' = 'NHibernate.Driver.MicrosoftDataSqlClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2008Dialect' + }; + 'SqlServer2012-MicrosoftDataSqlClientDriver' = @{ + 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;'; + 'connection.driver_class' = 'NHibernate.Driver.MicrosoftDataSqlClientDriver'; 'dialect' = 'NHibernate.Dialect.MsSql2012Dialect' }; 'Oracle' = @{ diff --git a/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs b/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs index deea09fb3a5..0856f339d02 100644 --- a/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs +++ b/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs @@ -23,6 +23,7 @@ public class DatabaseSetup { {"NHibernate.Driver.SqlClientDriver", SetupSqlServer}, {"NHibernate.Driver.Sql2008ClientDriver", SetupSqlServer}, + {"NHibernate.Driver.MicrosoftDataSqlClientDriver", SetupSqlServer}, {"NHibernate.Driver.FirebirdClientDriver", SetupFirebird}, {"NHibernate.Driver.NpgsqlDriver", SetupNpgsql}, {"NHibernate.Driver.OracleDataClientDriver", SetupOracle}, diff --git a/src/NHibernate/Driver/MicrosoftDataSqlClientDriver.cs b/src/NHibernate/Driver/MicrosoftDataSqlClientDriver.cs index 1c4ad3d9fc0..e2e12674e3d 100644 --- a/src/NHibernate/Driver/MicrosoftDataSqlClientDriver.cs +++ b/src/NHibernate/Driver/MicrosoftDataSqlClientDriver.cs @@ -112,7 +112,7 @@ protected override void InitializeParameter(DbParameter dbParam, string name, Sq case DbType.AnsiStringFixedLength: dbParam.Size = IsAnsiText(dbParam, sqlType) ? MsSql2000Dialect.MaxSizeForAnsiClob - : MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString; + : IsChar(dbParam, sqlType) ? sqlType.Length : MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString; break; case DbType.Binary: dbParam.Size = IsBlob(dbParam, sqlType) @@ -130,7 +130,7 @@ protected override void InitializeParameter(DbParameter dbParam, string name, Sq case DbType.StringFixedLength: dbParam.Size = IsText(dbParam, sqlType) ? MsSql2000Dialect.MaxSizeForClob - : MsSql2000Dialect.MaxSizeForLengthLimitedString; + : IsChar(dbParam, sqlType) ? sqlType.Length : MsSql2000Dialect.MaxSizeForLengthLimitedString; break; case DbType.DateTime2: dbParam.Size = MsSql2000Dialect.MaxDateTime2; @@ -199,6 +199,18 @@ protected static bool IsBlob(DbParameter dbParam, SqlType sqlType) return sqlType is BinaryBlobSqlType || DbType.Binary == dbParam.DbType && sqlType.LengthDefined && sqlType.Length > MsSql2000Dialect.MaxSizeForLengthLimitedBinary; } + + /// + /// Interprets if a parameter is a character (for the purposes of setting its default size) + /// + /// The parameter + /// The of the parameter + /// True, if the parameter should be interpreted as a character, otherwise False + protected static bool IsChar(DbParameter dbParam, SqlType sqlType) + { + return sqlType.LengthDefined && sqlType.Length == 1 && + (dbParam.DbType == DbType.StringFixedLength || dbParam.DbType == DbType.AnsiStringFixedLength); + } /// public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor session) diff --git a/src/NHibernate/Driver/SqlClientDriver.cs b/src/NHibernate/Driver/SqlClientDriver.cs index 1002005395d..a3da3a4db73 100644 --- a/src/NHibernate/Driver/SqlClientDriver.cs +++ b/src/NHibernate/Driver/SqlClientDriver.cs @@ -295,8 +295,8 @@ protected static bool IsBlob(DbParameter dbParam, SqlType sqlType) /// True, if the parameter should be interpreted as a character, otherwise False protected static bool IsChar(DbParameter dbParam, SqlType sqlType) { - return (DbType.StringFixedLength == dbParam.DbType || DbType.AnsiStringFixedLength == dbParam.DbType) && - sqlType.LengthDefined && sqlType.Length == 1; + return sqlType.LengthDefined && sqlType.Length == 1 && + (dbParam.DbType == DbType.StringFixedLength || dbParam.DbType == DbType.AnsiStringFixedLength); } public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor session) diff --git a/teamcity.build b/teamcity.build index 7e90e13e430..b8125f5dfe5 100644 --- a/teamcity.build +++ b/teamcity.build @@ -67,11 +67,22 @@ + + + + + + + + + + + From 7b2d5d4e57f7ab02f936fdbeb997a2ffd506ef96 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 12:15:41 +0300 Subject: [PATCH 009/128] Update dependency Microsoft.AspNetCore.OData to v7.7.0 (#3092) --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index f2535b6d1a5..f78ed49c96b 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -55,7 +55,7 @@ - + From 1b13f03726de7c5c4a6d080b289445c22259694b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 23:01:04 +0200 Subject: [PATCH 010/128] Update dependency System.Linq.Dynamic.Core to v1.2.19 (#3099) --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index f78ed49c96b..70d1e2330c7 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -60,7 +60,7 @@ - + From 743d93d4b6c23149f0de079b326eda2a8e703d05 Mon Sep 17 00:00:00 2001 From: csharper2010 Date: Tue, 18 Jul 2023 09:54:59 +0200 Subject: [PATCH 011/128] Fixes cascading orphan delete on versioned entity (#3326) VisitCollectionsBeforeSave must be called no matter if substitute is already true. On versioned entities this is always the case. Fixes #3325 Co-authored-by: Alex Zaytsev Co-authored-by: Roman Artiukhin --- .../AbstractEntityWithManyToManyTest.cs | 2 +- .../Async/NHSpecificTest/GH3325/Fixture.cs | 121 ++++++++++++++++++ .../Async/ReadOnly/ReadOnlyVersionedNodes.cs | 9 +- .../AbstractEntityWithManyToManyTest.cs | 2 +- .../NHSpecificTest/GH3325/Entity.cs | 26 ++++ .../NHSpecificTest/GH3325/Fixture.cs | 109 ++++++++++++++++ .../NHSpecificTest/GH3325/Mappings.hbm.xml | 31 +++++ .../ReadOnly/ReadOnlyVersionedNodes.cs | 9 +- .../Default/AbstractSaveEventListener.cs | 2 +- .../Default/AbstractSaveEventListener.cs | 2 +- 10 files changed, 299 insertions(+), 14 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index a5e9222fd42..2432a8705c1 100644 --- a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -496,7 +496,7 @@ public async Task CreateWithNonEmptyManyToManyCollectionMergeWithNewElementAsync s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs new file mode 100644 index 00000000000..da325b51328 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// +// 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.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task CanRemoveChildAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildAfterSaveAndExplicitFlushAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlushAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + private async Task AssertParentIsChildlessAsync(Guid parentId, Guid childId, CancellationToken cancellationToken = default(CancellationToken)) + { + using var session = OpenSession(); + + var parent = await (session.GetAsync(parentId, cancellationToken)); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = await (session.GetAsync(childId, cancellationToken)); + Assert.That(child, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs index def3e860c51..2adb9224758 100644 --- a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs @@ -558,7 +558,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -571,7 +571,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); @@ -609,7 +609,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -622,8 +622,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); diff --git a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index 1e77060ab44..be22e24c08a 100644 --- a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -485,7 +485,7 @@ public void CreateWithNonEmptyManyToManyCollectionMergeWithNewElement() s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs new file mode 100644 index 00000000000..e63e6c3819b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual int Version { get; set; } = -1; + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class EntityWithoutDeleteOrphan + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class ChildEntity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs new file mode 100644 index 00000000000..a0ba4123dac --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void CanRemoveChildAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildAfterSaveAndExplicitFlush() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + session.Flush(); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlush() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + session.Flush(); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + private void AssertParentIsChildless(Guid parentId, Guid childId) + { + using var session = OpenSession(); + + var parent = session.Get(parentId); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = session.Get(childId); + Assert.That(child, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml new file mode 100644 index 00000000000..712bf46fb1f --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs index 6ef31d2ae23..0773dd3e83e 100644 --- a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs @@ -624,7 +624,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -637,7 +637,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); @@ -675,7 +675,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -688,8 +688,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); diff --git a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs index f86e9a6c158..0d7213cc0ad 100644 --- a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs @@ -210,7 +210,7 @@ protected virtual async Task PerformSaveOrReplicateAsync(object entity, if (persister.HasCollections) { - substitute = substitute || await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false); + substitute = await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false) || substitute; } if (substitute) diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index 8c9f356304f..cbec2218a22 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -235,7 +235,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE if (persister.HasCollections) { - substitute = substitute || VisitCollectionsBeforeSave(entity, id, values, types, source); + substitute = VisitCollectionsBeforeSave(entity, id, values, types, source) || substitute; } if (substitute) From f3bd74ef8d90675a756e54ccd956c0ef24bf6a33 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 18 Jul 2023 12:30:52 +0000 Subject: [PATCH 012/128] Call BeforeAssemble on persistent collection InitializeFromCache to allow batch fetching (#3365) Fixes #3359 --- .../Async/CacheTest/BatchableCacheFixture.cs | 25 ++++++++++++++++++- .../CacheTest/BatchableCacheFixture.cs | 25 ++++++++++++++++++- .../Generic/PersistentGenericBag.cs | 9 ++++++- .../Generic/PersistentGenericIdentifierBag.cs | 13 ++++++++-- .../Generic/PersistentGenericList.cs | 9 ++++++- .../Generic/PersistentGenericMap.cs | 13 ++++++++-- .../Generic/PersistentGenericSet.cs | 9 ++++++- .../Async/Collection/PersistentArrayHolder.cs | 8 +++++- .../Generic/PersistentGenericBag.cs | 9 ++++++- .../Generic/PersistentGenericIdentifierBag.cs | 13 ++++++++-- .../Generic/PersistentGenericList.cs | 9 ++++++- .../Generic/PersistentGenericMap.cs | 16 +++++++++--- .../Generic/PersistentGenericSet.cs | 9 ++++++- .../Collection/PersistentArrayHolder.cs | 8 +++++- 14 files changed, 156 insertions(+), 19 deletions(-) diff --git a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs index c3c2195688a..3fe00c5e385 100644 --- a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs @@ -1565,8 +1565,31 @@ public async Task QueryFetchEntityBatchCacheTestAsync(bool clearEntityCacheAfter Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count"); } + [Test] + public async Task CollectionLazyInitializationFromCacheIsBatchedAsync() + { + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(await (s.Query().Select(x => x.Id).FirstAsync()))); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(await (s.Query().Select(x => x.Id).FirstAsync()))); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private async Task AssertMultipleCacheCallsAsync(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, - int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken)) + int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken)) where TEntity : CacheEntity { var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName); diff --git a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs index 150369306b2..a18e7b616ca 100644 --- a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs @@ -1553,8 +1553,31 @@ public void QueryFetchEntityBatchCacheTest(bool clearEntityCacheAfterQuery, bool Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count"); } + [Test] + public void CollectionLazyInitializationFromCacheIsBatched() + { + using (var s = OpenSession()) + { + var readOnly = s.Get(s.Query().Select(x => x.Id).First()); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + + using (var s = OpenSession()) + { + var readOnly = s.Get(s.Query().Select(x => x.Id).First()); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private void AssertMultipleCacheCalls(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, - int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null) + int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null) where TEntity : CacheEntity { var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs index 3b229ac54b8..7ffa1b41fb9 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs @@ -109,9 +109,16 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist var array = (object[]) disassembled; var size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + for (var i = 0; i < size; i++) { - var element = await (persister.ElementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); + var element = await (elementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); if (element != null) { _gbag.Add((T) element); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs index 6e3ea111d01..af37fb8a1e0 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -44,10 +44,19 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var identifierType = persister.IdentifierType; + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + await (identifierType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); + } + for (int i = 0; i < size; i += 2) { - _identifiers[i / 2] = await (persister.IdentifierType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); - _values.Add((T) await (persister.ElementType.AssembleAsync(array[i + 1], Session, owner, cancellationToken)).ConfigureAwait(false)); + _identifiers[i / 2] = await (identifierType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); + _values.Add((T) await (elementType.AssembleAsync(array[i + 1], Session, owner, cancellationToken)).ConfigureAwait(false)); } } diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs index 1417c98e361..6ac827ecfa0 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs @@ -98,9 +98,16 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; for (int i = 0; i < size; i++) { - var element = await (persister.ElementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + + for (int i = 0; i < size; i++) + { + var element = await (elementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); WrappedList.Add((T) (element ?? DefaultForType)); } } diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs index e574577a111..fbe6e30c490 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs @@ -94,10 +94,19 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var indexType = persister.IndexType; + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + await (indexType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); + } + for (int i = 0; i < size; i += 2) { - WrappedMap[(TKey)await (persister.IndexType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false)] = - (TValue)await (persister.ElementType.AssembleAsync(array[i + 1], Session, owner, cancellationToken)).ConfigureAwait(false); + WrappedMap[(TKey)await (indexType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false)] = + (TValue)await (elementType.AssembleAsync(array[i + 1], Session, owner, cancellationToken)).ConfigureAwait(false); } } diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs index 91f2f86f626..c567ea44d86 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs @@ -84,9 +84,16 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist var array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + for (int i = 0; i < size; i++) { - var element = await (persister.ElementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); + var element = await (elementType.AssembleAsync(array[i], Session, owner, cancellationToken)).ConfigureAwait(false); if (element != null) { WrappedSet.Add((T) element); diff --git a/src/NHibernate/Async/Collection/PersistentArrayHolder.cs b/src/NHibernate/Async/Collection/PersistentArrayHolder.cs index 448309f2f9e..a08d2e6e96e 100644 --- a/src/NHibernate/Async/Collection/PersistentArrayHolder.cs +++ b/src/NHibernate/Async/Collection/PersistentArrayHolder.cs @@ -94,9 +94,15 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist array = System.Array.CreateInstance(persister.ElementClass, cached.Length); + var elementType = persister.ElementType; for (int i = 0; i < cached.Length; i++) { - array.SetValue(await (persister.ElementType.AssembleAsync(cached[i], Session, owner, cancellationToken)).ConfigureAwait(false), i); + await (elementType.BeforeAssembleAsync(cached[i], Session, cancellationToken)).ConfigureAwait(false); + } + + for (int i = 0; i < cached.Length; i++) + { + array.SetValue(await (elementType.AssembleAsync(cached[i], Session, owner, cancellationToken)).ConfigureAwait(false), i); } } diff --git a/src/NHibernate/Collection/Generic/PersistentGenericBag.cs b/src/NHibernate/Collection/Generic/PersistentGenericBag.cs index 98c916717c3..6530936f613 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericBag.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericBag.cs @@ -400,9 +400,16 @@ public override void InitializeFromCache(ICollectionPersister persister, object var array = (object[]) disassembled; var size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + elementType.BeforeAssemble(array[i], Session); + } + for (var i = 0; i < size; i++) { - var element = persister.ElementType.Assemble(array[i], Session, owner); + var element = elementType.Assemble(array[i], Session, owner); if (element != null) { _gbag.Add((T) element); diff --git a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs index 884d454b76e..71005049ad8 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -75,10 +75,19 @@ public override void InitializeFromCache(ICollectionPersister persister, object object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var identifierType = persister.IdentifierType; + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + identifierType.BeforeAssemble(array[i], Session); + elementType.BeforeAssemble(array[i + 1], Session); + } + for (int i = 0; i < size; i += 2) { - _identifiers[i / 2] = persister.IdentifierType.Assemble(array[i], Session, owner); - _values.Add((T) persister.ElementType.Assemble(array[i + 1], Session, owner)); + _identifiers[i / 2] = identifierType.Assemble(array[i], Session, owner); + _values.Add((T) elementType.Assemble(array[i + 1], Session, owner)); } } diff --git a/src/NHibernate/Collection/Generic/PersistentGenericList.cs b/src/NHibernate/Collection/Generic/PersistentGenericList.cs index 6255616dd0e..2c08510c311 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericList.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericList.cs @@ -160,9 +160,16 @@ public override void InitializeFromCache(ICollectionPersister persister, object object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; for (int i = 0; i < size; i++) { - var element = persister.ElementType.Assemble(array[i], Session, owner); + elementType.BeforeAssemble(array[i], Session); + } + + for (int i = 0; i < size; i++) + { + var element = elementType.Assemble(array[i], Session, owner); WrappedList.Add((T) (element ?? DefaultForType)); } } diff --git a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs index 5fab797d793..e81aee07578 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs @@ -163,10 +163,19 @@ public override void InitializeFromCache(ICollectionPersister persister, object object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var indexType = persister.IndexType; + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + indexType.BeforeAssemble(array[i], Session); + elementType.BeforeAssemble(array[i + 1], Session); + } + for (int i = 0; i < size; i += 2) { - WrappedMap[(TKey)persister.IndexType.Assemble(array[i], Session, owner)] = - (TValue)persister.ElementType.Assemble(array[i + 1], Session, owner); + WrappedMap[(TKey)indexType.Assemble(array[i], Session, owner)] = + (TValue)elementType.Assemble(array[i + 1], Session, owner); } } @@ -246,8 +255,9 @@ public void Add(TKey key, TValue value) { if (key == null) { - throw new ArgumentNullException("key"); + throw new ArgumentNullException(nameof(key)); } + if (PutQueueEnabled) { var found = TryReadElementByKey(key, out _, out _); diff --git a/src/NHibernate/Collection/Generic/PersistentGenericSet.cs b/src/NHibernate/Collection/Generic/PersistentGenericSet.cs index 4e138bb22fa..f2736a8d21c 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericSet.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericSet.cs @@ -154,9 +154,16 @@ public override void InitializeFromCache(ICollectionPersister persister, object var array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); + + var elementType = persister.ElementType; + for (int i = 0; i < size; i++) + { + elementType.BeforeAssemble(array[i], Session); + } + for (int i = 0; i < size; i++) { - var element = persister.ElementType.Assemble(array[i], Session, owner); + var element = elementType.Assemble(array[i], Session, owner); if (element != null) { WrappedSet.Add((T) element); diff --git a/src/NHibernate/Collection/PersistentArrayHolder.cs b/src/NHibernate/Collection/PersistentArrayHolder.cs index 242d7dac51a..1bd42dc42ce 100644 --- a/src/NHibernate/Collection/PersistentArrayHolder.cs +++ b/src/NHibernate/Collection/PersistentArrayHolder.cs @@ -196,9 +196,15 @@ public override void InitializeFromCache(ICollectionPersister persister, object array = System.Array.CreateInstance(persister.ElementClass, cached.Length); + var elementType = persister.ElementType; for (int i = 0; i < cached.Length; i++) { - array.SetValue(persister.ElementType.Assemble(cached[i], Session, owner), i); + elementType.BeforeAssemble(cached[i], Session); + } + + for (int i = 0; i < cached.Length; i++) + { + array.SetValue(elementType.Assemble(cached[i], Session, owner), i); } } From 3186197c1eec77aae46eb0f2ce8cf37bb4c2a03b Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 15:32:43 +0300 Subject: [PATCH 013/128] Migrate dev NuGet packages to Cloudsmith (#3367) (cherry picked from commit 26b557fc38824e812527f18cd5cbe3f40fab5398) --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8da992df161..6290ebbaa94 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Nightly Development Builds -------------------------- The quickest way to get the latest development build of NHibernate is to add it to your project using -NuGet from MyGet feed (). +NuGet from Cloudsmith feed (). In order to make life a little bit easier you can register the package source in the NuGet.Config file in the top folder of your project, similar to the following. @@ -35,11 +35,18 @@ file in the top folder of your project, similar to the following. - + ``` +Package repository hosting is graciously provided by [Cloudsmith](https://cloudsmith.com). +Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that +enables your organization to create, store and share packages in any format, to any place, with total +confidence. + +[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=flat-square)](https://cloudsmith.com) + Community Forums ---------------- From 62f7fe9003b1a17b4b8f924b73d659f5d1dbfc05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 08:57:10 +1000 Subject: [PATCH 014/128] Update dependency NUnit3TestAdapter to v4.5.0 (#3362) --- .../NHibernate.Test.VisualBasic.vbproj | 2 +- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- .../NHibernate.TestDatabaseSetup.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index 6859ccff6d7..b21426b8b58 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -28,7 +28,7 @@ - + diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 70d1e2330c7..411cecd921c 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -63,7 +63,7 @@ - + diff --git a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj index 6d6174c26ee..1eab7c9ff7b 100644 --- a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj +++ b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj @@ -16,7 +16,7 @@ - + From 13565fb13db643b2f64d8f407ae19b71e3e9af00 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 19 Jul 2023 06:19:11 +0300 Subject: [PATCH 015/128] Allow internal entity classess/interfaces in .NET Standard 2.0 for field interceptor (#3368) --- src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs index f3255a2aaab..4fed7814108 100644 --- a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs +++ b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs @@ -57,10 +57,9 @@ public static TypeInfo CreateProxyType(System.Type baseType) var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name); -#if NETFX || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER if (!baseType.IsVisible) ProxyBuilderHelper.GenerateInstanceOfIgnoresAccessChecksToAttribute(assemblyBuilder, baseType.Assembly.GetName().Name); -#endif + var moduleBuilder = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName); const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit; From 8a8180a18aafe56f35a2261611c6721dcb89ce25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 20:13:51 +0200 Subject: [PATCH 016/128] Update dependency NUnit.Console to v3.16.3 (#3361) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Tools/packages.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/packages.csproj b/Tools/packages.csproj index 9bd32fe4d05..5ec330d2986 100644 --- a/Tools/packages.csproj +++ b/Tools/packages.csproj @@ -11,7 +11,7 @@ - + From 0fdb589b35aa44d3dbb3031578d51338543b3b07 Mon Sep 17 00:00:00 2001 From: csharper2010 Date: Thu, 20 Jul 2023 06:32:06 +0200 Subject: [PATCH 017/128] Fix AND/OR negation logic in hql (#3328) * Fixes #3327 Co-authored-by: Roman Artiukhin --- .../Async/NHSpecificTest/GH3327/Fixture.cs | 63 +++++++++++++++++++ .../NHSpecificTest/GH3327/Entity.cs | 17 +++++ .../NHSpecificTest/GH3327/Fixture.cs | 52 +++++++++++++++ .../NHSpecificTest/GH3327/Mappings.hbm.xml | 16 +++++ src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs | 8 +-- 5 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs new file mode 100644 index 00000000000..b34a71f1317 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child", Parent = parent }; + session.Save(parent); + session.Save(child); + t.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task NotIsCorrectlyHandledAsync() + { + using var session = OpenSession(); + var q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That((await (q.ListAsync()))[0], Is.EqualTo(1)); + + q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That((await (q.ListAsync()))[0], Is.EqualTo(0)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs new file mode 100644 index 00000000000..9f9b2bafce2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs @@ -0,0 +1,17 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + public class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class ChildEntity + { + public virtual int Id { get; set; } + public virtual Entity Parent { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs new file mode 100644 index 00000000000..aef1a40243e --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs @@ -0,0 +1,52 @@ +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child", Parent = parent }; + session.Save(parent); + session.Save(child); + t.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void NotIsCorrectlyHandled() + { + using var session = OpenSession(); + var q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That(q.List()[0], Is.EqualTo(1)); + + q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That(q.List()[0], Is.EqualTo(0)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml new file mode 100644 index 00000000000..a6eee729fae --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index f33f8b13acb..6c05fc6c999 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -214,14 +214,14 @@ public IASTNode NegateNode(IASTNode node) case OR: node.Type = AND; node.Text = "{and}"; - NegateNode(node.GetChild(0)); - NegateNode(node.GetChild(1)); + node.SetChild(0, NegateNode(node.GetChild(0))); + node.SetChild(1, NegateNode(node.GetChild(1))); return node; case AND: node.Type = OR; node.Text = "{or}"; - NegateNode(node.GetChild(0)); - NegateNode(node.GetChild(1)); + node.SetChild(0, NegateNode(node.GetChild(0))); + node.SetChild(1, NegateNode(node.GetChild(1))); return node; case EQ: node.Type = NE; From 387501124baf279c0c583908ffd70a6d46f0388d Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 21 Jul 2023 17:18:23 +0300 Subject: [PATCH 018/128] Support association joins from main query to be used in subqueries (#3369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3334 Co-authored-by: CSharper2010 Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- .../Async/NHSpecificTest/GH1228/Fixture.cs | 106 +++++++++ .../Async/NHSpecificTest/GH3334/Fixture.cs | 204 ++++++++++++++++++ .../NHSpecificTest/GH1228/Fixture.cs | 192 +++++++---------- .../NHSpecificTest/GH3334/Entity.cs | 33 +++ .../NHSpecificTest/GH3334/Fixture.cs | 193 +++++++++++++++++ .../NHSpecificTest/GH3334/Mappings.hbm.xml | 36 ++++ src/NHibernate.Test/TestDialect.cs | 5 + .../TestDialects/MySQL5TestDialect.cs | 7 + src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs | 12 +- src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g | 8 +- .../Hql/Ast/ANTLR/Tree/FromClause.cs | 5 + .../Hql/Ast/ANTLR/Tree/FromElement.cs | 12 +- .../Hql/Ast/ANTLR/Tree/FromElementFactory.cs | 6 +- 13 files changed, 683 insertions(+), 136 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs new file mode 100644 index 00000000000..a95df9e5f21 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1228 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [Test] + public async Task TestThetaJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatWorks.ListAsync()); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatWorks.ListAsync()); + } + + [Test] + public async Task TestAnsiJoinOnAssociationInSubQueryAsync() + { + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + + using var s = OpenSession(); + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + } + + [Test] + public async Task TestOtherAnsiJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..b25d10169a7 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// 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.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public async Task NoExceptionOnExecuteQueryAsync(TestCaseItem testCase) + { + using var session = OpenSession(); + var q = session.CreateQuery(testCase.Hql); + Assert.That(await (q.ListAsync()), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 940b721a90b..64e4af85e3e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -2,132 +2,94 @@ namespace NHibernate.Test.NHSpecificTest.GH1228 { + [TestFixture] public class Fixture : BugTestCase { [Test] - public void TestOk() + public void TestThetaJoinOnAssociationInSubQuery() { - using (ISession s = OpenSession()) - { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatWorks = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - , ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatWorks.List(); - } - { - var queryThatWorks = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - , ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatWorks.List(); - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + using var s = OpenSession(); + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatWorks.List(); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatWorks.List(); } [Test] - public void TestWrongSql() + public void TestAnsiJoinOnAssociationInSubQuery() { - using (ISession s = OpenSession()) - { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + + using var s = OpenSession(); + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. } [Test] - public void Test3() { - using (ISession s = OpenSession()) { - using (ITransaction t = s.BeginTransaction()) { - try { - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN sheet.Folder AS folder - WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN inv.Folders AS folder - WHERE folder = ROOT.Folder AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - } - finally { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + public void TestOtherAnsiJoinOnAssociationInSubQuery() + { + using var s = OpenSession(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs new file mode 100644 index 00000000000..718d3ac3488 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + public class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + public virtual OtherEntity OtherEntity { get; set; } + } + + public class ChildEntity + { + public virtual int Id { get; set; } + public virtual Entity Parent { get; set; } + public virtual string Name { get; set; } + public virtual GrandChildEntity Child { get; set; } + } + + public class GrandChildEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class OtherEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Entities { get; set; } = new HashSet(); + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..8ebf4b1d29c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,193 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public void NoExceptionOnExecuteQuery(TestCaseItem testCase) + { + using var session = OpenSession(); + var q = session.CreateQuery(testCase.Hql); + Assert.That(q.List(), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml new file mode 100644 index 00000000000..1f5bcdfe8e6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index 49b2f7e0f69..e7bc20d304f 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -203,5 +203,10 @@ public bool SupportsSqlType(SqlType sqlType) /// Returns true if you can cancel a query. /// public virtual bool SupportsCancelQuery => true; + + /// + /// Some databases (MySql) don't support using main table aliases in subquery inside join ON clause + /// + public virtual bool SupportsCorrelatedColumnsInSubselectJoin => true; } } diff --git a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs index 0ec57f43bc6..ea68e6f19b7 100644 --- a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs @@ -14,5 +14,12 @@ public MySQL5TestDialect(Dialect.Dialect dialect) /// This behaviour is documented at: http://dev.mysql.com/doc/refman/5.6/en/update.html /// public override bool SupportsModifyAndSelectSameTable => false; + + /// + /// A correlated column can be present only in the subquery's WHERE clause (and not in the SELECT list, + /// a JOIN or ORDER BY clause, a GROUP BY list, or a HAVING clause). Nor can there be any correlated column inside a derived table in the subquery's FROM list. + /// See https://dev.mysql.com/doc/refman/8.0/en/correlated-subqueries.html + /// + public override bool SupportsCorrelatedColumnsInSubselectJoin => false; } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs index ac22725e582..8628201c18b 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs @@ -832,16 +832,6 @@ void CreateFromJoinElement( HandleWithFragment(fromElement, with); } - - if (fromElement.Parent == null) - { - // Most likely means association join is used in invalid context - // I.e. in subquery: from EntityA a where exists (from EntityB join a.Assocation) - // Maybe we should throw exception instead - fromElement.FromClause.AddChild(fromElement); - if (fromElement.IsImplied) - fromElement.JoinSequence.SetUseThetaStyle(true); - } } if ( log.IsDebugEnabled() ) @@ -930,7 +920,7 @@ private static string GetPropertyPath(DotNode dotNode, IASTNode alias) return lhs.Path + "." + path; } - IASTNode CreateFromElement(string path, IASTNode pathNode, IASTNode alias, IASTNode propertyFetch) + FromElement CreateFromElement(string path, IASTNode pathNode, IASTNode alias, IASTNode propertyFetch) { FromElement fromElement = _currentFromClause.AddFromElement(path, alias); SetPropertyFetch(fromElement, propertyFetch, alias); diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g index 47b42f286ea..623cc830fd8 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g @@ -266,10 +266,14 @@ fromElementList @init{ fromElement! @init { - IASTNode fromElement = null; + FromElement fromElement = null; } // A simple class name, alias element. - : ^(RANGE p=path (a=ALIAS)? (pf=propertyFetch)? ) { fromElement = CreateFromElement($p.p, $p.tree, $a, $pf.tree); } + : ^(RANGE p=path (a=ALIAS)? (pf=propertyFetch)? ) + { + fromElement = CreateFromElement($p.p, $p.tree, $a, $pf.tree); + fromElement.JoinSequence.SetUseThetaStyle(true); + } -> {fromElement != null}? ^({fromElement}) -> | je=joinElement diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs index 39179f1419a..839ea736e5d 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs @@ -447,6 +447,11 @@ internal void FinishInit() dependentElement.Parent.InsertChild(index, item); } } + + if (_appendFromElements.Count > 0) + { + _fromElements[0].JoinSequence.SetUseThetaStyle(true); + } _appendFromElements.Clear(); } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index 79d42962748..a22c13e84ff 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -707,12 +707,18 @@ public void SetOrigin(FromElement origin, bool manyToMany) { // HHH-276 : implied joins in a subselect where clause - The destination needs to be added // to the destination's from clause. - FromClause.AddChild(this); // Not sure if this is will fix everything, but it works. + FromClause.AddChild(this); + + // Generate correlated implied joins inside subquery implicitly + // As some dialects (MySql) do not support correlated columns to be used in subquery join ON clause + if (IsImplied) + { + JoinSequence.SetUseThetaStyle(true); + } } else { - // Otherwise, the destination node was implied by the FROM clause and the FROM clause processor - // will automatically add it in the right place. + FromClause.AppendFromElement(this); } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs index 4f80d774f43..e9a95769f1f 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs @@ -122,10 +122,6 @@ private FromElement CreateFromElementInSubselect( string tableAlias = correlatedSubselect ? fromElement.TableAlias : null; - //To properly generete subselect implicit join is required by SqlGenerator - if (fromElement.IsImplied) - fromElement.JoinSequence.SetUseThetaStyle(true); - // If the from element isn't in the same clause, create a new from element. if (fromElement.FromClause != _fromClause) { @@ -321,7 +317,7 @@ public FromElement CreateEntityJoin( // 1) 'elem' is the "root from-element" in correlated subqueries // 2) The DotNode.useThetaStyleImplicitJoins has been set to true // and 'elem' represents an implicit join - if (elem.FromClause != elem.Origin.FromClause || DotNode.UseThetaStyleImplicitJoins) + if (DotNode.UseThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.Type = HqlSqlWalker.FROM_FRAGMENT; From e842cc51861cb1b0d9d9ba6bc2f8457a93f7014e Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 23 Jul 2023 10:16:20 +0300 Subject: [PATCH 019/128] Refactor sequential select related members in AbstractEntityPersister (#3373) * Rename GetSubclassPropertyTableNumber(string propertyName, string entityName) to GetSubclassJoinPropertyTableNumber * Skip dictionary initialization logic if not required --- .../Entity/AbstractEntityPersister.cs | 24 ++++++++++++++----- .../Entity/SingleTableEntityPersister.cs | 6 ++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index fb603da740a..5e2f3e4748d 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -263,7 +263,7 @@ public virtual void BindValues(DbCommand ps) // This must be a Lazy, because instances of this class must be thread safe. private readonly Lazy defaultUniqueKeyPropertyNamesForSelectId; - private readonly Dictionary propertyTableNumbersByNameAndSubclass = new Dictionary(); + private readonly Dictionary propertySubclassJoinTableNumbersByName; protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory) @@ -441,6 +441,17 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr List columnSelectables = new List(); List propNullables = new List(); + if (persistentClass.SubclassJoinClosureIterator.Any()) + { + propertySubclassJoinTableNumbersByName = new Dictionary(); + foreach (Property prop in persistentClass.SubclassPropertyClosureIterator) + { + var joinNumber = persistentClass.GetJoinNumber(prop); + if (joinNumber != 0) + propertySubclassJoinTableNumbersByName[prop.PersistentClass.EntityName + '.' + prop.Name] = joinNumber; + } + } + foreach (Property prop in persistentClass.SubclassPropertyClosureIterator) { names.Add(prop.Name); @@ -449,8 +460,6 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr definedBySubclass.Add(isDefinedBySubclass); propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct? types.Add(prop.Type); - propertyTableNumbersByNameAndSubclass[prop.PersistentClass.EntityName + '.' + prop.Name] = - persistentClass.GetJoinNumber(prop); string[] cols = new string[prop.ColumnSpan]; string[] forms = new string[prop.ColumnSpan]; @@ -1125,12 +1134,15 @@ protected virtual bool IsIdOfTable(int property, int table) protected abstract int GetSubclassPropertyTableNumber(int i); - internal int GetSubclassPropertyTableNumber(string propertyName, string entityName) + internal int GetSubclassJoinPropertyTableNumber(string propertyName, string entityName) { + if (propertySubclassJoinTableNumbersByName == null) + return 0; + var type = propertyMapping.ToType(propertyName); if (type.IsAssociationType && ((IAssociationType) type).UseLHSPrimaryKey) return 0; - propertyTableNumbersByNameAndSubclass.TryGetValue(entityName + '.' + propertyName, out var tabnum); + propertySubclassJoinTableNumbersByName.TryGetValue(entityName + '.' + propertyName, out var tabnum); return tabnum; } @@ -4878,7 +4890,7 @@ internal SqlString GenerateSequentialSelect(AbstractEntityPersister subclassPers var classes = subclassPersister.PropertySubclassNames; for (var i = 0; i < props.Length; i++) { - var propTableNumber = GetSubclassPropertyTableNumber(props[i], classes[i]); + var propTableNumber = GetSubclassJoinPropertyTableNumber(props[i], classes[i]); if (IsSubclassTableSequentialSelect(propTableNumber) && !IsSubclassTableLazy(propTableNumber)) { tableNumbers.Add(propTableNumber); diff --git a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs index 9aa8a71a3e4..3b1f0c5f7a8 100644 --- a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs @@ -696,7 +696,7 @@ protected override void AddDiscriminatorToInsert(SqlInsertBuilder insert) protected override bool IsSubclassPropertyDeferred(string propertyName, string entityName) { return - hasSequentialSelects && IsSubclassTableSequentialSelect(base.GetSubclassPropertyTableNumber(propertyName, entityName)); + hasSequentialSelects && IsSubclassTableSequentialSelect(GetSubclassPropertyTableNumber(propertyName, entityName)); } protected override bool IsPropertyDeferred(int propertyIndex) @@ -713,9 +713,9 @@ public override bool HasSequentialSelect //Since v5.3 [Obsolete("This method has no more usage in NHibernate and will be removed in a future version.")] - public new int GetSubclassPropertyTableNumber(string propertyName, string entityName) + public int GetSubclassPropertyTableNumber(string propertyName, string entityName) { - return base.GetSubclassPropertyTableNumber(propertyName, entityName); + return GetSubclassJoinPropertyTableNumber(propertyName, entityName); } //Since v5.3 From 5f6069a46e0aab60f77316ecf2f32f1bdf13823b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 19:28:13 +0200 Subject: [PATCH 020/128] Update dependency System.Data.SQLite.Core to v1.0.116 (#3098) --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 411cecd921c..58a806329e7 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -59,7 +59,7 @@ - + From d578b1dd26f5706bb0dcfbc40ee3f0990e7fbc91 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Mon, 24 Jul 2023 19:06:45 +0300 Subject: [PATCH 021/128] Simplify aggregateDistinctAll rule in Hql.g (#3374) --- src/NHibernate/Hql/Ast/ANTLR/Hql.g | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Hql.g b/src/NHibernate/Hql/Ast/ANTLR/Hql.g index 281e997138f..364c9142711 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Hql.g +++ b/src/NHibernate/Hql/Ast/ANTLR/Hql.g @@ -628,12 +628,11 @@ aggregateArgument ; aggregateDistinctAll - : ( distinctAll aggregateArgument ) => (distinctAll aggregateArgument) - | aggregateArgument + : ( distinctAll? aggregateArgument ) ; distinctAll - : ( DISTINCT | ALL ) + : {input.LA(1) == DISTINCT || input.LA(1) == ALL}? ( DISTINCT | ALL ) ; //## collection: ( OPEN query CLOSE ) | ( 'elements'|'indices' OPEN path CLOSE ); From 7a1bf08fa52c789f4eb6b1b63ae4c1c069b0737e Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 24 Jul 2023 22:21:14 +0000 Subject: [PATCH 022/128] Remove NHibernate.Example.Web project (#3379) --- .github/renovate.json | 10 --- src/NHibernate.Everything.sln | 39 -------- .../Infrastructure/AppSessionFactory.cs | 40 --------- .../NHibernateToMicrosoftLogger.cs | 43 --------- .../NHibernateToMicrosoftLoggerFactory.cs | 26 ------ src/NHibernate.Example.Web/Models/Item.cs | 9 -- src/NHibernate.Example.Web/Models/ItemMap.cs | 16 ---- .../NHibernate.Example.Web.csproj | 35 -------- src/NHibernate.Example.Web/Pages/Error.cshtml | 23 ----- .../Pages/Error.cshtml.cs | 21 ----- src/NHibernate.Example.Web/Pages/Index.cshtml | 9 -- .../Pages/Index.cshtml.cs | 16 ---- .../Pages/InsertItem.cshtml | 19 ---- .../Pages/InsertItem.cshtml.cs | 63 ------------- .../Pages/Schema.cshtml | 16 ---- .../Pages/Schema.cshtml.cs | 68 -------------- .../Pages/ViewData.cshtml | 40 --------- .../Pages/ViewData.cshtml.cs | 90 ------------------- .../Pages/_Layout.cshtml | 41 --------- .../Pages/_ViewImports.cshtml | 3 - .../Pages/_ViewStart.cshtml | 3 - src/NHibernate.Example.Web/Program.cs | 35 -------- .../Properties/launchSettings.json | 27 ------ src/NHibernate.Example.Web/Startup.cs | 53 ----------- .../appsettings.Development.json | 10 --- src/NHibernate.Example.Web/appsettings.json | 8 -- 26 files changed, 763 deletions(-) delete mode 100644 src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs delete mode 100644 src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs delete mode 100644 src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs delete mode 100644 src/NHibernate.Example.Web/Models/Item.cs delete mode 100644 src/NHibernate.Example.Web/Models/ItemMap.cs delete mode 100644 src/NHibernate.Example.Web/NHibernate.Example.Web.csproj delete mode 100644 src/NHibernate.Example.Web/Pages/Error.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/Error.cshtml.cs delete mode 100644 src/NHibernate.Example.Web/Pages/Index.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/Index.cshtml.cs delete mode 100644 src/NHibernate.Example.Web/Pages/InsertItem.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs delete mode 100644 src/NHibernate.Example.Web/Pages/Schema.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/Schema.cshtml.cs delete mode 100644 src/NHibernate.Example.Web/Pages/ViewData.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs delete mode 100644 src/NHibernate.Example.Web/Pages/_Layout.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/_ViewImports.cshtml delete mode 100644 src/NHibernate.Example.Web/Pages/_ViewStart.cshtml delete mode 100644 src/NHibernate.Example.Web/Program.cs delete mode 100644 src/NHibernate.Example.Web/Properties/launchSettings.json delete mode 100644 src/NHibernate.Example.Web/Startup.cs delete mode 100644 src/NHibernate.Example.Web/appsettings.Development.json delete mode 100644 src/NHibernate.Example.Web/appsettings.json diff --git a/.github/renovate.json b/.github/renovate.json index 98411a821c0..595245c44b1 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -20,16 +20,6 @@ ], "groupName": "NUnit" }, - { - "matchPackageNames": [ - "Microsoft.AspNetCore", - "Microsoft.AspNetCore.Mvc", - "Microsoft.AspNetCore.Mvc.Razor.ViewCompilation", - "Microsoft.AspNetCore.StaticFiles" - ], - "groupName": "Microsoft.AspNetCore 2.0", - "allowedVersions": "~2.1.0" - }, { "matchPackagePrefixes": [ "Oracle.ManagedDataAccess" diff --git a/src/NHibernate.Everything.sln b/src/NHibernate.Everything.sln index c2c257360fc..4d1b272a260 100644 --- a/src/NHibernate.Everything.sln +++ b/src/NHibernate.Everything.sln @@ -70,93 +70,54 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.Tool.HbmXsd", "N EndProject Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "NHibernate.Test.VisualBasic", "NHibernate.Test.VisualBasic\NHibernate.Test.VisualBasic.vbproj", "{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.Example.Web", "NHibernate.Example.Web\NHibernate.Example.Web.csproj", "{B291C1C1-599B-418E-8591-8A8CF1CAA188}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.TestDatabaseSetup", "NHibernate.TestDatabaseSetup\NHibernate.TestDatabaseSetup.csproj", "{783DB85E-2EED-4377-8EF4-8D6EFE042007}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|.NET = Debug|.NET Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms Release|.NET = Release|.NET Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|.NET.ActiveCfg = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|.NET.ActiveCfg = Release|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Any CPU.ActiveCfg = Release|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Any CPU.Build.0 = Release|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|.NET.ActiveCfg = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|.NET.ActiveCfg = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Any CPU.Build.0 = Release|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Mixed Platforms.Build.0 = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|.NET.ActiveCfg = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|.NET.ActiveCfg = Release|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Any CPU.Build.0 = Release|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Mixed Platforms.Build.0 = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|.NET.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|.NET.ActiveCfg = Release|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Any CPU.Build.0 = Release|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|.NET.ActiveCfg = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|.NET.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.Build.0 = Release|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|.NET.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|.NET.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|.NET.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|.NET.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Any CPU.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Mixed Platforms.Build.0 = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|.NET.ActiveCfg = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|.NET.Build.0 = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Any CPU.Build.0 = Debug|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|.NET.ActiveCfg = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|.NET.Build.0 = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Any CPU.ActiveCfg = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Any CPU.Build.0 = Release|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs b/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs deleted file mode 100644 index 38265648eda..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs +++ /dev/null @@ -1,40 +0,0 @@ -using NHibernate.Cfg; -using NHibernate.Dialect; -using NHibernate.Driver; -using NHibernate.Example.Web.Models; -using NHibernate.Mapping.ByCode; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class AppSessionFactory - { - public Configuration Configuration { get; } - public ISessionFactory SessionFactory { get; } - - public AppSessionFactory(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) - { - NHibernate.NHibernateLogger.SetLoggersFactory(new NHibernateToMicrosoftLoggerFactory(loggerFactory)); - - var mapper = new ModelMapper(); - mapper.AddMapping(); - var domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); - - Configuration = new Configuration(); - Configuration.DataBaseIntegration(db => - { - db.ConnectionString = @"Server=(local)\SQLEXPRESS;initial catalog=nhibernate;Integrated Security=true"; - db.Dialect(); - db.Driver(); - }) - .AddMapping(domainMapping); - Configuration.SessionFactory().GenerateStatistics(); - - SessionFactory = Configuration.BuildSessionFactory(); - } - - public ISession OpenSession() - { - return SessionFactory.OpenSession(); - } - } -} diff --git a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs b/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs deleted file mode 100644 index a30f2f1236f..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Internal; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class NHibernateToMicrosoftLogger : INHibernateLogger - { - private readonly ILogger _msLogger; - - public NHibernateToMicrosoftLogger(ILogger msLogger) - { - _msLogger = msLogger ?? throw new ArgumentNullException(nameof(msLogger)); - } - - private static readonly Dictionary MapLevels = new Dictionary - { - { NHibernateLogLevel.Trace, LogLevel.Trace }, - { NHibernateLogLevel.Debug, LogLevel.Debug }, - { NHibernateLogLevel.Info, LogLevel.Information }, - { NHibernateLogLevel.Warn, LogLevel.Warning }, - { NHibernateLogLevel.Error, LogLevel.Error }, - { NHibernateLogLevel.Fatal, LogLevel.Critical }, - { NHibernateLogLevel.None, LogLevel.None }, - }; - - public void Log(NHibernateLogLevel logLevel, NHibernateLogValues state, Exception exception) - { - _msLogger.Log(MapLevels[logLevel], 0, new FormattedLogValues(state.Format, state.Args), exception, MessageFormatter); - } - - public bool IsEnabled(NHibernateLogLevel logLevel) - { - return _msLogger.IsEnabled(MapLevels[logLevel]); - } - - private static string MessageFormatter(object state, Exception error) - { - return state.ToString(); - } - } -} diff --git a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs b/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs deleted file mode 100644 index 0e732127cd4..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class NHibernateToMicrosoftLoggerFactory : INHibernateLoggerFactory - { - private readonly Microsoft.Extensions.Logging.ILoggerFactory _loggerFactory; - - public NHibernateToMicrosoftLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); - } - - public INHibernateLogger LoggerFor(string keyName) - { - var msLogger = _loggerFactory.CreateLogger(keyName); - return new NHibernateToMicrosoftLogger(msLogger); - } - - public INHibernateLogger LoggerFor(System.Type type) - { - return LoggerFor( - Microsoft.Extensions.Logging.Abstractions.Internal.TypeNameHelper.GetTypeDisplayName(type)); - } - } -} diff --git a/src/NHibernate.Example.Web/Models/Item.cs b/src/NHibernate.Example.Web/Models/Item.cs deleted file mode 100644 index 7306ed585ca..00000000000 --- a/src/NHibernate.Example.Web/Models/Item.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace NHibernate.Example.Web.Models -{ - public class Item - { - public virtual int Id { get; set; } - public virtual decimal Price { get; set; } - public virtual string Description { get; set; } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Models/ItemMap.cs b/src/NHibernate.Example.Web/Models/ItemMap.cs deleted file mode 100644 index 6f206b8a5ef..00000000000 --- a/src/NHibernate.Example.Web/Models/ItemMap.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NHibernate.Mapping.ByCode; -using NHibernate.Mapping.ByCode.Conformist; - -namespace NHibernate.Example.Web.Models -{ - public class ItemMap : ClassMapping - { - public ItemMap() - { - Lazy(false); - Id(x => x.Id, map => map.Generator(Generators.Native)); - Property(x => x.Price); - Property(x => x.Description); - } - } -} diff --git a/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj b/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj deleted file mode 100644 index 7bd7b9f7109..00000000000 --- a/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - netcoreapp2.0;net48 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/NHibernate.Example.Web/Pages/Error.cshtml b/src/NHibernate.Example.Web/Pages/Error.cshtml deleted file mode 100644 index b1f3143a42e..00000000000 --- a/src/NHibernate.Example.Web/Pages/Error.cshtml +++ /dev/null @@ -1,23 +0,0 @@ -@page -@model ErrorModel -@{ - ViewData["Title"] = "Error"; -} - -

Error.

-

An error occurred while processing your request.

- -@if (Model.ShowRequestId) -{ -

- Request ID: @Model.RequestId -

-} - -

Development Mode

-

- Swapping to Development environment will display more detailed information about the error that occurred. -

-

- Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. -

diff --git a/src/NHibernate.Example.Web/Pages/Error.cshtml.cs b/src/NHibernate.Example.Web/Pages/Error.cshtml.cs deleted file mode 100644 index 8c9952f597a..00000000000 --- a/src/NHibernate.Example.Web/Pages/Error.cshtml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace NHibernate.Example.Web.Pages -{ - public class ErrorModel : PageModel - { - public string RequestId { get; set; } - - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/Index.cshtml b/src/NHibernate.Example.Web/Pages/Index.cshtml deleted file mode 100644 index d76c879b19c..00000000000 --- a/src/NHibernate.Example.Web/Pages/Index.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@page -@model IndexModel -@{ - ViewData["Title"] = "NHibernate Demo"; -} - -

NHibernate Demo

-Schema Operations -View Data diff --git a/src/NHibernate.Example.Web/Pages/Index.cshtml.cs b/src/NHibernate.Example.Web/Pages/Index.cshtml.cs deleted file mode 100644 index 9d41b89fca1..00000000000 --- a/src/NHibernate.Example.Web/Pages/Index.cshtml.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace NHibernate.Example.Web.Pages -{ - public class IndexModel : PageModel - { - public void OnGet() - { - } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml b/src/NHibernate.Example.Web/Pages/InsertItem.cshtml deleted file mode 100644 index 1f2f61953be..00000000000 --- a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml +++ /dev/null @@ -1,19 +0,0 @@ -@page -@model InsertItemModel -@{ - ViewData["Title"] = "Insert New Item"; -} -
- - - - - - - - - - - -
Price:
Description:
-
\ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs b/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs deleted file mode 100644 index c670497996e..00000000000 --- a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Models; - -namespace NHibernate.Example.Web.Pages -{ - public class InsertItemModel : PageModel - { - [BindProperty] - public InsertItemEvent NewItem { get; set; } - - private readonly ISession _session; - - public InsertItemModel(ISession session) - { - _session = session; - } - - public void OnGet() - { - } - - public IActionResult OnPost() - { - if (!ModelState.IsValid) - { - return Page(); - } - - using (var tx = _session.BeginTransaction()) - { - var item = new Item - { - Price = NewItem.Price, - Description = NewItem.Description, - }; - _session.Save(item); - - tx.Commit(); - } - - return RedirectToPage("/ViewData"); - } - - public IActionResult OnPostCancel() - { - return RedirectToPage("/ViewData"); - } - - public class InsertItemEvent - { - [Required, Range(0.0, double.MaxValue)] - public decimal Price { get; set; } - - public string Description { get; set; } - } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/Schema.cshtml b/src/NHibernate.Example.Web/Pages/Schema.cshtml deleted file mode 100644 index ea9f23481b9..00000000000 --- a/src/NHibernate.Example.Web/Pages/Schema.cshtml +++ /dev/null @@ -1,16 +0,0 @@ -@page -@model SchemaModel -@{ - ViewData["Title"] = "Schema Operations"; -} - -Back to the main page - -
-
- - -
-
- -

@Model.Status

\ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs b/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs deleted file mode 100644 index 42b2533fb0e..00000000000 --- a/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Infrastructure; -using NHibernate.Example.Web.Models; -using NHibernate.Tool.hbm2ddl; - -namespace NHibernate.Example.Web.Pages -{ - public class SchemaModel : PageModel - { - [TempData] - public string Status { get; set; } - - private readonly AppSessionFactory _applicationSession; - private readonly ISession _session; - - public SchemaModel(ISession session, AppSessionFactory applicationSession) - { - _applicationSession = applicationSession; - _session = session ?? throw new ArgumentNullException(nameof(session)); - } - - public void OnGet() - { - } - - public IActionResult OnPostCreateSchema() - { - var export = new SchemaExport(_applicationSession.Configuration); - export.Create(false, true); - - using (var tx = _session.BeginTransaction()) - { - var item1 = new Item - { - Description = "First item", - Price = 100m - }; - _session.Save(item1); - - var item2 = new Item - { - Description = "Second item", - Price = 150m - }; - _session.Save(item2); - - tx.Commit(); - } - - Status = "Schema created"; - return RedirectToPage(); - } - - public IActionResult OnPostDropSchema() - { - SchemaExport export = new SchemaExport(_applicationSession.Configuration); - export.Drop(false, true); - - Status = "Schema dropped"; - return RedirectToPage(); - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/ViewData.cshtml b/src/NHibernate.Example.Web/Pages/ViewData.cshtml deleted file mode 100644 index ca4681624aa..00000000000 --- a/src/NHibernate.Example.Web/Pages/ViewData.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@page -@model ViewDataModel -@{ - ViewData["Title"] = "View Items"; -} - -
- - - - - - @foreach (var item in Model.Items) - { - - @if (Model.Editing == item.Id) - { - - - - - } - else - { - - - - - } - - } -
Item List
IdPriceDescription
- - - @item.Id - - - @item.Id@item.Price@item.Description
-
-Add New Item \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs b/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs deleted file mode 100644 index 6ac9785df97..00000000000 --- a/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Models; - -namespace NHibernate.Example.Web.Pages -{ - public class ViewDataModel : PageModel - { - public IList Items { get; set; } - public int? Editing { get; set; } - - private readonly ISession _session; - - public ViewDataModel(ISession session) - { - _session = session; - } - - public void OnGet(int? editing) - { - Editing = editing; - - using (var tx = _session.BeginTransaction()) - { - Items = _session.QueryOver().List(); - } - } - - public IActionResult OnPostEdit(int id) - { - return RedirectToPage(new {editing = id}); - } - - public IActionResult OnPostDelete(int id) - { - using (var tx = _session.BeginTransaction()) - { - var item = _session.Get(id); - if (item != null) - { - _session.Delete(item); - } - - tx.Commit(); - } - - return RedirectToPage(); - } - - public IActionResult OnPostUpdate(int id, UpdateItemEvent updateItem) - { - if (!ModelState.IsValid) - { - return Page(); - } - - using (var tx = _session.BeginTransaction()) - { - var item = _session.Get(id); - if (item != null) - { - item.Price = updateItem.Price; - item.Description = updateItem.Description; - _session.Update(item); - } - - tx.Commit(); - } - - return RedirectToPage(); - } - - public IActionResult OnPostCancelUpdate() - { - return RedirectToPage(); - } - - public class UpdateItemEvent - { - [Required, Range(0.0, double.MaxValue)] - public decimal Price { get; set; } - public string Description { get; set; } - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/_Layout.cshtml b/src/NHibernate.Example.Web/Pages/_Layout.cshtml deleted file mode 100644 index 7db516fb7d5..00000000000 --- a/src/NHibernate.Example.Web/Pages/_Layout.cshtml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - @ViewData["Title"] - - - - @RenderBody() - -

- @Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default.Application.RuntimeFramework -

- -@RenderSection("Scripts", required: false) - - diff --git a/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml b/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml deleted file mode 100644 index 935fef42347..00000000000 --- a/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@using NHibernate.Example.Web -@namespace NHibernate.Example.Web.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml b/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml deleted file mode 100644 index a5f10045db9..00000000000 --- a/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "_Layout"; -} diff --git a/src/NHibernate.Example.Web/Program.cs b/src/NHibernate.Example.Web/Program.cs deleted file mode 100644 index bf57dbb80fe..00000000000 --- a/src/NHibernate.Example.Web/Program.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Serilog; -using Serilog.Events; - -namespace NHibernate.Example.Web -{ - public class Program - { - public static void Main(string[] args) - { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) - .Enrich.FromLogContext() - .WriteTo.Console() - .CreateLogger(); - - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .UseSerilog() - .Build(); - } -} diff --git a/src/NHibernate.Example.Web/Properties/launchSettings.json b/src/NHibernate.Example.Web/Properties/launchSettings.json deleted file mode 100644 index a39df606d36..00000000000 --- a/src/NHibernate.Example.Web/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:60203/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "NHibernate.Example.Web": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:60204/" - } - } -} diff --git a/src/NHibernate.Example.Web/Startup.cs b/src/NHibernate.Example.Web/Startup.cs deleted file mode 100644 index 8d21a5e684d..00000000000 --- a/src/NHibernate.Example.Web/Startup.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using NHibernate.Example.Web.Infrastructure; - -namespace NHibernate.Example.Web -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddSingleton(); - services.AddScoped(x => x.GetService().OpenSession()); - - services.AddMvc(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - app.UseStaticFiles(); - - app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller}/{action=Index}/{id?}"); - }); - } - } -} diff --git a/src/NHibernate.Example.Web/appsettings.Development.json b/src/NHibernate.Example.Web/appsettings.Development.json deleted file mode 100644 index fa8ce71a97a..00000000000 --- a/src/NHibernate.Example.Web/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/src/NHibernate.Example.Web/appsettings.json b/src/NHibernate.Example.Web/appsettings.json deleted file mode 100644 index 5fff67bacc4..00000000000 --- a/src/NHibernate.Example.Web/appsettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Warning" - } - } -} From c9d0a951edaaaecfe591b806bc72bb0aa30fbb7c Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 25 Jul 2023 05:03:46 +0300 Subject: [PATCH 023/128] Fix BeforeAssemble call for Map and IdentifierBag (#3380) Fixup for #3365 --- .../Collection/Generic/PersistentGenericIdentifierBag.cs | 2 +- .../Async/Collection/Generic/PersistentGenericMap.cs | 4 ++-- .../Collection/Generic/PersistentGenericIdentifierBag.cs | 2 +- src/NHibernate/Collection/Generic/PersistentGenericMap.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs index af37fb8a1e0..1b8a8f57502 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -47,7 +47,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist var identifierType = persister.IdentifierType; var elementType = persister.ElementType; - for (int i = 0; i < size; i++) + for (int i = 0; i < size; i += 2) { await (identifierType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs index fbe6e30c490..3348087744a 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs @@ -94,10 +94,10 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); - + var indexType = persister.IndexType; var elementType = persister.ElementType; - for (int i = 0; i < size; i++) + for (int i = 0; i < size; i += 2) { await (indexType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); diff --git a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs index 71005049ad8..59769257121 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -78,7 +78,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object var identifierType = persister.IdentifierType; var elementType = persister.ElementType; - for (int i = 0; i < size; i++) + for (int i = 0; i < size; i += 2) { identifierType.BeforeAssemble(array[i], Session); elementType.BeforeAssemble(array[i + 1], Session); diff --git a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs index e81aee07578..24c4c30568e 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs @@ -163,10 +163,10 @@ public override void InitializeFromCache(ICollectionPersister persister, object object[] array = (object[])disassembled; int size = array.Length; BeforeInitialize(persister, size); - + var indexType = persister.IndexType; var elementType = persister.ElementType; - for (int i = 0; i < size; i++) + for (int i = 0; i < size; i += 2) { indexType.BeforeAssemble(array[i], Session); elementType.BeforeAssemble(array[i + 1], Session); From 5a38bd81b35ce2c243068ba16cf4af2b8da87246 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 26 Jul 2023 01:16:14 +0300 Subject: [PATCH 024/128] Move HqlToken.PossibleId to HqlParser.IsPossibleId method and remove castings (#3377) --- src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs | 71 ++++++++++------------- src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs | 9 ++- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index 6c05fc6c999..35e7a520565 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -147,8 +147,8 @@ public void WeakKeywords() // Case 2: The current token is after FROM and before '.'. if (t != IDENT && input.LA(-1) == FROM && ((input.LA(2) == DOT) || (input.LA(2) == IDENT) || (input.LA(2) == -1))) { - HqlToken hqlToken = input.LT(1) as HqlToken; - if (hqlToken != null && hqlToken.PossibleId) + var hqlToken = input.LT(1); + if (IsPossibleId(hqlToken)) { hqlToken.Type = IDENT; if (log.IsDebugEnabled()) @@ -192,8 +192,8 @@ public void WeakKeywords2() // Case 2: The current token is after FROM and before '.'. if (t != IDENT && input.LA(-1) == FROM && input.LA(2) == DOT) { - HqlToken hqlToken = (HqlToken)input.LT(1); - if (hqlToken.PossibleId) + var hqlToken = input.LT(1); + if (IsPossibleId(hqlToken)) { hqlToken.Type = IDENT; if (log.IsDebugEnabled()) @@ -290,16 +290,8 @@ public IASTNode NegateNode(IASTNode node) } } - public IASTNode ProcessEqualityExpression(object o) + public IASTNode ProcessEqualityExpression(IASTNode x) { - IASTNode x = o as IASTNode; - - if (x == null) - { - log.Warn("processEqualityExpression() : No expression to process!"); - return null; - } - int type = x.Type; if (type == EQ || type == NE) { @@ -336,11 +328,11 @@ public void HandleDotIdent() if (input.LA(1) == DOT && input.LA(2) != IDENT) { // See if the second lookahed token can be an identifier. - HqlToken t = input.LT(2) as HqlToken; - if (t != null && t.PossibleId) + var t = input.LT(2); + if (IsPossibleId(t)) { // Set it! - input.LT(2).Type = IDENT; + t.Type = IDENT; if (log.IsDebugEnabled()) { log.Debug("handleDotIdent() : new LT(2) token - {0}", input.LT(1)); @@ -401,37 +393,38 @@ public IASTNode ProcessMemberOf(IToken n, IASTNode p, IASTNode root) public IASTNode HandleIdentifierError(IToken token, RecognitionException ex) { - if (token is HqlToken) + // ... and the token could be an identifier and the error is + // a mismatched token error ... + if (IsPossibleId(token) && (ex is MismatchedTokenException mte) + // ... and the expected token type was an identifier, then: + && mte.Expecting == IDENT) { - HqlToken hqlToken = (HqlToken)token; + // Use the token as an identifier. + _parseErrorHandler.ReportWarning("Keyword '" + + token.Text + + "' is being interpreted as an identifier due to: " + mte.Message); - // ... and the token could be an identifer and the error is - // a mismatched token error ... - if (hqlToken.PossibleId && (ex is MismatchedTokenException)) - { - MismatchedTokenException mte = (MismatchedTokenException)ex; - - // ... and the expected token type was an identifier, then: - if (mte.Expecting == IDENT) - { - // Use the token as an identifier. - _parseErrorHandler.ReportWarning("Keyword '" - + token.Text - + "' is being interpreted as an identifier due to: " + mte.Message); + // Add the token to the AST. - // Add the token to the AST. + token.Type = WEIRD_IDENT; - token.Type = WEIRD_IDENT; - - input.Consume(); - return (IASTNode) adaptor.Create(token); - } - } + input.Consume(); + return (IASTNode) adaptor.Create(token); } - + // Otherwise, handle the error normally. ReflectHelper.PreserveStackTrace(ex); throw ex; } + + /// + /// Indicates if the token could be an identifier. + /// + /// + public static bool IsPossibleId(IToken token) + { + var type = token.Type; + return type >= 0 && type < possibleIds.Length && possibleIds[type]; + } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs index 7c2449b50e7..12d1b634534 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs @@ -39,10 +39,9 @@ public HqlToken(IToken other) /// /// Indicates if the token could be an identifier. /// - public bool PossibleId - { - get { return HqlParser.possibleIds[Type]; } - } + // Since 5.5 + [Obsolete("Use HqlParser.IsPossibleId method instead.")] + public bool PossibleId => HqlParser.IsPossibleId(this); /// /// Returns the previous token type. @@ -62,7 +61,7 @@ public override string ToString() + Text + "\",<" + Type + "> previously: <" + PreviousType + ">,line=" + Line + ",col=" - + CharPositionInLine + ",possibleID=" + PossibleId + "]"; + + CharPositionInLine + ",possibleID=" + HqlParser.IsPossibleId(this) + "]"; } } } From f38a6fd86c5bd15927a1d487c9911842f08ce152 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:20:56 +1000 Subject: [PATCH 025/128] Update dependency Microsoft.Data.SqlClient to v3.1.3 (#3102) --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 58a806329e7..a523ac5f94f 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -56,7 +56,7 @@ - + From c4c711d0aad46da4e058ef1d2006304971b75506 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 28 Jul 2023 08:17:25 +0300 Subject: [PATCH 026/128] Improve path rule handling with reserved words in Hql.g (#3384) Avoids handled exception when parsing queries with reserved words in path. --- .../Hql/Parser/HqlParserFixture.cs | 30 +++++++++++++++++++ .../Hql/Parser/WarningAsErrorReporter.cs | 29 ++++++++++++++++++ src/NHibernate.Test/NHibernate.Test.csproj | 3 ++ src/NHibernate/Hql/Ast/ANTLR/Hql.g | 5 ++-- src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs | 21 +++++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs create mode 100644 src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs diff --git a/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs new file mode 100644 index 00000000000..9eb0095ea37 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs @@ -0,0 +1,30 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NUnit.Framework; + +namespace NHibernate.Test.Hql.Parser +{ + [TestFixture] + public class HqlParserFixture + { + [Test] + public void HandlesPathWithReservedWords() + { + Assert.DoesNotThrow(() => Parse("delete from System.Object")); + Assert.DoesNotThrow(() => Parse("delete from Object.Object.Object.Object")); + } + + private static void Parse(string hql) + { + var lex = new HqlLexer(new CaseInsensitiveStringStream(hql)); + var tokens = new CommonTokenStream(lex); + + var parser = new HqlParser(tokens) + { + TreeAdaptor = new ASTTreeAdaptor(), + ParseErrorHandler = new WarningAsErrorReporter() + }.statement(); + } + } +} diff --git a/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs new file mode 100644 index 00000000000..5897d670698 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs @@ -0,0 +1,29 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; + +namespace NHibernate.Test.Hql.Parser +{ + public class WarningAsErrorReporter : IParseErrorHandler + { + public void ReportError(RecognitionException e) + { + throw e; + } + + public void ReportError(string s) + { + throw new QueryException(s); + } + + public void ReportWarning(string s) + { + throw new QueryException(s); + } + + public int GetErrorCount() => 0; + + public void ThrowQueryException() + { + } + } +} diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index a523ac5f94f..a3770c40cbf 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -46,6 +46,9 @@ + + Hql\Parser\CaseInsensitiveStringStream.cs + UtilityTest\AsyncReaderWriterLock.cs diff --git a/src/NHibernate/Hql/Ast/ANTLR/Hql.g b/src/NHibernate/Hql/Ast/ANTLR/Hql.g index 364c9142711..fa4d5467f72 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Hql.g +++ b/src/NHibernate/Hql/Ast/ANTLR/Hql.g @@ -695,10 +695,9 @@ constant path @init { -// TODO - need to clean up DotIdent - suspect that DotIdent2 supersedes the other one, but need to do the analysis -//HandleDotIdent2(); +HandleDotIdents(); } - : identifier ( DOT^ { WeakKeywords(); } identifier )* + : identifier ( DOT^ identifier )* ; // Wraps the IDENT token from the lexer, in order to provide diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index 35e7a520565..764cccdf873 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -112,6 +112,27 @@ protected override object RecoverFromMismatchedToken(IIntStream input, int ttype throw new MismatchedTokenException(ttype, input); } + public void HandleDotIdents() + { + int i = 2; + + while (input.LA(i) == DOT) + { + var next = input.LT(i + 1); + if (next != null) + next.Type = IDENT; + i += 2; + } + + if (input.LA(1) == IDENT || input.LA(2) != DOT) + return; + + if (IsPossibleId(input.LT(1))) + { + input.LT(1).Type = IDENT; + } + } + public void WeakKeywords() { int t = input.LA(1); From dd17017b658adc1e90bfba0d2bfea2fb5d9518f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 30 Jul 2023 20:52:55 +0200 Subject: [PATCH 027/128] Release 5.4.4 (#3386) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 87df1acdbd8..403c50e24a6 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.4 4 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index 1a7f3e97521..a15d6949d9d 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,27 @@ -Build 5.4.3 +Build 5.4.4 +============================= + +Release notes - NHibernate - Version 5.4.4 + +6 issues were resolved in this release. + +** Bug + + * #3359 2nd level cache GetMany ineffective for collections + * #3354 Invalid program generated by FieldInterceptorProxyBuilder for indexer property getter + * #3352 Fetch throws "could not resolve property" error for a property that is not mapped + +** Improvement + + * #3368 Allow internal entity classes/interfaces in .NET Standard 2.0 for field interceptor + +** Task + + * #3386 Release 5.4.4 + * #3367 Update readme with actual dev build information for 5.4 + + +Build 5.4.3 ============================= Release notes - NHibernate - Version 5.4.3 From d6fd1dcedff65571baf7e8b59dc4b88c508d312b Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 1 Aug 2023 16:52:01 +0300 Subject: [PATCH 028/128] Enable Not node handling in HqlParser.NegateNode (#3390) --- .../Async/NHSpecificTest/GH3327/Fixture.cs | 16 ++++++++++++++++ .../NHSpecificTest/GH3327/Fixture.cs | 16 ++++++++++++++++ src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs | 6 ++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs index b34a71f1317..dd487c61382 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs @@ -59,5 +59,21 @@ WHERE NOT ( )"); Assert.That((await (q.ListAsync()))[0], Is.EqualTo(0)); } + + [Test] + public async Task NotNotExistsNegatedAsync() + { + using var log = new SqlLogSpy(); + using var session = OpenSession(); + var results = await (session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + NOT EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND NOT ROOT.Name = 'Parent' + )").ListAsync()); + Assert.That(log.GetWholeLog(), Does.Not.Contains(" NOT ").IgnoreCase); + Assert.That(results.Count, Is.EqualTo(1)); + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs index aef1a40243e..31efc796ed1 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs @@ -48,5 +48,21 @@ WHERE NOT ( )"); Assert.That(q.List()[0], Is.EqualTo(0)); } + + [Test] + public void NotNotExistsNegated() + { + using var log = new SqlLogSpy(); + using var session = OpenSession(); + var results = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + NOT EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND NOT ROOT.Name = 'Parent' + )").List(); + Assert.That(log.GetWholeLog(), Does.Not.Contains(" NOT ").IgnoreCase); + Assert.That(results.Count, Is.EqualTo(1)); + } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index 764cccdf873..c59f2a99a03 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -300,10 +300,8 @@ public IASTNode NegateNode(IASTNode node) node.Type = BETWEEN; node.Text = "{not}" + node.Text; return node; // (NOT (NOT_BETWEEN a b) ) => (BETWEEN a b) - /* This can never happen because this rule will always eliminate the child NOT. - case NOT: - return x.getFirstChild(); // (NOT (NOT x) ) => (x) - */ + case NOT: + return node.GetChild(0); // (NOT (NOT x) ) => (x) default: IASTNode not = (IASTNode) TreeAdaptor.Create(NOT, "not"); not.AddChild(node); From 494917424e599e702d2c0540c10a8fa9065f6448 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 1 Aug 2023 22:23:04 +0300 Subject: [PATCH 029/128] Use table group joins for many-to-many in Criteria and Entity loaders (#2687) Possible breaking change: Default not-found behavior now works correctly for many-to-many in Criteria so now it throws ObjectNotFoundException exception on many-to-many Criteria fetch for not found records. --- ...ixture.cs => ManyToManyFilteredFixture.cs} | 39 +++-- ....cs => ManyToManyNotFoundIgnoreFixture.cs} | 136 ++++++++++------ .../ManyToManyThrowsForNotFoundFixture.cs | 85 ++++++++++ .../ManyToManyPropertyRefFixture.cs | 23 ++- ...ixture.cs => ManyToManyFilteredFixture.cs} | 39 +++-- .../NHSpecificTest/GH1994/Mappings.hbm.xml | 6 +- .../NHSpecificTest/NH750/Device.cs | 9 +- .../NHSpecificTest/NH750/Fixture.cs | 113 ------------- .../NH750/ManyToManyNotFoundIgnoreFixture.cs | 151 ++++++++++++++++++ .../ManyToManyThrowsForNotFoundFixture.cs | 74 +++++++++ .../NHSpecificTest/NH750/Mappings.hbm.xml | 6 +- .../ManyToManyPropertyRefFixture.cs | 23 ++- .../Loader/AbstractEntityJoinWalker.cs | 2 +- src/NHibernate/Loader/JoinWalker.cs | 68 ++++---- .../Loader/OuterJoinableAssociation.cs | 14 +- .../Collection/AbstractCollectionPersister.cs | 9 +- .../Collection/BasicCollectionPersister.cs | 44 +---- .../Collection/OneToManyPersister.cs | 8 +- .../Entity/AbstractEntityPersister.cs | 9 +- .../Entity/ISupportSelectModeJoinable.cs | 2 +- 20 files changed, 581 insertions(+), 279 deletions(-) rename src/NHibernate.Test/Async/NHSpecificTest/GH1994/{Fixture.cs => ManyToManyFilteredFixture.cs} (83%) rename src/NHibernate.Test/Async/NHSpecificTest/NH750/{Fixture.cs => ManyToManyNotFoundIgnoreFixture.cs} (51%) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs rename src/NHibernate.Test/NHSpecificTest/GH1994/{Fixture.cs => ManyToManyFilteredFixture.cs} (82%) delete mode 100644 src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs similarity index 83% rename from src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs rename to src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs index ff47bd2ad14..0c930f421f3 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs @@ -10,7 +10,6 @@ using System.Linq; using NHibernate.Criterion; -using NHibernate.Dialect; using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; @@ -20,7 +19,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1994 { using System.Threading.Tasks; [TestFixture] - public class FixtureAsync : BugTestCase + public class ManyToManyFilteredFixtureAsync : BugTestCase { protected override void OnSetUp() { @@ -41,14 +40,7 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.Delete("from System.Object"); - transaction.Commit(); } } @@ -70,9 +62,6 @@ public async Task TestUnfilteredLinqQueryAsync() [Test] public async Task TestFilteredByWhereCollectionLinqQueryAsync() { - if(Dialect is PostgreSQLDialect) - Assert.Ignore("Dialect doesn't support 0/1 to bool implicit cast"); - using (var s = OpenSession()) { var query = await (s.Query() @@ -150,5 +139,31 @@ public async Task TestQueryOverRestrictionWithClauseAsync() Assert.That(query[0].Documents.Count, Is.EqualTo(1), "filtered asset documents"); } } + + [Test] + public async Task LazyLoadAsync() + { + using (var s = OpenSession()) + { + var asset = await (s.Query().FirstAsync()); + Assert.That(asset.Documents.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } + + [Test] + public async Task LazyLoadFilteredAsync() + { + using (var s = OpenSession()) + { + s.EnableFilter("deletedFilter").SetParameter("deletedParam", false); + + var asset = await (s.Query().FirstAsync()); + Assert.That(asset.Documents.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs similarity index 51% rename from src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs rename to src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs index 07df8065629..2ab73df8d3a 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -10,78 +10,72 @@ using System; using NHibernate.Cfg; +using NHibernate.Criterion; +using NHibernate.Transform; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH750 { using System.Threading.Tasks; [TestFixture] - public class FixtureAsync : BugTestCase + public class ManyToManyNotFoundIgnoreFixtureAsync : BugTestCase { - protected override void OnTearDown() - { - using (ISession s = Sfi.OpenSession()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - s.Flush(); - } - } + private int id1; + private int id2; - protected override void Configure(Configuration configuration) + protected override void OnSetUp() { - configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); - base.Configure(configuration); - } - - [Test] - public async Task DeviceOfDriveAsync() - { - int[] dvSavedId = new int[2]; Drive dr1 = new Drive("Drive 1"); Drive dr2 = new Drive("Drive 2"); Drive dr3 = new Drive("Drive 3"); Device dv1 = new Device("Device 1"); Device dv2 = new Device("Device 2"); - using (ISession s = Sfi.OpenSession()) + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) { - await (s.SaveAsync(dr1)); - await (s.SaveAsync(dr2)); - await (s.SaveAsync(dr3)); - dvSavedId[0] = (int) await (s.SaveAsync(dv1)); - dvSavedId[1] = (int) await (s.SaveAsync(dv2)); - await (s.FlushAsync()); + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + dv1.Drives.Add(dr1); + dv1.Drives.Add(dr2); + dv2.Drives.Add(dr1); + dv2.Drives.Add(dr3); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); } + } - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); + protected override void OnTearDown() + { using (ISession s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) { - dvSavedId[0] = (int) await (s.SaveAsync(dv1)); - dvSavedId[1] = (int) await (s.SaveAsync(dv2)); - await (s.FlushAsync()); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); } - dv1 = null; - dv2 = null; + } + + [Test] + public async Task DeviceOfDriveAsync() + { + Device dv1; + Device dv2; using (ISession s = Sfi.OpenSession()) { - await (s.DeleteAsync(dr3)); - await (s.FlushAsync()); - dv1 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[0])); - dv2 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[1])); + dv1 = (Device) await (s.LoadAsync(typeof(Device), id1)); + dv2 = (Device) await (s.LoadAsync(typeof(Device), id2)); } - Assert.AreEqual(2, dv1.Drives.Count); - // Verify one is missing - Assert.AreEqual(1, dv2.Drives.Count); - // Verify dv1 unchanged - Assert.IsTrue(dv1.Drives.Contains(dr1)); - Assert.IsTrue(dv1.Drives.Contains(dr2)); - // Verify dv2 - Assert.IsTrue(dv2.Drives.Contains(dr1)); - Assert.IsFalse(dv2.Drives.Contains(dr3)); + Assert.That(dv1.Drives, Has.Count.EqualTo(2).And.None.Null); + // Verify one is missing + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); //Make sure that flush didn't touch not-found="ignore" records for not modified collection using (var s = Sfi.OpenSession()) @@ -99,7 +93,7 @@ public async Task DeviceOfDriveAsync() using (var t = s.BeginTransaction()) { dv2 = await (s.GetAsync(dv2.Id)); - dv2.Drives.Add(dr2); + dv2.Drives.Add(dv1.Drives[1]); await (t.CommitAsync()); } @@ -120,5 +114,49 @@ async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string } } } + + [Test] + public async Task QueryOverFetchAsync() + { + using (var s = OpenSession()) + { + var dv2 = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } + + [Test] + public async Task HqlFetchAsync() + { + using (var s = OpenSession()) + { + var dv2 = await (s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } + + [Test] + public async Task LazyLoadAsync() + { + using (var s = OpenSession()) + { + var dv2 = await (s.GetAsync(id2)); + await (NHibernateUtil.InitializeAsync(dv2.Drives)); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs new file mode 100644 index 00000000000..59b6a0044bf --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NHibernate.Criterion; +using NHibernate.Linq; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + using System.Threading.Tasks; + [TestFixture] + public class ManyToManyThrowsForNotFoundFixtureAsync : BugTestCase + { + private int _id; + + protected override void OnSetUp() + { + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); + + _id = (int) s.Save(dv); + s.Flush(); + + s.Clear(); + s.Delete(dr); + t.Commit(); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + } + + [Test] + public async Task LazyLoadAsync() + { + using var s = OpenSession(); + var device = await (s.GetAsync(_id)); + Assert.ThrowsAsync(() => NHibernateUtil.InitializeAsync(device.DrivesNotIgnored)); + } + + [Test] + public void QueryOverFetchAsync() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(_id)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (queryOver.SingleOrDefaultAsync())))); + } + + [Test] + public void LinqFetchAsync() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.DrivesNotIgnored) + .Where(x => x.Id == _id); + Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync())))); + } + } +} diff --git a/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs b/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs index 1bb2716733f..435758ac99e 100644 --- a/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs +++ b/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs @@ -8,20 +8,22 @@ //------------------------------------------------------------------------------ +using System.Linq; using NHibernate.Criterion; +using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.PropertyRef { using System.Threading.Tasks; - [TestFixture] + [TestFixture(Description = "NH-2180 (GH-1214)")] public class ManyToManyPropertyRefFixtureAsync : TestCase { protected override string[] Mappings => new[] { "PropertyRef.ManyToManyWithPropertyRef.hbm.xml" }; protected override string MappingsAssembly => "NHibernate.Test"; - private object _manyAId; + private long _manyAId; protected override void OnSetUp() { @@ -34,7 +36,7 @@ protected override void OnSetUp() var manyB2 = new ManyB { Number = 8, Value = "a value of b2" }; var manyB3 = new ManyB { Number = 12, Value = "a value of b3" }; - _manyAId = session.Save(manyA); + _manyAId = (long) session.Save(manyA); session.Save(manyB1); session.Save(manyB2); session.Save(manyB3); @@ -144,5 +146,20 @@ bei NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueK Assert.That(loadedManyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); } + + [Test] + public async Task LinqFetchAsync() + { + using (var session = OpenSession()) + { + var manyA = (await (session + .Query() + .Where(a => a.Id == _manyAId) + .FetchMany(a => a.ManyBs) + .ToListAsync())) + .First(); + Assert.That(manyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs similarity index 82% rename from src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs rename to src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs index 5dbe043ebfe..4edb09d5cb1 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs @@ -1,6 +1,5 @@ using System.Linq; using NHibernate.Criterion; -using NHibernate.Dialect; using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; @@ -9,7 +8,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1994 { [TestFixture] - public class Fixture : BugTestCase + public class ManyToManyFilteredFixture : BugTestCase { protected override void OnSetUp() { @@ -30,14 +29,7 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.Delete("from System.Object"); - transaction.Commit(); } } @@ -59,9 +51,6 @@ public void TestUnfilteredLinqQuery() [Test] public void TestFilteredByWhereCollectionLinqQuery() { - if(Dialect is PostgreSQLDialect) - Assert.Ignore("Dialect doesn't support 0/1 to bool implicit cast"); - using (var s = OpenSession()) { var query = s.Query() @@ -139,5 +128,31 @@ public void TestQueryOverRestrictionWithClause() Assert.That(query[0].Documents.Count, Is.EqualTo(1), "filtered asset documents"); } } + + [Test] + public void LazyLoad() + { + using (var s = OpenSession()) + { + var asset = s.Query().First(); + Assert.That(asset.Documents.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } + + [Test] + public void LazyLoadFiltered() + { + using (var s = OpenSession()) + { + s.EnableFilter("deletedFilter").SetParameter("deletedParam", false); + + var asset = s.Query().First(); + Assert.That(asset.Documents.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml index 449a4b8bc97..dba718ccde7 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml @@ -5,7 +5,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs index 7a77e8b2e04..897045acaf6 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs @@ -33,11 +33,18 @@ public string Manifacturer } private IList _drives = new List(); + private IList _drivesNotIgnored = new List(); public IList Drives { get { return _drives; } set { _drives = value; } } + + public IList DrivesNotIgnored + { + get => _drivesNotIgnored; + set => _drivesNotIgnored = value; + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs deleted file mode 100644 index b766cd8b87e..00000000000 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using NHibernate.Cfg; -using NUnit.Framework; - -namespace NHibernate.Test.NHSpecificTest.NH750 -{ - [TestFixture] - public class Fixture : BugTestCase - { - protected override void OnTearDown() - { - using (ISession s = Sfi.OpenSession()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - s.Flush(); - } - } - - protected override void Configure(Configuration configuration) - { - configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); - base.Configure(configuration); - } - - [Test] - public void DeviceOfDrive() - { - int[] dvSavedId = new int[2]; - Drive dr1 = new Drive("Drive 1"); - Drive dr2 = new Drive("Drive 2"); - Drive dr3 = new Drive("Drive 3"); - Device dv1 = new Device("Device 1"); - Device dv2 = new Device("Device 2"); - using (ISession s = Sfi.OpenSession()) - { - s.Save(dr1); - s.Save(dr2); - s.Save(dr3); - dvSavedId[0] = (int) s.Save(dv1); - dvSavedId[1] = (int) s.Save(dv2); - s.Flush(); - } - - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); - using (ISession s = Sfi.OpenSession()) - { - dvSavedId[0] = (int) s.Save(dv1); - dvSavedId[1] = (int) s.Save(dv2); - s.Flush(); - } - dv1 = null; - dv2 = null; - using (ISession s = Sfi.OpenSession()) - { - s.Delete(dr3); - s.Flush(); - dv1 = (Device) s.Load(typeof(Device), dvSavedId[0]); - dv2 = (Device) s.Load(typeof(Device), dvSavedId[1]); - } - Assert.AreEqual(2, dv1.Drives.Count); - // Verify one is missing - Assert.AreEqual(1, dv2.Drives.Count); - // Verify dv1 unchanged - Assert.IsTrue(dv1.Drives.Contains(dr1)); - Assert.IsTrue(dv1.Drives.Contains(dr2)); - - // Verify dv2 - Assert.IsTrue(dv2.Drives.Contains(dr1)); - Assert.IsFalse(dv2.Drives.Contains(dr3)); - - //Make sure that flush didn't touch not-found="ignore" records for not modified collection - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = s.Get(dv2.Id); - s.Flush(); - t.Commit(); - } - - VerifyResult(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection"); - - //Many-to-many clears collection and recreates it so not-found ignore records are lost - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = s.Get(dv2.Id); - dv2.Drives.Add(dr2); - t.Commit(); - } - - VerifyResult(2, 2, msg: "modified collection"); - - void VerifyResult(int expectedInCollection, int expectedInDb, string msg) - { - using (var s = Sfi.OpenSession()) - { - var realCound = Convert.ToInt32( - s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") - .SetParameter("id", dv2.Id) - .UniqueResult()); - dv2 = s.Get(dv2.Id); - - Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); - Assert.That(realCound, Is.EqualTo(expectedInDb), msg); - } - } - } - } -} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs new file mode 100644 index 00000000000..ecff1b3486b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -0,0 +1,151 @@ +using System; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture] + public class ManyToManyNotFoundIgnoreFixture : BugTestCase + { + private int id1; + private int id2; + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + dv1.Drives.Add(dr1); + dv1.Drives.Add(dr2); + dv2.Drives.Add(dr1); + dv2.Drives.Add(dr3); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); + } + } + + protected override void OnTearDown() + { + using (ISession s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + } + + [Test] + public void DeviceOfDrive() + { + Device dv1; + Device dv2; + using (ISession s = Sfi.OpenSession()) + { + dv1 = (Device) s.Load(typeof(Device), id1); + dv2 = (Device) s.Load(typeof(Device), id2); + } + + Assert.That(dv1.Drives, Has.Count.EqualTo(2).And.None.Null); + // Verify one is missing + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + + //Make sure that flush didn't touch not-found="ignore" records for not modified collection + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = s.Get(dv2.Id); + s.Flush(); + t.Commit(); + } + + VerifyResult(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection"); + + //Many-to-many clears collection and recreates it so not-found ignore records are lost + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = s.Get(dv2.Id); + dv2.Drives.Add(dv1.Drives[1]); + t.Commit(); + } + + VerifyResult(2, 2, msg: "modified collection"); + + void VerifyResult(int expectedInCollection, int expectedInDb, string msg) + { + using (var s = Sfi.OpenSession()) + { + var realCound = Convert.ToInt32( + s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") + .SetParameter("id", dv2.Id) + .UniqueResult()); + dv2 = s.Get(dv2.Id); + + Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); + Assert.That(realCound, Is.EqualTo(expectedInDb), msg); + } + } + } + + [Test] + public void QueryOverFetch() + { + using (var s = OpenSession()) + { + var dv2 = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } + + [Test] + public void HqlFetch() + { + using (var s = OpenSession()) + { + var dv2 = s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } + + [Test] + public void LazyLoad() + { + using (var s = OpenSession()) + { + var dv2 = s.Get(id2); + NHibernateUtil.Initialize(dv2.Drives); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs new file mode 100644 index 00000000000..bef312c398c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -0,0 +1,74 @@ +using System.Linq; +using NHibernate.Criterion; +using NHibernate.Linq; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture] + public class ManyToManyThrowsForNotFoundFixture : BugTestCase + { + private int _id; + + protected override void OnSetUp() + { + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); + + _id = (int) s.Save(dv); + s.Flush(); + + s.Clear(); + s.Delete(dr); + t.Commit(); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + } + + [Test] + public void LazyLoad() + { + using var s = OpenSession(); + var device = s.Get(_id); + Assert.Throws(() => NHibernateUtil.Initialize(device.DrivesNotIgnored)); + } + + [Test] + public void QueryOverFetch() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(_id)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.Throws(() => NHibernateUtil.Initialize(queryOver.SingleOrDefault())); + } + + [Test] + public void LinqFetch() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.DrivesNotIgnored) + .Where(x => x.Id == _id); + Assert.Throws(() => NHibernateUtil.Initialize(query.SingleOrDefault())); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml index 6a100d7926d..56d7c9c5927 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml @@ -5,7 +5,7 @@ default-access="field.camelcase-underscore" default-lazy="false"> - + @@ -13,6 +13,10 @@ + + + + diff --git a/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs b/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs index 054cba44957..9ecb5dd4377 100644 --- a/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs +++ b/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs @@ -1,16 +1,18 @@ +using System.Linq; using NHibernate.Criterion; +using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.PropertyRef { - [TestFixture] + [TestFixture(Description = "NH-2180 (GH-1214)")] public class ManyToManyPropertyRefFixture : TestCase { protected override string[] Mappings => new[] { "PropertyRef.ManyToManyWithPropertyRef.hbm.xml" }; protected override string MappingsAssembly => "NHibernate.Test"; - private object _manyAId; + private long _manyAId; protected override void OnSetUp() { @@ -23,7 +25,7 @@ protected override void OnSetUp() var manyB2 = new ManyB { Number = 8, Value = "a value of b2" }; var manyB3 = new ManyB { Number = 12, Value = "a value of b3" }; - _manyAId = session.Save(manyA); + _manyAId = (long) session.Save(manyA); session.Save(manyB1); session.Save(manyB2); session.Save(manyB3); @@ -133,5 +135,20 @@ bei NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueK Assert.That(loadedManyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); } + + [Test] + public void LinqFetch() + { + using (var session = OpenSession()) + { + var manyA = session + .Query() + .Where(a => a.Id == _manyAId) + .FetchMany(a => a.ManyBs) + .ToList() + .First(); + Assert.That(manyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); + } + } } } diff --git a/src/NHibernate/Loader/AbstractEntityJoinWalker.cs b/src/NHibernate/Loader/AbstractEntityJoinWalker.cs index 4eb40d53210..606c55423d1 100644 --- a/src/NHibernate/Loader/AbstractEntityJoinWalker.cs +++ b/src/NHibernate/Loader/AbstractEntityJoinWalker.cs @@ -121,7 +121,7 @@ private void InitStatementString(OuterJoinableAssociation rootAssociation, SqlSt Suffixes = BasicLoader.GenerateSuffixes(joins + 1); var suffix = Suffixes[joins]; - selectClause = new SqlString(rootAssociation.GetSelectFragment(suffix, null, null) + SelectString(associations)); + selectClause = new SqlString(rootAssociation.GetSelectFragment(suffix, null) + SelectString(associations)); } JoinFragment ojf = MergeOuterJoins(associations); diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index e2650582718..5fa910eb48f 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text.RegularExpressions; using NHibernate.Collection; using NHibernate.Engine; @@ -884,41 +883,51 @@ protected JoinFragment MergeOuterJoins(IList associati JoinFragment outerjoin = Dialect.CreateOuterJoinFragment(); var sortedAssociations = GetSortedAssociations(associations); - OuterJoinableAssociation last = null; - foreach (OuterJoinableAssociation oj in sortedAssociations) + for (var index = 0; index < sortedAssociations.Count; index++) { - if (last != null && last.IsManyToManyWith(oj)) + OuterJoinableAssociation oj = sortedAssociations[index]; + if (oj.IsCollection && oj.Joinable is IQueryableCollection qc && qc.IsManyToMany && index < sortedAssociations.Count - 1) { - oj.AddManyToManyJoin(outerjoin, (IQueryableCollection) last.Joinable); + var entityAssociation = sortedAssociations[index + 1]; + var f = qc.GetManyToManyFilterFragment(entityAssociation.RHSAlias, enabledFilters); + if (oj.IsManyToManyWith(entityAssociation) + && TableGroupJoinHelper.ProcessAsTableGroupJoin( + new[] {oj, entityAssociation}, + new[] {oj.On, entityAssociation.On, string.IsNullOrEmpty(f) ? SqlString.Empty : new SqlString(f)}, + true, + outerjoin, + alias => true, + factory)) + { + index++; + continue; + } } - else + + // NH Different behavior : NH1179 and NH1293 + // Apply filters for entity joins and Many-To-One associations + SqlString filter = null; + var enabledFiltersForJoin = oj.ForceFilter ? enabledFilters : enabledFiltersForManyToOne; + if (oj.ForceFilter || enabledFiltersForJoin.Count > 0) { - // NH Different behavior : NH1179 and NH1293 - // Apply filters for entity joins and Many-To-One associations - SqlString filter = null; - var enabledFiltersForJoin = oj.ForceFilter ? enabledFilters : enabledFiltersForManyToOne; - if (oj.ForceFilter || enabledFiltersForJoin.Count > 0) + string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForJoin); + bool joinClauseDoesNotContainsFilterAlready = + oj.On?.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; + if (joinClauseDoesNotContainsFilterAlready) { - string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForJoin); - bool joinClauseDoesNotContainsFilterAlready = - oj.On?.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; - if (joinClauseDoesNotContainsFilterAlready) - { - filter = new SqlString(manyToOneFilterFragment); - } + filter = new SqlString(manyToOneFilterFragment); } + } - if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] {oj}, new[] {oj.On, filter}, true, outerjoin, alias => true, factory)) - continue; + if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] {oj}, new[] {oj.On, filter}, true, outerjoin, alias => true, factory)) + continue; - oj.AddJoins(outerjoin); + oj.AddJoins(outerjoin); - // Ensure that the join condition is added to the join, not the where clause. - // Adding the condition to the where clause causes left joins to become inner joins. - if (SqlStringHelper.IsNotEmpty(filter)) - outerjoin.AddFromFragmentString(filter); - } - last = oj; + // Ensure that the join condition is added to the join, not the where clause. + // Adding the condition to the where clause causes left joins to become inner joins. + if (SqlStringHelper.IsNotEmpty(filter)) + outerjoin.AddFromFragmentString(filter); } return outerjoin; @@ -1212,7 +1221,6 @@ public string SelectString(IList associations) for (int i = 0; i < associations.Count; i++) { OuterJoinableAssociation join = associations[i]; - OuterJoinableAssociation next = (i == associations.Count - 1) ? null : associations[i + 1]; IJoinable joinable = join.Joinable; string entitySuffix = (suffixes == null || entityAliasCount >= suffixes.Length) ? null : suffixes[entityAliasCount]; @@ -1221,7 +1229,7 @@ public string SelectString(IList associations) ? null : collectionSuffixes[collectionAliasCount]; - string selectFragment = join.GetSelectFragment(entitySuffix, collectionSuffix, next); + string selectFragment = join.GetSelectFragment(entitySuffix, collectionSuffix); if (!string.IsNullOrWhiteSpace(selectFragment)) { @@ -1243,7 +1251,7 @@ public string SelectString(IList associations) [Obsolete("This method has no more usages and will be removed in a future version")] protected static string GetSelectFragment(OuterJoinableAssociation join, string entitySuffix, string collectionSuffix, OuterJoinableAssociation next = null) { - return join.GetSelectFragment(entitySuffix, collectionSuffix, next); + return join.GetSelectFragment(entitySuffix, collectionSuffix); } protected interface IJoinQueueEntry diff --git a/src/NHibernate/Loader/OuterJoinableAssociation.cs b/src/NHibernate/Loader/OuterJoinableAssociation.cs index 47a2e01e613..74180f89408 100644 --- a/src/NHibernate/Loader/OuterJoinableAssociation.cs +++ b/src/NHibernate/Loader/OuterJoinableAssociation.cs @@ -169,6 +169,8 @@ public bool IsManyToManyWith(OuterJoinableAssociation other) return false; } + //Since 5.4 + [Obsolete("This method is not used anymore and will be removed in a next major version")] public void AddManyToManyJoin(JoinFragment outerjoin, IQueryableCollection collection) { string manyToManyFilter = collection.GetManyToManyFilterFragment(rhsAlias, enabledFilters); @@ -204,7 +206,7 @@ internal bool ShouldFetchCollectionPersister() throw new ArgumentOutOfRangeException(nameof(SelectMode), SelectMode.ToString()); } - internal string GetSelectFragment(string entitySuffix, string collectionSuffix, OuterJoinableAssociation next) + internal string GetSelectFragment(string entitySuffix, string collectionSuffix) { switch (SelectMode) { @@ -212,8 +214,8 @@ internal string GetSelectFragment(string entitySuffix, string collectionSuffix, case SelectMode.Fetch: #pragma warning disable 618 return Joinable.SelectFragment( - next?.Joinable, - next?.RHSAlias, + null, + null, RHSAlias, entitySuffix, collectionSuffix, @@ -224,8 +226,8 @@ internal string GetSelectFragment(string entitySuffix, string collectionSuffix, #pragma warning disable 618 return ReflectHelper.CastOrThrow(Joinable, "fetch lazy properties") .SelectFragment( - next?.Joinable, - next?.RHSAlias, + null, + null, RHSAlias, entitySuffix, collectionSuffix, @@ -236,8 +238,6 @@ internal string GetSelectFragment(string entitySuffix, string collectionSuffix, case SelectMode.FetchLazyPropertyGroup: return ReflectHelper.CastOrThrow(Joinable, "fetch lazy property") .SelectFragment( - next?.Joinable, - next?.RHSAlias, RHSAlias, collectionSuffix, ShouldFetchCollectionPersister(), diff --git a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs index 612900b989b..a5c18cf92cb 100644 --- a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs @@ -1777,8 +1777,15 @@ public virtual string SelectFragment( return SelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = true}); } - //6.0 TODO: Make abstract + // 6.0 TODO: Remove + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public virtual string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string currentCollectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, currentCollectionSuffix, includeCollectionColumns, entityInfo); + } + + // 6.0 TODO: Make abstract + public virtual string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { throw new NotImplementedException("SelectFragment with fetching lazy properties option is not implemented by " + GetType().FullName); } diff --git a/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs b/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs index 65eb87b0724..d28a1a5b7ee 100644 --- a/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs @@ -262,51 +262,15 @@ protected override int DoUpdateRows(object id, IPersistentCollection collection, } } + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { - // we need to determine the best way to know that two joinables - // represent a single many-to-many... - if (rhs != null && IsManyToMany && !rhs.IsCollection) - { - IAssociationType elementType = (IAssociationType) ElementType; - if (rhs.Equals(elementType.GetAssociatedJoinable(Factory))) - { - return ManyToManySelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, elementType); - } - } - return includeCollectionColumns - ? GetSelectFragment(lhsAlias, collectionSuffix).ToSqlStringFragment(false) - : string.Empty; + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); } - private string ManyToManySelectFragment( - IJoinable rhs, - string rhsAlias, - string lhsAlias, - string collectionSuffix, - IAssociationType elementType) + public override string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { - SelectFragment frag = GenerateSelectFragment(lhsAlias, collectionSuffix); - - // We need to select in the associated entity table instead of taking the collection actual element, - // because filters can be applied to the entity table outer join. In such case, we need to return null - // for filtered-out elements. (It is tempting to switch to an inner join and just use - // SelectFragment(lhsAlias, collectionSuffix) for many-to-many too, but this would hinder the proper - // handling of the not-found feature.) - var elementColumnNames = string.IsNullOrEmpty(elementType.RHSUniqueKeyPropertyName) - ? rhs.KeyColumnNames - // rhs is the entity persister, it does not handle being referenced through an unique key by a - // collection and always yield its identifier columns as KeyColumnNames. We need to resolve the - // key columns instead. - // 6.0 TODO: consider breaking again that IJoinable.SelectFragment interface for transmitting - // the OuterJoinableAssociation instead of its Joinable property. This would allow to get the - // adequate columns directly instead of re-computing them. - : ((IPropertyMapping) rhs).ToColumns(elementType.RHSUniqueKeyPropertyName); - frag.AddColumns(rhsAlias, elementColumnNames, elementColumnAliases); - AppendIndexColumns(frag, lhsAlias); - AppendIdentifierColumns(frag, lhsAlias); - - return frag.ToSqlStringFragment(false); + return includeCollectionColumns ? GetSelectFragment(lhsAlias, collectionSuffix).ToSqlStringFragment(false) : string.Empty; } /// diff --git a/src/NHibernate/Persister/Collection/OneToManyPersister.cs b/src/NHibernate/Persister/Collection/OneToManyPersister.cs index 2973deec937..2f525fe65f0 100644 --- a/src/NHibernate/Persister/Collection/OneToManyPersister.cs +++ b/src/NHibernate/Persister/Collection/OneToManyPersister.cs @@ -294,7 +294,13 @@ protected override int DoUpdateRows(object id, IPersistentCollection collection, } } + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); + } + + public override string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { var buf = new StringBuilder(); @@ -317,7 +323,7 @@ public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhs { var selectMode = ReflectHelper.CastOrThrow(ElementPersister, "fetch lazy properties"); if (selectMode != null) - return buf.Append(selectMode.SelectFragment(null, null, lhsAlias, null, false, entityInfo)).ToString(); + return buf.Append(selectMode.SelectFragment(lhsAlias, null, false, entityInfo)).ToString(); } var ojl = (IOuterJoinLoadable)ElementPersister; diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 5e2f3e4748d..205fdb1f212 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -4461,10 +4461,17 @@ public string SelectFragment( IJoinable rhs, string rhsAlias, string lhsAlias, string entitySuffix, string collectionSuffix, bool includeCollectionColumns, bool includeLazyProperties) { - return SelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = includeLazyProperties}); + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = includeLazyProperties}); } + //Since v5.5 + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); + } + + public string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { return GetIdentifierSelectFragment(lhsAlias, entityInfo.EntitySuffix).ToSqlStringFragment(false) + GetPropertiesSelectFragment( diff --git a/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs b/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs index bff0512d40f..45ddb1d2123 100644 --- a/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs +++ b/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs @@ -36,6 +36,6 @@ public EntityLoadInfo(string entitySuffix) // 6.0 TODO: merge into 'IJoinable'. internal interface ISupportLazyPropsJoinable { - string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo); + string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo); } } From 782f8d7f3e521343c177f7c3289b2fff15f1b6c8 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 2 Aug 2023 09:30:24 +0300 Subject: [PATCH 030/128] Clean up Linq Joiner class removing no longer needed AddJoinMethod property (#3391) Obsoleted by #2539 --- src/NHibernate/Linq/Visitors/JoinBuilder.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/NHibernate/Linq/Visitors/JoinBuilder.cs b/src/NHibernate/Linq/Visitors/JoinBuilder.cs index a898389fae5..470b3174135 100644 --- a/src/NHibernate/Linq/Visitors/JoinBuilder.cs +++ b/src/NHibernate/Linq/Visitors/JoinBuilder.cs @@ -25,10 +25,7 @@ internal Joiner(QueryModel queryModel) { _nameGenerator = new NameGenerator(queryModel); _queryModel = queryModel; - AddJoinMethod = AddJoin; } - - internal System.Action AddJoinMethod { get; } public IEnumerable Joins { @@ -42,7 +39,7 @@ public Expression AddJoin(Expression expression, string key) if (!_joins.TryGetValue(key, out join)) { join = new NhJoinClause(_nameGenerator.GetNewName(), expression.Type, expression); - AddJoinMethod(_queryModel, join); + AddJoin(_queryModel, join); _joins.Add(key, join); } From 8f05f67e808dc2fc503d4fd0d94b6c9cb66429a1 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 4 Aug 2023 10:05:04 +0300 Subject: [PATCH 031/128] Partial fix fetching lazy property after Select in Linq (#3392) Partial fix of #3356 Fix wrong hql From node detection logic. Query source detection is still broken. --- .../FetchLazyPropertiesFixture.cs | 12 ++++++++++++ .../FetchLazyPropertiesFixture.cs | 12 ++++++++++++ src/NHibernate/Linq/IntermediateHqlTree.cs | 11 +++++++++++ .../ResultOperatorProcessors/ProcessFetch.cs | 13 +++++++------ 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs index 6a812cd5888..18df844bd71 100644 --- a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -186,6 +186,18 @@ public async Task TestLinqFetchPropertyAsync() AssertFetchProperty(person); } + [Test] + public async Task TestLinqFetchPropertyAfterSelectAsync() + { + using var s = OpenSession(); + var owner = await (s.Query() + .Select(a => a.Owner) + .Fetch(o => o.Image) + .FirstOrDefaultAsync(o => o.Id == 1)); + + AssertFetchProperty(owner); + } + private static void AssertFetchProperty(Person person) { Assert.That(person, Is.Not.Null); diff --git a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs index 7a89e998c36..f05c462e5c8 100644 --- a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -175,6 +175,18 @@ public void TestLinqFetchProperty() AssertFetchProperty(person); } + [Test] + public void TestLinqFetchPropertyAfterSelect() + { + using var s = OpenSession(); + var owner = s.Query() + .Select(a => a.Owner) + .Fetch(o => o.Image) + .FirstOrDefault(o => o.Id == 1); + + AssertFetchProperty(owner); + } + private static void AssertFetchProperty(Person person) { Assert.That(person, Is.Not.Null); diff --git a/src/NHibernate/Linq/IntermediateHqlTree.cs b/src/NHibernate/Linq/IntermediateHqlTree.cs index 17417319e41..4104ff4854d 100644 --- a/src/NHibernate/Linq/IntermediateHqlTree.cs +++ b/src/NHibernate/Linq/IntermediateHqlTree.cs @@ -127,6 +127,17 @@ public void AddFromClause(HqlTreeNode from) _root.NodesPreOrder.OfType().First().AddChild(from); } + internal HqlTreeNode GetFromNodeByAlias(string alias) => + _root.NodesPreOrder + .First(x => x.AstNode.Type == HqlSqlWalker.FROM).Children + .First(x => GetNodeAlias(x) == alias); + + private static string GetNodeAlias(HqlTreeNode fromNode) => + fromNode.Children + .Select(x => x.AstNode) + .First(x => x.Type == HqlSqlWalker.ALIAS) + .Text; + internal HqlRange GetFromRangeClause() { return _root.NodesPreOrder.OfType().First().Children.OfType().FirstOrDefault(); diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs index 7c18f9476f4..69323f0a006 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using NHibernate.Hql.Ast; +using NHibernate.Hql.Ast.ANTLR; using NHibernate.Persister.Entity; using NHibernate.Type; using Remotion.Linq.EagerFetching; @@ -21,7 +22,7 @@ public void Process(FetchRequestBase resultOperator, QueryModelVisitor queryMode public void Process(FetchRequestBase resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree, string sourceAlias) { - Process(resultOperator, queryModelVisitor, tree, null, sourceAlias); + Process(resultOperator, queryModelVisitor, tree, tree.GetFromNodeByAlias(sourceAlias), sourceAlias); } private void Process( @@ -68,13 +69,12 @@ private void Process( propType = metadata.GetPropertyType(resultOperator.RelationMember.Name); } } - + if (propType != null && !propType.IsAssociationType) { if (currentNode == null) { - currentNode = tree.GetFromRangeClause() - ?? throw new InvalidOperationException($"Property {resultOperator.RelationMember.Name} cannot be fetched for this type of query."); + throw new InvalidOperationException($"Property {resultOperator.RelationMember.Name} cannot be fetched for this type of query."); } currentNode.AddChild(tree.TreeBuilder.Fetch()); @@ -85,12 +85,13 @@ private void Process( { if (componentType == null) { - componentType = propType as ComponentType; - if (componentType == null) + if (!propType.IsComponentType) { throw new InvalidOperationException( $"Property {innerFetch.RelationMember.Name} cannot be fetched from a non component type property {resultOperator.RelationMember.Name}."); } + + componentType = (ComponentType) propType; } var subTypeIndex = componentType.GetPropertyIndex(innerFetch.RelationMember.Name); From a7deeb068a82fea9c2826856bc9d95d291856341 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 4 Aug 2023 23:33:34 +0300 Subject: [PATCH 032/128] Get rid of select queries for each ManyToMany not found ignored element in hql (#3394) --- .../NH750/ManyToManyNotFoundIgnoreFixture.cs | 85 ++++++++++++------- .../NH750/ManyToManyNotFoundIgnoreFixture.cs | 85 ++++++++++++------- src/NHibernate/Engine/TableGroupJoinHelper.cs | 23 +++-- .../Hql/Ast/ANTLR/Tree/FromElementFactory.cs | 4 +- 4 files changed, 124 insertions(+), 73 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs index 2ab73df8d3a..86eca58dbac 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -9,7 +9,6 @@ using System; -using NHibernate.Cfg; using NHibernate.Criterion; using NHibernate.Transform; using NUnit.Framework; @@ -17,11 +16,21 @@ namespace NHibernate.Test.NHSpecificTest.NH750 { using System.Threading.Tasks; - [TestFixture] + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] public class ManyToManyNotFoundIgnoreFixtureAsync : BugTestCase { private int id1; private int id2; + private int _drive2Id; + private readonly int _drivesCount; + private int DrivesCountWithOneIgnored => _drivesCount == 0? 0 : _drivesCount - 1; + + public ManyToManyNotFoundIgnoreFixtureAsync(int drivesCount) + { + _drivesCount = drivesCount; + } protected override void OnSetUp() { @@ -34,12 +43,12 @@ protected override void OnSetUp() using (var t = s.BeginTransaction()) { s.Save(dr1); - s.Save(dr2); + _drive2Id = (int)s.Save(dr2); s.Save(dr3); - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); id1 = (int) s.Save(dv1); id2 = (int) s.Save(dv2); @@ -51,15 +60,22 @@ protected override void OnSetUp() } } + private void AddDrive(Device dv, Drive drive) + { + if(dv.Drives.Count >= _drivesCount) + return; + dv.Drives.Add(drive); + } + protected override void OnTearDown() { - using (ISession s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - t.Commit(); - } + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); } [Test] @@ -73,9 +89,9 @@ public async Task DeviceOfDriveAsync() dv2 = (Device) await (s.LoadAsync(typeof(Device), id2)); } - Assert.That(dv1.Drives, Has.Count.EqualTo(2).And.None.Null); + Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); // Verify one is missing - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); //Make sure that flush didn't touch not-found="ignore" records for not modified collection using (var s = Sfi.OpenSession()) @@ -86,18 +102,23 @@ public async Task DeviceOfDriveAsync() await (t.CommitAsync()); } - await (VerifyResultAsync(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection")); + await (VerifyResultAsync(expectedInCollection: DrivesCountWithOneIgnored, expectedInDb: _drivesCount, msg: "not modified collection")); + + // Many-to-many clears collection and recreates it so not-found ignore records are lost + // Note: It's not the case when no valid records are present, so loaded Drives collection is empty + // Just skip this check in this case: + if (_drivesCount < 2) + return; - //Many-to-many clears collection and recreates it so not-found ignore records are lost using (var s = Sfi.OpenSession()) using (var t = s.BeginTransaction()) { dv2 = await (s.GetAsync(dv2.Id)); - dv2.Drives.Add(dv1.Drives[1]); + dv2.Drives.Add(await (s.LoadAsync(_drive2Id))); await (t.CommitAsync()); } - await (VerifyResultAsync(2, 2, msg: "modified collection")); + await (VerifyResultAsync(_drivesCount, _drivesCount, msg: "modified collection")); async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string msg) { @@ -127,23 +148,23 @@ public async Task QueryOverFetchAsync() .SingleOrDefaultAsync()); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); } } [Test] public async Task HqlFetchAsync() { - using (var s = OpenSession()) - { - var dv2 = await (s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") - .SetResultTransformer(Transformers.DistinctRootEntity) - .SetParameter("id", id2) - .UniqueResultAsync()); - - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); - } + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] @@ -155,7 +176,7 @@ public async Task LazyLoadAsync() await (NHibernateUtil.InitializeAsync(dv2.Drives)); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs index ecff1b3486b..a627f326dad 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -1,16 +1,25 @@ using System; -using NHibernate.Cfg; using NHibernate.Criterion; using NHibernate.Transform; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH750 { - [TestFixture] + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] public class ManyToManyNotFoundIgnoreFixture : BugTestCase { private int id1; private int id2; + private int _drive2Id; + private readonly int _drivesCount; + private int DrivesCountWithOneIgnored => _drivesCount == 0? 0 : _drivesCount - 1; + + public ManyToManyNotFoundIgnoreFixture(int drivesCount) + { + _drivesCount = drivesCount; + } protected override void OnSetUp() { @@ -23,12 +32,12 @@ protected override void OnSetUp() using (var t = s.BeginTransaction()) { s.Save(dr1); - s.Save(dr2); + _drive2Id = (int)s.Save(dr2); s.Save(dr3); - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); id1 = (int) s.Save(dv1); id2 = (int) s.Save(dv2); @@ -40,15 +49,22 @@ protected override void OnSetUp() } } + private void AddDrive(Device dv, Drive drive) + { + if(dv.Drives.Count >= _drivesCount) + return; + dv.Drives.Add(drive); + } + protected override void OnTearDown() { - using (ISession s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - t.Commit(); - } + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); } [Test] @@ -62,9 +78,9 @@ public void DeviceOfDrive() dv2 = (Device) s.Load(typeof(Device), id2); } - Assert.That(dv1.Drives, Has.Count.EqualTo(2).And.None.Null); + Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); // Verify one is missing - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); //Make sure that flush didn't touch not-found="ignore" records for not modified collection using (var s = Sfi.OpenSession()) @@ -75,18 +91,23 @@ public void DeviceOfDrive() t.Commit(); } - VerifyResult(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection"); + VerifyResult(expectedInCollection: DrivesCountWithOneIgnored, expectedInDb: _drivesCount, msg: "not modified collection"); + + // Many-to-many clears collection and recreates it so not-found ignore records are lost + // Note: It's not the case when no valid records are present, so loaded Drives collection is empty + // Just skip this check in this case: + if (_drivesCount < 2) + return; - //Many-to-many clears collection and recreates it so not-found ignore records are lost using (var s = Sfi.OpenSession()) using (var t = s.BeginTransaction()) { dv2 = s.Get(dv2.Id); - dv2.Drives.Add(dv1.Drives[1]); + dv2.Drives.Add(s.Load(_drive2Id)); t.Commit(); } - VerifyResult(2, 2, msg: "modified collection"); + VerifyResult(_drivesCount, _drivesCount, msg: "modified collection"); void VerifyResult(int expectedInCollection, int expectedInDb, string msg) { @@ -116,23 +137,23 @@ public void QueryOverFetch() .SingleOrDefault(); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); } } [Test] public void HqlFetch() { - using (var s = OpenSession()) - { - var dv2 = s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") - .SetResultTransformer(Transformers.DistinctRootEntity) - .SetParameter("id", id2) - .UniqueResult(); - - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); - } + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] @@ -144,7 +165,7 @@ public void LazyLoad() NHibernateUtil.Initialize(dv2.Drives); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); } } } diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 12ad3be28a2..132a677fee3 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -4,6 +4,7 @@ using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.SqlCommand; +using NHibernate.Type; namespace NHibernate.Engine { @@ -68,14 +69,17 @@ private static bool NeedsTableGroupJoin(IReadOnlyList joins, SqlString[] foreach (var join in joins) { - var entityPersister = GetEntityPersister(join.Joinable, out var isManyToMany); + var entityPersister = GetEntityPersister(join.Joinable, out var manyToManyType); + if (manyToManyType?.IsNullable == true) + return true; + if (entityPersister?.HasSubclassJoins(includeSubclasses && isSubclassIncluded(join.Alias)) != true) continue; if (hasWithClause) return true; - if (!isManyToMany // many-to-many keys are stored in separate table + if (manyToManyType == null // many-to-many keys are stored in separate table && entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) { return true; @@ -94,14 +98,14 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm var isAssociationJoin = lhsColumns.Length > 0; if (isAssociationJoin) { - var entityPersister = GetEntityPersister(first.Joinable, out var isManyToMany); + var entityPersister = GetEntityPersister(first.Joinable, out var manyToManyType); string rhsAlias = first.Alias; string[] rhsColumns = first.RHSColumns; for (int j = 0; j < lhsColumns.Length; j++) { fromFragment.Add(lhsColumns[j]) .Add("=") - .Add((entityPersister == null || isManyToMany) // many-to-many keys are stored in separate table + .Add((entityPersister == null || manyToManyType != null) // many-to-many keys are stored in separate table ? rhsAlias : entityPersister.GenerateTableAliasForColumn(rhsAlias, rhsColumns[j])) .Add(".") @@ -116,15 +120,18 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm return fromFragment.ToSqlString(); } - private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out bool isManyToMany) + private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out EntityType manyToManyType) { - isManyToMany = false; + manyToManyType = null; if (!joinable.IsCollection) return joinable as AbstractEntityPersister; var collection = (IQueryableCollection) joinable; - isManyToMany = collection.IsManyToMany; - return collection.ElementType.IsEntityType ? collection.ElementPersister as AbstractEntityPersister : null; + if (!collection.ElementType.IsEntityType) + return null; + if (collection.IsManyToMany) + manyToManyType = (EntityType) collection.ElementType; + return collection.ElementPersister as AbstractEntityPersister; } private static void AppendWithClause(SqlStringBuilder fromFragment, bool hasConditions, SqlString[] withClauseFragments) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs index e9a95769f1f..f6726bfa8b3 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs @@ -424,7 +424,9 @@ private FromElement CreateManyToMany( // Add the second join, the one that ends in the destination table. JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType, implicitJoin); - joinSequence.AddJoin(sfh.GetElementAssociationType(_collectionType), tableAlias, joinType, secondJoinColumns); + // It's safe to always use inner join for many-to-many not-found ignore mapping as it's processed by table group join + var secondJoinType = type.IsNullable ? JoinType.InnerJoin : joinType; + joinSequence.AddJoin(sfh.GetElementAssociationType(_collectionType), tableAlias, secondJoinType, secondJoinColumns); elem = CreateJoin(associatedEntityName, tableAlias, joinSequence, type, false); elem.UseFromFragment = true; } From 2d774801f88790706bf39fb478881b746a59f501 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 6 Aug 2023 16:30:29 +0300 Subject: [PATCH 033/128] Remove hql ConstantConverter (#3395) Removed logic handled in DotNode class (see LiteralProcessor.LookupConstant) --- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 51 ------------- src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs | 28 ++++++- .../Hql/Ast/ANTLR/Tree/JavaConstantNode.cs | 37 +++++----- .../Hql/Ast/ANTLR/Util/LiteralProcessor.cs | 74 ++----------------- src/NHibernate/Util/ReflectHelper.cs | 25 ++----- 5 files changed, 57 insertions(+), 158 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 6bab2557751..a318e9be5b5 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -547,10 +547,6 @@ public IASTNode Parse() try { var ast = (IASTNode) parser.statement().Tree; - - var walker = new NodeTraverser(new ConstantConverter(_sfi)); - walker.TraverseDepthFirst(ast); - return ast; } finally @@ -558,53 +554,6 @@ public IASTNode Parse() parser.ParseErrorHandler.ThrowQueryException(); } } - - class ConstantConverter : IVisitationStrategy - { - private IASTNode _dotRoot; - private readonly ISessionFactoryImplementor _sfi; - - public ConstantConverter(ISessionFactoryImplementor sfi) - { - _sfi = sfi; - } - - public void Visit(IASTNode node) - { - if (_dotRoot != null) - { - // we are already processing a dot-structure - if (ASTUtil.IsSubtreeChild(_dotRoot, node)) - { - // ignore it... - return; - } - - // we are now at a new tree level - _dotRoot = null; - } - - if (_dotRoot == null && node.Type == HqlSqlWalker.DOT) - { - _dotRoot = node; - HandleDotStructure(_dotRoot); - } - } - - private void HandleDotStructure(IASTNode dotStructureRoot) - { - var expression = ASTUtil.GetPathText(dotStructureRoot); - - var constant = ReflectHelper.GetConstantValue(expression, _sfi); - - if (constant != null) - { - dotStructureRoot.ClearChildren(); - dotStructureRoot.Type = HqlSqlWalker.JAVA_CONSTANT; - dotStructureRoot.Text = expression; - } - } - } } internal class HqlSqlTranslator diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs index 4b0f127a2ca..686ab1d05ff 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs @@ -18,7 +18,7 @@ namespace NHibernate.Hql.Ast.ANTLR.Tree /// Ported by: Steve Strong /// [CLSCompliant(false)] - public class DotNode : FromReferenceNode + public class DotNode : FromReferenceNode, IExpectedTypeAwareNode { private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(DotNode)); @@ -72,6 +72,8 @@ public class DotNode : FromReferenceNode /// private JoinType _joinType = JoinType.InnerJoin; + private object _constantValue; + public DotNode(IToken token) : base(token) { } @@ -287,11 +289,14 @@ private IType GetDataType() return DataType; } - public void SetResolvedConstant(string text) + public void SetResolvedConstant(string text) => SetResolvedConstant(text, null); + + public void SetResolvedConstant(string text, object value) { _path = text; _dereferenceType = DerefJavaConstant; IsResolved = true; // Don't resolve the node again. + _constantValue = value; } private static QueryException BuildIllegalCollectionDereferenceException(string propertyName, IASTNode lhs) @@ -772,5 +777,24 @@ public void ResolveSelectExpression() lhs = (FromReferenceNode)lhs.GetChild(0); } } + + public IType ExpectedType + { + get => DataType; + set + { + if (Type != HqlSqlWalker.JAVA_CONSTANT) + return; + + DataType = value; + } + } + + public override SqlString RenderText(ISessionFactoryImplementor sessionFactory) + { + return Type == HqlSqlWalker.JAVA_CONSTANT + ? JavaConstantNode.ResolveToLiteralString(DataType, _constantValue, sessionFactory.Dialect) + : base.RenderText(sessionFactory); + } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/JavaConstantNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/JavaConstantNode.cs index 74e05746f5f..5c46638f8a1 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/JavaConstantNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/JavaConstantNode.cs @@ -38,27 +38,30 @@ public ISessionFactoryImplementor SessionFactory set { _factory = value; } } - public override SqlString RenderText(ISessionFactoryImplementor sessionFactory) - { - ProcessText(); + public override SqlString RenderText(ISessionFactoryImplementor sessionFactory) + { + ProcessText(); IType type = _expectedType ?? _heuristicType; - return new SqlString(ResolveToLiteralString( type )); + return ResolveToLiteralString(type); } - private string ResolveToLiteralString(IType type) - { - try - { - ILiteralType literalType = (ILiteralType)type; - Dialect.Dialect dialect = _factory.Dialect; - return literalType.ObjectToSQLString(_constantValue, dialect); - } - catch (Exception t) - { - throw new QueryException(LiteralProcessor.ErrorCannotFormatLiteral + Text, t); - } - } + private SqlString ResolveToLiteralString(IType type) + { + return ResolveToLiteralString(type, _constantValue, _factory.Dialect); + } + + internal static SqlString ResolveToLiteralString(IType type, object constantValue, Dialect.Dialect dialect) + { + try + { + return new SqlString(((ILiteralType) type).ObjectToSQLString(constantValue, dialect)); + } + catch (Exception t) + { + throw new QueryException(LiteralProcessor.ErrorCannotFormatLiteral + constantValue, t); + } + } private void ProcessText() { diff --git a/src/NHibernate/Hql/Ast/ANTLR/Util/LiteralProcessor.cs b/src/NHibernate/Hql/Ast/ANTLR/Util/LiteralProcessor.cs index dd89906775b..0d82a990fbb 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Util/LiteralProcessor.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Util/LiteralProcessor.cs @@ -70,7 +70,7 @@ public void LookupConstant(DotNode node) } else { - Object value = ReflectHelper.GetConstantValue(text); + var value = ReflectHelper.GetConstantValue(text, _walker.SessionFactoryHelper.Factory); if (value == null) { throw new InvalidPathException("Invalid path: '" + text + "'"); @@ -149,6 +149,7 @@ public void ProcessConstant(SqlNode constant, bool resolveIdent) if (isIdent && queryable != null) { constant.Text = queryable.DiscriminatorSQLValue; + constant.DataType = queryable.DiscriminatorType; } // Otherwise, it's a literal. else @@ -275,74 +276,9 @@ private void SetConstantValue(DotNode node, string text, object value) node.ClearChildren(); // Chop off the rest of the tree. - if (value is string) - { - node.Type = HqlSqlWalker.QUOTED_String; - } - else if (value is char) - { - node.Type = HqlSqlWalker.QUOTED_String; - } - else if (value is byte) - { - node.Type = HqlSqlWalker.NUM_INT; - } - else if (value is short) - { - node.Type = HqlSqlWalker.NUM_INT; - } - else if (value is int) - { - node.Type = HqlSqlWalker.NUM_INT; - } - else if (value is long) - { - node.Type = HqlSqlWalker.NUM_LONG; - } - else if (value is double) - { - node.Type = HqlSqlWalker.NUM_DOUBLE; - } - else if (value is decimal) - { - node.Type = HqlSqlWalker.NUM_DECIMAL; - } - else if (value is float) - { - node.Type = HqlSqlWalker.NUM_FLOAT; - } - else - { - node.Type = HqlSqlWalker.CONSTANT; - } - - IType type; - try - { - type = TypeFactory.HeuristicType(value.GetType().Name); - } - catch (MappingException me) - { - throw new QueryException(me); - } - - if (type == null) - { - throw new QueryException(LiteralProcessor.ErrorCannotDetermineType + node.Text); - } - try - { - ILiteralType literalType = (ILiteralType)type; - NHibernate.Dialect.Dialect dialect = _walker.SessionFactoryHelper.Factory.Dialect; - node.Text = literalType.ObjectToSQLString(value, dialect); - } - catch (Exception e) - { - throw new QueryException(LiteralProcessor.ErrorCannotFormatLiteral + node.Text, e); - } - - node.DataType = type; - node.SetResolvedConstant(text); + node.Type = HqlSqlWalker.JAVA_CONSTANT; + node.DataType = TypeFactory.HeuristicType(value.GetType().Name); + node.SetResolvedConstant(text, value); } interface IDecimalFormatter diff --git a/src/NHibernate/Util/ReflectHelper.cs b/src/NHibernate/Util/ReflectHelper.cs index 06352101745..e665a68a9c3 100644 --- a/src/NHibernate/Util/ReflectHelper.cs +++ b/src/NHibernate/Util/ReflectHelper.cs @@ -820,31 +820,18 @@ private static MethodInfo SafeGetMethod(System.Type type, MethodInfo method, Sys return foundMethod; } - internal static object GetConstantValue(string qualifiedName) - { - return GetConstantValue(qualifiedName, null); - } - internal static object GetConstantValue(string qualifiedName, ISessionFactoryImplementor sfi) { string className = StringHelper.Qualifier(qualifiedName); - if (!string.IsNullOrEmpty(className)) - { - System.Type t = System.Type.GetType(className); - - if (t == null && sfi != null) - { - t = System.Type.GetType(sfi.GetImportedClassName(className)); - } + if (string.IsNullOrEmpty(className)) + return null; - if (t != null) - { - return GetConstantValue(t, StringHelper.Unqualify(qualifiedName)); - } - } + var t = System.Type.GetType(sfi?.GetImportedClassName(className) ?? className); - return null; + return t == null + ? null + : GetConstantValue(t, StringHelper.Unqualify(qualifiedName)); } // Since v5 From d1a7e10177ee88f2421b916dd5a48563d556d253 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 9 Aug 2023 09:53:19 +0300 Subject: [PATCH 034/128] Get rid of select queries for each ManyToMany not found ignored element in Criteria and lazy loading (#3396) --- .../NHSpecificTest/NH750/ManyToManyFixture.cs | 155 ++++++++++++++++++ .../NH750/ManyToManyNotFoundIgnoreFixture.cs | 118 ++++++++----- .../ManyToManyThrowsForNotFoundFixture.cs | 52 ++++-- .../NHSpecificTest/NH750/Device.cs | 21 ++- .../NHSpecificTest/NH750/Drive.cs | 6 +- .../NHSpecificTest/NH750/ManyToManyFixture.cs | 144 ++++++++++++++++ .../NH750/ManyToManyNotFoundIgnoreFixture.cs | 116 ++++++++----- .../ManyToManyThrowsForNotFoundFixture.cs | 52 ++++-- .../NHSpecificTest/NH750/Mappings.hbm.xml | 4 +- src/NHibernate/Loader/JoinWalker.cs | 10 +- 10 files changed, 553 insertions(+), 125 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs new file mode 100644 index 00000000000..362bd7a6f71 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// +// 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 NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + using System.Threading.Tasks; + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyFixtureAsync : BugTestCase + { + private int id2; + private readonly int _drivesCount; + private int _withTemplateId; + private int ValidDrivesCount => _drivesCount; + + public ManyToManyFixtureAsync(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.DrivesNotIgnored.Count >= _drivesCount) + return; + dv.DrivesNotIgnored.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public async Task QueryOverFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task QueryOverFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.CreateQuery("from Device d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task LazyLoadAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + + var dv2 = await (s.GetAsync(id2)); + + await (NHibernateUtil.InitializeAsync(dv2.DrivesNotIgnored)); + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + // First query for Device, second for Drives collection + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs index 86eca58dbac..2889ad0ea64 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -24,8 +24,9 @@ public class ManyToManyNotFoundIgnoreFixtureAsync : BugTestCase private int id1; private int id2; private int _drive2Id; + private int _withTemplateId; private readonly int _drivesCount; - private int DrivesCountWithOneIgnored => _drivesCount == 0? 0 : _drivesCount - 1; + private int ValidDrivesCount => _drivesCount == 0 ? 0 : _drivesCount - 1; public ManyToManyNotFoundIgnoreFixtureAsync(int drivesCount) { @@ -39,25 +40,26 @@ protected override void OnSetUp() Drive dr3 = new Drive("Drive 3"); Device dv1 = new Device("Device 1"); Device dv2 = new Device("Device 2"); - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - s.Save(dr1); - _drive2Id = (int)s.Save(dr2); - s.Save(dr3); - AddDrive(dv1, dr2); - AddDrive(dv1, dr1); - AddDrive(dv2, dr3); - AddDrive(dv2, dr1); - - id1 = (int) s.Save(dv1); - id2 = (int) s.Save(dv2); - s.Flush(); - - s.Clear(); - s.Delete(dr3); - t.Commit(); - } + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + _drive2Id = (int)s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); } private void AddDrive(Device dv, Drive drive) @@ -87,11 +89,13 @@ public async Task DeviceOfDriveAsync() { dv1 = (Device) await (s.LoadAsync(typeof(Device), id1)); dv2 = (Device) await (s.LoadAsync(typeof(Device), id2)); + await (NHibernateUtil.InitializeAsync(dv1.Drives)); + await (NHibernateUtil.InitializeAsync(dv2.Drives)); } Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); // Verify one is missing - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); //Make sure that flush didn't touch not-found="ignore" records for not modified collection using (var s = Sfi.OpenSession()) @@ -102,7 +106,7 @@ public async Task DeviceOfDriveAsync() await (t.CommitAsync()); } - await (VerifyResultAsync(expectedInCollection: DrivesCountWithOneIgnored, expectedInDb: _drivesCount, msg: "not modified collection")); + await (VerifyResultAsync(expectedInCollection: ValidDrivesCount, expectedInDb: _drivesCount, msg: "not modified collection")); // Many-to-many clears collection and recreates it so not-found ignore records are lost // Note: It's not the case when no valid records are present, so loaded Drives collection is empty @@ -139,17 +143,34 @@ async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string [Test] public async Task QueryOverFetchAsync() { - using (var s = OpenSession()) - { - var dv2 = await (s.QueryOver() - .Fetch(SelectMode.Fetch, x => x.Drives) - .Where(Restrictions.IdEq(id2)) - .TransformUsing(Transformers.DistinctRootEntity) - .SingleOrDefaultAsync()); - - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); - } + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task QueryOverFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.Drives) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] @@ -163,21 +184,36 @@ public async Task HqlFetchAsync() .UniqueResultAsync()); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] public async Task LazyLoadAsync() { - using (var s = OpenSession()) - { - var dv2 = await (s.GetAsync(id2)); - await (NHibernateUtil.InitializeAsync(dv2.Drives)); + using var s = OpenSession(); - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); - } + var dv2 = await (s.GetAsync(id2)); + using var log = new SqlLogSpy(); + + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs index 59b6a0044bf..78848ea3659 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -21,24 +21,25 @@ namespace NHibernate.Test.NHSpecificTest.NH750 public class ManyToManyThrowsForNotFoundFixtureAsync : BugTestCase { private int _id; + private int _withTemplateId; protected override void OnSetUp() { - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - Device dv = new Device("Device"); - Drive dr = new Drive("Drive"); - s.Save(dr); - dv.DrivesNotIgnored.Add(dr); + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv }; + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); - _id = (int) s.Save(dv); - s.Flush(); + _id = (int) s.Save(dv); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); - s.Clear(); - s.Delete(dr); - t.Commit(); - } + s.Clear(); + s.Delete(dr); + t.Commit(); } protected override void OnTearDown() @@ -68,7 +69,18 @@ public void QueryOverFetchAsync() .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) .Where(Restrictions.IdEq(_id)) .TransformUsing(Transformers.DistinctRootEntity); - Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (queryOver.SingleOrDefaultAsync())))); + Assert.ThrowsAsync(() => queryOver.SingleOrDefaultAsync()); + } + + [Test] + public void QueryOverFetch2Async() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x=> x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.ThrowsAsync(() => queryOver.SingleOrDefaultAsync()); } [Test] @@ -81,5 +93,17 @@ public void LinqFetchAsync() .Where(x => x.Id == _id); Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync())))); } + + [Test] + public void LinqFetch2Async() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.Template) + .ThenFetchMany(x => x.DrivesNotIgnored) + .Where(x => x.Id == _withTemplateId); + Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync())))); + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs index 897045acaf6..b4496828089 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs @@ -6,6 +6,11 @@ namespace NHibernate.Test.NHSpecificTest.NH750 { public class Device { + private int _id; + private Device _template; + private IList _drives = new List(); + private IList _drivesNotIgnored = new List(); + public Device() : base() { } @@ -16,9 +21,13 @@ public Device(string manifacturer) _manifacturer = manifacturer; } - private int _id; + public virtual Device Template + { + get => _template; + set => _template = value; + } - public int Id + public virtual int Id { get { return _id; } set { _id = value; } @@ -26,22 +35,20 @@ public int Id private string _manifacturer; - public string Manifacturer + public virtual string Manifacturer { get { return _manifacturer; } set { _manifacturer = value; } } - private IList _drives = new List(); - private IList _drivesNotIgnored = new List(); - public IList Drives + public virtual IList Drives { get { return _drives; } set { _drives = value; } } - public IList DrivesNotIgnored + public virtual IList DrivesNotIgnored { get => _drivesNotIgnored; set => _drivesNotIgnored = value; diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs index b449dfb27ea..0e473bdf875 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs @@ -16,7 +16,7 @@ public Drive(string classFullName) private int _id; - public int Id + public virtual int Id { get { return _id; } set { _id = value; } @@ -24,7 +24,7 @@ public int Id private string _classFullName; - public string ClassFullName + public virtual string ClassFullName { get { return _classFullName; } set { _classFullName = value; } @@ -44,4 +44,4 @@ public override int GetHashCode() return _classFullName.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs new file mode 100644 index 00000000000..dd923c1a1eb --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs @@ -0,0 +1,144 @@ +using System; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyFixture : BugTestCase + { + private int id2; + private readonly int _drivesCount; + private int _withTemplateId; + private int ValidDrivesCount => _drivesCount; + + public ManyToManyFixture(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.DrivesNotIgnored.Count >= _drivesCount) + return; + dv.DrivesNotIgnored.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public void QueryOverFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void QueryOverFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.CreateQuery("from Device d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void LazyLoad() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + + var dv2 = s.Get(id2); + + NHibernateUtil.Initialize(dv2.DrivesNotIgnored); + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + // First query for Device, second for Drives collection + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs index a627f326dad..3762342e932 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -13,8 +13,9 @@ public class ManyToManyNotFoundIgnoreFixture : BugTestCase private int id1; private int id2; private int _drive2Id; + private int _withTemplateId; private readonly int _drivesCount; - private int DrivesCountWithOneIgnored => _drivesCount == 0? 0 : _drivesCount - 1; + private int ValidDrivesCount => _drivesCount == 0 ? 0 : _drivesCount - 1; public ManyToManyNotFoundIgnoreFixture(int drivesCount) { @@ -28,25 +29,26 @@ protected override void OnSetUp() Drive dr3 = new Drive("Drive 3"); Device dv1 = new Device("Device 1"); Device dv2 = new Device("Device 2"); - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - s.Save(dr1); - _drive2Id = (int)s.Save(dr2); - s.Save(dr3); - AddDrive(dv1, dr2); - AddDrive(dv1, dr1); - AddDrive(dv2, dr3); - AddDrive(dv2, dr1); - - id1 = (int) s.Save(dv1); - id2 = (int) s.Save(dv2); - s.Flush(); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; - s.Clear(); - s.Delete(dr3); - t.Commit(); - } + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + _drive2Id = (int)s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); } private void AddDrive(Device dv, Drive drive) @@ -76,11 +78,13 @@ public void DeviceOfDrive() { dv1 = (Device) s.Load(typeof(Device), id1); dv2 = (Device) s.Load(typeof(Device), id2); + NHibernateUtil.Initialize(dv1.Drives); + NHibernateUtil.Initialize(dv2.Drives); } Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); // Verify one is missing - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); //Make sure that flush didn't touch not-found="ignore" records for not modified collection using (var s = Sfi.OpenSession()) @@ -91,7 +95,7 @@ public void DeviceOfDrive() t.Commit(); } - VerifyResult(expectedInCollection: DrivesCountWithOneIgnored, expectedInDb: _drivesCount, msg: "not modified collection"); + VerifyResult(expectedInCollection: ValidDrivesCount, expectedInDb: _drivesCount, msg: "not modified collection"); // Many-to-many clears collection and recreates it so not-found ignore records are lost // Note: It's not the case when no valid records are present, so loaded Drives collection is empty @@ -128,17 +132,34 @@ void VerifyResult(int expectedInCollection, int expectedInDb, string msg) [Test] public void QueryOverFetch() { - using (var s = OpenSession()) - { - var dv2 = s.QueryOver() - .Fetch(SelectMode.Fetch, x => x.Drives) - .Where(Restrictions.IdEq(id2)) - .TransformUsing(Transformers.DistinctRootEntity) - .SingleOrDefault(); - - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); - } + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void QueryOverFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.Drives) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] @@ -152,21 +173,36 @@ public void HqlFetch() .UniqueResult(); Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } [Test] public void LazyLoad() { - using (var s = OpenSession()) - { - var dv2 = s.Get(id2); - NHibernateUtil.Initialize(dv2.Drives); + using var s = OpenSession(); - Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); - Assert.That(dv2.Drives, Has.Count.EqualTo(DrivesCountWithOneIgnored).And.None.Null); - } + var dv2 = s.Get(id2); + using var log = new SqlLogSpy(); + + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs index bef312c398c..27ce2d3aaaf 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -10,24 +10,25 @@ namespace NHibernate.Test.NHSpecificTest.NH750 public class ManyToManyThrowsForNotFoundFixture : BugTestCase { private int _id; + private int _withTemplateId; protected override void OnSetUp() { - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - Device dv = new Device("Device"); - Drive dr = new Drive("Drive"); - s.Save(dr); - dv.DrivesNotIgnored.Add(dr); + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv }; + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); - _id = (int) s.Save(dv); - s.Flush(); + _id = (int) s.Save(dv); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); - s.Clear(); - s.Delete(dr); - t.Commit(); - } + s.Clear(); + s.Delete(dr); + t.Commit(); } protected override void OnTearDown() @@ -57,7 +58,18 @@ public void QueryOverFetch() .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) .Where(Restrictions.IdEq(_id)) .TransformUsing(Transformers.DistinctRootEntity); - Assert.Throws(() => NHibernateUtil.Initialize(queryOver.SingleOrDefault())); + Assert.Throws(() => queryOver.SingleOrDefault()); + } + + [Test] + public void QueryOverFetch2() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x=> x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.Throws(() => queryOver.SingleOrDefault()); } [Test] @@ -70,5 +82,17 @@ public void LinqFetch() .Where(x => x.Id == _id); Assert.Throws(() => NHibernateUtil.Initialize(query.SingleOrDefault())); } + + [Test] + public void LinqFetch2() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.Template) + .ThenFetchMany(x => x.DrivesNotIgnored) + .Where(x => x.Id == _withTemplateId); + Assert.Throws(() => NHibernateUtil.Initialize(query.SingleOrDefault())); + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml index 56d7c9c5927..e2b3987d60e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml @@ -2,13 +2,13 @@ + default-access="field.camelcase-underscore"> + diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index 5fa910eb48f..9d28bd9d61c 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -347,10 +347,7 @@ private void WalkCollectionTree(IQueryableCollection persister, string alias, st string[] aliasedLhsColumns = persister.GetElementColumnNames(alias); string[] lhsColumns = persister.ElementColumnNames; - // if the current depth is 0, the root thing being loaded is the - // many-to-many collection itself. Here, it is alright to use - // an inner join... - bool useInnerJoin = _depth == 0; + const bool useInnerJoin = false; var joinType = GetJoinType( @@ -364,6 +361,11 @@ private void WalkCollectionTree(IQueryableCollection persister, string alias, st _depth - 1, null); + // It's safe to always use inner join for many-to-many not-found ignore mapping as it's processed by table group join; + // otherwise we need left join for proper not-found exception handling + if (joinType == JoinType.LeftOuterJoin && ((EntityType) type).IsNullable) + joinType = JoinType.InnerJoin; + AddAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, From 737e2c8aa07cc75d5e6f2763dc8984ac40b5df81 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sat, 12 Aug 2023 16:00:51 +0300 Subject: [PATCH 035/128] Cache Dialect in all public Configuration methods (#3399) Wrap mapping usages in StaticDialectMappingWrapper Fixes #3397 --- src/NHibernate/Cfg/Configuration.cs | 31 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/NHibernate/Cfg/Configuration.cs b/src/NHibernate/Cfg/Configuration.cs index 6b52f6008ba..4055114a3fd 100644 --- a/src/NHibernate/Cfg/Configuration.cs +++ b/src/NHibernate/Cfg/Configuration.cs @@ -246,10 +246,14 @@ private class StaticDialectMappingWrapper : IMapping { private readonly IMapping _mapping; - public StaticDialectMappingWrapper(IMapping mapping) + public StaticDialectMappingWrapper(IMapping mapping): this(mapping, mapping.Dialect) + { + } + + public StaticDialectMappingWrapper(IMapping mapping, Dialect.Dialect dialect) { _mapping = mapping; - Dialect = mapping.Dialect; + Dialect = dialect; } public IType GetIdentifierType(string className) @@ -941,11 +945,12 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) var script = new List(); + var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); foreach (var table in TableMappings) { if (table.IsPhysicalTable && IncludeAction(table.SchemaActions, SchemaAction.Export)) { - script.Add(table.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(table.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); script.AddRange(table.SqlCommentStrings(dialect, defaultCatalog, defaultSchema)); } } @@ -958,7 +963,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { foreach (var uk in table.UniqueKeyIterator) { - string constraintString = uk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema); + string constraintString = uk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema); if (constraintString != null) { script.Add(constraintString); @@ -968,7 +973,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) foreach (var index in table.IndexIterator) { - script.Add(index.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(index.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } if (dialect.SupportsForeignKeyConstraintInAlterTable) @@ -977,7 +982,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { if (fk.IsGenerated(dialect) && IncludeAction(fk.ReferencedTable.SchemaActions, SchemaAction.Export)) { - script.Add(fk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(fk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } } } @@ -994,7 +999,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { if (auxDbObj.AppliesToDialect(dialect)) { - script.Add(auxDbObj.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(auxDbObj.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } } @@ -2364,6 +2369,7 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet var defaultSchema = GetQuotedDefaultSchema(dialect); var script = new List(50); + var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); foreach (var table in TableMappings) { if (table.IsPhysicalTable && IncludeAction(table.SchemaActions, SchemaAction.Update)) @@ -2372,11 +2378,11 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet table.Catalog ?? defaultCatalog, table.IsQuoted); if (tableInfo == null) { - script.Add(table.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(table.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } else { - string[] alterDDL = table.SqlAlterStrings(dialect, mapping, tableInfo, defaultCatalog, defaultSchema); + string[] alterDDL = table.SqlAlterStrings(dialect, staticDialectMapping, tableInfo, defaultCatalog, defaultSchema); script.AddRange(alterDDL); } @@ -2404,7 +2410,7 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet && (!(dialect is MySQLDialect) || tableInfo.GetIndexMetadata(fk.Name) == null)); if (create) { - script.Add(fk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(fk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } } } @@ -2414,7 +2420,7 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet { if (tableInfo == null || tableInfo.GetIndexMetadata(index.Name) == null) { - script.Add(index.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); + script.Add(index.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); } } } @@ -2440,6 +2446,7 @@ public void ValidateSchema(Dialect.Dialect dialect, IDatabaseMetadata databaseMe { SecondPassCompile(); + var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); var defaultCatalog = GetQuotedDefaultCatalog(dialect); var defaultSchema = GetQuotedDefaultSchema(dialect); @@ -2466,7 +2473,7 @@ public void ValidateSchema(Dialect.Dialect dialect, IDatabaseMetadata databaseMe } else { - validationErrors.AddRange(table.ValidateColumns(dialect, mapping, tableInfo)); + validationErrors.AddRange(table.ValidateColumns(dialect, staticDialectMapping, tableInfo)); } } } From 4308ec9f1e8c51d6fc35c4c6a554b8c3bb9256b9 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 13 Aug 2023 13:19:19 +0300 Subject: [PATCH 036/128] Fix NamedSQLQuery ignores query-param type (#3404) Fixes #3311 --- .../SqlQueryParamTypeFixture.cs | 61 +++++++++++++++++++ .../GH3311SqlQueryParam/Entity.cs | 10 +++ .../GH3311SqlQueryParam/Mappings.hbm.xml | 14 +++++ .../SqlQueryParamTypeFixture.cs | 50 +++++++++++++++ .../Cfg/XmlHbmBinding/NamedSQLQueryBinder.cs | 7 ++- src/NHibernate/Engine/Query/QueryPlanCache.cs | 22 +++++-- src/NHibernate/Impl/AbstractSessionImpl.cs | 4 +- 7 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs new file mode 100644 index 00000000000..4ddde3d2a41 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// 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.Data; +using NHibernate.Dialect; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + using System.Threading.Tasks; + [TestFixture] + public class SqlQueryParamTypeFixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new Entity {Name = "Bob"}; + session.Save(e1); + + var e2 = new Entity {Name = "Sally"}; + session.Save(e2); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + (Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)) + || Dialect is SQLiteDialect); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task AppliesParameterTypeFromQueryParamAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + await (s.GetNamedQuery("entityIdByName").SetParameter("name", "Bob").UniqueResultAsync()); + Assert.That(log.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs new file mode 100644 index 00000000000..3dba8b9c90b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs @@ -0,0 +1,10 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + class Entity + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml new file mode 100644 index 00000000000..028a77a8a61 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + select s.Id from Entity s where s.Name = :name + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs new file mode 100644 index 00000000000..c7c5f1967f0 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs @@ -0,0 +1,50 @@ +using System.Data; +using NHibernate.Dialect; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + [TestFixture] + public class SqlQueryParamTypeFixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new Entity {Name = "Bob"}; + session.Save(e1); + + var e2 = new Entity {Name = "Sally"}; + session.Save(e2); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + (Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)) + || Dialect is SQLiteDialect); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void AppliesParameterTypeFromQueryParam() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + s.GetNamedQuery("entityIdByName").SetParameter("name", "Bob").UniqueResult(); + Assert.That(log.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } +} diff --git a/src/NHibernate/Cfg/XmlHbmBinding/NamedSQLQueryBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/NamedSQLQueryBinder.cs index e9bb3f89081..d802bb534c2 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/NamedSQLQueryBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/NamedSQLQueryBinder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using NHibernate.Cfg.MappingSchema; using NHibernate.Engine; using NHibernate.Util; @@ -33,7 +34,11 @@ public void AddSqlQuery(HbmSqlQuery querySchema) ? querySchema.cachemode.ToCacheMode() : null; - var parameterTypes = new LinkedHashMap(); + var parameterTypes = + querySchema.Items.EmptyIfNull().OfType() + .Where(x => !string.IsNullOrEmpty(x.type)) + .ToDictionary(x => x.name, x => x.type); + var synchronizedTables = GetSynchronizedTables(querySchema); NamedSQLQueryDefinition namedQuery; diff --git a/src/NHibernate/Engine/Query/QueryPlanCache.cs b/src/NHibernate/Engine/Query/QueryPlanCache.cs index c2b8cd9e1f6..33b260ed39e 100644 --- a/src/NHibernate/Engine/Query/QueryPlanCache.cs +++ b/src/NHibernate/Engine/Query/QueryPlanCache.cs @@ -5,6 +5,7 @@ using NHibernate.Engine.Query.Sql; using NHibernate.Hql; using NHibernate.Linq; +using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Engine.Query @@ -40,6 +41,11 @@ public QueryPlanCache(ISessionFactoryImplementor factory) } public ParameterMetadata GetSQLParameterMetadata(string query) + { + return GetSQLParameterMetadata(query, CollectionHelper.EmptyDictionary()); + } + + public ParameterMetadata GetSQLParameterMetadata(string query, IDictionary parameterTypes) { var metadata = (ParameterMetadata)sqlParamMetadataCache[query]; if (metadata == null) @@ -49,7 +55,7 @@ public ParameterMetadata GetSQLParameterMetadata(string query) // retrieval for a native-sql query depends on all of the return // types having been set, which might not be the case up-front when // param metadata would be most useful - metadata = BuildNativeSQLParameterMetadata(query); + metadata = BuildNativeSQLParameterMetadata(query, parameterTypes); sqlParamMetadataCache.Put(query, metadata); } return metadata; @@ -170,14 +176,14 @@ public NativeSQLQueryPlan GetNativeSQLQueryPlan(NativeSQLQuerySpecification spec return plan; } - private ParameterMetadata BuildNativeSQLParameterMetadata(string sqlString) + private ParameterMetadata BuildNativeSQLParameterMetadata(string sqlString, + IDictionary parameterTypes) { ParamLocationRecognizer recognizer = ParamLocationRecognizer.ParseLocations(sqlString); var ordinalDescriptors = new OrdinalParameterDescriptor[recognizer.OrdinalParameterLocationList.Count]; - for (int i = 0; i < recognizer.OrdinalParameterLocationList.Count; i++) + for (int i = 0; i < ordinalDescriptors.Length; i++) { - int position = recognizer.OrdinalParameterLocationList[i]; ordinalDescriptors[i] = new OrdinalParameterDescriptor(i, null); } @@ -187,8 +193,14 @@ private ParameterMetadata BuildNativeSQLParameterMetadata(string sqlString) { string name = entry.Key; ParamLocationRecognizer.NamedParameterDescription description = entry.Value; + IType expectedType = null; + if (parameterTypes.TryGetValue(name, out var type) && !string.IsNullOrEmpty(type)) + { + expectedType = TypeFactory.HeuristicType(type); + } + namedParamDescriptorMap[name] = - new NamedParameterDescriptor(name, null, description.JpaStyle); + new NamedParameterDescriptor(name, expectedType, description.JpaStyle); } return new ParameterMetadata(ordinalDescriptors, namedParamDescriptorMap); diff --git a/src/NHibernate/Impl/AbstractSessionImpl.cs b/src/NHibernate/Impl/AbstractSessionImpl.cs index d2fd81b1b72..4fe9c9ae598 100644 --- a/src/NHibernate/Impl/AbstractSessionImpl.cs +++ b/src/NHibernate/Impl/AbstractSessionImpl.cs @@ -299,7 +299,7 @@ public virtual IQuery GetNamedSQLQuery(string name) throw new MappingException("Named SQL query not known: " + name); } var query = new SqlQueryImpl(nsqlqd, this, - _factory.QueryPlanCache.GetSQLParameterMetadata(nsqlqd.QueryString)); + _factory.QueryPlanCache.GetSQLParameterMetadata(nsqlqd.QueryString, nsqlqd.ParameterTypes)); query.SetComment("named native SQL query " + name); InitQuery(query, nsqlqd); return query; @@ -378,7 +378,7 @@ public virtual IQuery GetNamedQuery(string queryName) throw new MappingException("Named query not known: " + queryName); } query = new SqlQueryImpl(nsqlqd, this, - _factory.QueryPlanCache.GetSQLParameterMetadata(nsqlqd.QueryString)); + _factory.QueryPlanCache.GetSQLParameterMetadata(nsqlqd.QueryString, nsqlqd.ParameterTypes)); query.SetComment("named native SQL query " + queryName); nqd = nsqlqd; } From 4dac4ca42841ca600e2e70803585c1f46bbe900d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 13 Aug 2023 16:17:00 +0200 Subject: [PATCH 037/128] Release 5.3.19 (#3405) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 8dc75dd47a5..6cad2a32da7 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.3 - 18 + 19 diff --git a/releasenotes.txt b/releasenotes.txt index fd095e4ef4d..c7317d2b4f6 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,20 @@ -Build 5.3.18 +Build 5.3.19 +============================= + +Release notes - NHibernate - Version 5.3.19 + +2 issues were resolved in this release. + +** Bug + + * #3397 GenerateSchemaCreationScript creates many identical dialect instances + +** Task + + * #3405 Release 5.3.19 + + +Build 5.3.18 ============================= Release notes - NHibernate - Version 5.3.18 From 7681611bfd86a12a7840dcdad99195ec6c5860cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 13 Aug 2023 23:01:17 +0200 Subject: [PATCH 038/128] Release 5.4.5 (#3408) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 403c50e24a6..73ae769c705 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.4 - 4 + 5 9.0 diff --git a/releasenotes.txt b/releasenotes.txt index 41d1fd8e987..a612526094e 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,17 @@ -Build 5.4.4 +Build 5.4.5 +============================= + +Release notes - NHibernate - Version 5.4.5 + +2 issues were resolved in this release. + +** Task + + * #3408 Release 5.4.4 + * #3407 Release Merge 5.3.19 in 5.4.x + + +Build 5.4.4 ============================= Release notes - NHibernate - Version 5.4.4 From 3e353c1db3c8f106aa43f5d2f5b3b0c232785676 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 15 Aug 2023 09:59:00 +0300 Subject: [PATCH 039/128] Fix orphan removal for detached one-to-one (#3406) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to #3403 Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- .../NHSpecificTest/GH3403OneToOne/Fixture.cs | 74 +++++++++++++++++++ .../NHSpecificTest/GH3403OneToOne/Entity.cs | 17 +++++ .../NHSpecificTest/GH3403OneToOne/Fixture.cs | 63 ++++++++++++++++ .../GH3403OneToOne/Mappings.hbm.xml | 18 +++++ src/NHibernate/Async/Engine/Cascade.cs | 2 +- src/NHibernate/Engine/Cascade.cs | 2 +- 6 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs new file mode 100644 index 00000000000..85c119e905c --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// 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 NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + private Guid _id; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = new Entity1 + { + Child = new Entity2() + }; + + entity.Child.Parent = entity; + + session.Save(entity); + transaction.Commit(); + _id = entity.Id; + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task OrphanDeleteForDetachedOneToOneAsync() + { + Guid childId; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var entity = await (session.GetAsync(_id)); + childId = entity.Child.Id; + await (session.EvictAsync(entity.Child)); + entity.Child = null; + + await (session.FlushAsync()); + await (transaction.CommitAsync()); + } + + using (var session = OpenSession()) + { + var entity = await (session.GetAsync(_id)); + Assert.That(entity, Is.Not.Null); + Assert.That(entity.Child, Is.Null, "Unexpected child on parent"); + + var child = await (session.GetAsync(childId)); + Assert.That(child , Is.Null, "Child is still in database"); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs new file mode 100644 index 00000000000..0bde7420b92 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs @@ -0,0 +1,17 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + public class Entity1 + { + public virtual Guid Id { get; set; } + + public virtual Entity2 Child { get; set; } + } + public class Entity2 + { + public virtual Guid Id { get; set; } + + public virtual Entity1 Parent { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs new file mode 100644 index 00000000000..08f965eef1d --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs @@ -0,0 +1,63 @@ +using System; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + [TestFixture] + public class Fixture : BugTestCase + { + private Guid _id; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = new Entity1 + { + Child = new Entity2() + }; + + entity.Child.Parent = entity; + + session.Save(entity); + transaction.Commit(); + _id = entity.Id; + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void OrphanDeleteForDetachedOneToOne() + { + Guid childId; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var entity = session.Get(_id); + childId = entity.Child.Id; + session.Evict(entity.Child); + entity.Child = null; + + session.Flush(); + transaction.Commit(); + } + + using (var session = OpenSession()) + { + var entity = session.Get(_id); + Assert.That(entity, Is.Not.Null); + Assert.That(entity.Child, Is.Null, "Unexpected child on parent"); + + var child = session.Get(childId); + Assert.That(child , Is.Null, "Child is still in database"); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml new file mode 100644 index 00000000000..175d587c0ce --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + Parent + + + + + diff --git a/src/NHibernate/Async/Engine/Cascade.cs b/src/NHibernate/Async/Engine/Cascade.cs index c0165e5cf66..46877a36ae1 100644 --- a/src/NHibernate/Async/Engine/Cascade.cs +++ b/src/NHibernate/Async/Engine/Cascade.cs @@ -151,7 +151,7 @@ private async Task CascadePropertyAsync(object parent, object child, IType type, if (loadedValue != null) { - await (eventSource.DeleteAsync(entry.Persister.EntityName, loadedValue, false, null, cancellationToken)).ConfigureAwait(false); + await (eventSource.DeleteAsync(((EntityType) type).GetAssociatedEntityName(), loadedValue, false, null, cancellationToken)).ConfigureAwait(false); } } } diff --git a/src/NHibernate/Engine/Cascade.cs b/src/NHibernate/Engine/Cascade.cs index 2c2c2987a3b..35098331337 100644 --- a/src/NHibernate/Engine/Cascade.cs +++ b/src/NHibernate/Engine/Cascade.cs @@ -203,7 +203,7 @@ private void CascadeProperty(object parent, object child, IType type, CascadeSty if (loadedValue != null) { - eventSource.Delete(entry.Persister.EntityName, loadedValue, false, null); + eventSource.Delete(((EntityType) type).GetAssociatedEntityName(), loadedValue, false, null); } } } From 509ed7696b27dce0a7f1fca251efed42418b59a5 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 16 Aug 2023 00:57:57 +1000 Subject: [PATCH 040/128] Do not store mapping field in Configuration (#3398) --- .../DialectTest/MsSql2008DialectFixture.cs | 11 +- src/NHibernate/Cfg/Configuration.cs | 102 +++++++----------- 2 files changed, 42 insertions(+), 71 deletions(-) diff --git a/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs index e02b69dfed2..3115bf26328 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs @@ -148,16 +148,7 @@ public void ScaleTypes() Assert.That(dialect.GetTypeName(SqlTypeFactory.GetTime(max + 1)), Is.EqualTo("time").IgnoreCase, "Over max time"); } - private static readonly FieldInfo _mappingField = - typeof(Configuration).GetField("mapping", BindingFlags.Instance | BindingFlags.NonPublic); - - private static IMapping GetMapping(Configuration cfg) - { - Assert.That(_mappingField, Is.Not.Null, "Unable to find field mapping"); - var mapping = _mappingField.GetValue(cfg) as IMapping; - Assert.That(mapping, Is.Not.Null, "Unable to find mapping object"); - return mapping; - } + private static IMapping GetMapping(Configuration cfg) => (IMapping) cfg.BuildSessionFactory(); private static void AssertSqlType(IType type, SqlType sqlType, IMapping mapping) { diff --git a/src/NHibernate/Cfg/Configuration.cs b/src/NHibernate/Cfg/Configuration.cs index 4055114a3fd..13e3ab51bb6 100644 --- a/src/NHibernate/Cfg/Configuration.cs +++ b/src/NHibernate/Cfg/Configuration.cs @@ -98,7 +98,6 @@ public Configuration(SerializationInfo info, StreamingContext context) FilterDefinitions = GetSerialedObject>(info, "filterDefinitions"); Imports = GetSerialedObject>(info, "imports"); interceptor = GetSerialedObject(info, "interceptor"); - mapping = GetSerialedObject(info, "mapping"); NamedQueries = GetSerialedObject>(info, "namedQueries"); NamedSQLQueries = GetSerialedObject>(info, "namedSqlQueries"); namingStrategy = GetSerialedObject(info, "namingStrategy"); @@ -124,7 +123,6 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) { ConfigureProxyFactoryFactory(); SecondPassCompile(); - Validate(); info.AddValue("entityNotFoundDelegate", EntityNotFoundDelegate); @@ -139,7 +137,6 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) info.AddValue("filterDefinitions", FilterDefinitions); info.AddValue("imports", Imports); info.AddValue("interceptor", interceptor); - info.AddValue("mapping", mapping); info.AddValue("namedQueries", NamedQueries); info.AddValue("namedSqlQueries", NamedSQLQueries); info.AddValue("namingStrategy", namingStrategy); @@ -246,10 +243,6 @@ private class StaticDialectMappingWrapper : IMapping { private readonly IMapping _mapping; - public StaticDialectMappingWrapper(IMapping mapping): this(mapping, mapping.Dialect) - { - } - public StaticDialectMappingWrapper(IMapping mapping, Dialect.Dialect dialect) { _mapping = mapping; @@ -279,23 +272,25 @@ public bool HasNonIdentifierPropertyNamedId(string className) public Dialect.Dialect Dialect { get; } } - private IMapping mapping; - protected Configuration(SettingsFactory settingsFactory) { - InitBlock(); this.settingsFactory = settingsFactory; Reset(); } - private void InitBlock() + // Since v5.5 + [Obsolete("Use BuildMapping(Dialect.Dialect) instead.")] + public virtual IMapping BuildMapping() { - mapping = BuildMapping(); + return new Mapping(this); } - public virtual IMapping BuildMapping() + public virtual IMapping BuildMapping(Dialect.Dialect dialect) { - return new Mapping(this); +#pragma warning disable CS0618 + var mapping = BuildMapping(); +#pragma warning restore CS0618 + return new StaticDialectMappingWrapper(mapping, dialect); } /// @@ -552,9 +547,8 @@ private void AddValidatedDocument(NamedXmlDocument doc) public void AddDeserializedMapping(HbmMapping mappingDocument, string documentFileName) { if (mappingDocument == null) - { - throw new ArgumentNullException("mappingDocument"); - } + throw new ArgumentNullException(nameof(mappingDocument)); + try { var dialect = new Lazy(() => Dialect.Dialect.GetDialect(properties)); @@ -749,9 +743,8 @@ public Configuration AddResource(string path, Assembly assembly) public Configuration AddResources(IEnumerable paths, Assembly assembly) { if (paths == null) - { - throw new ArgumentNullException("paths"); - } + throw new ArgumentNullException(nameof(paths)); + foreach (var path in paths) { AddResource(path, assembly); @@ -938,6 +931,7 @@ public static bool IncludeAction(SchemaAction actionsSource, SchemaAction includ /// public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { + var mapping = BuildMapping(dialect); SecondPassCompile(); var defaultCatalog = GetQuotedDefaultCatalog(dialect); @@ -945,12 +939,11 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) var script = new List(); - var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); foreach (var table in TableMappings) { if (table.IsPhysicalTable && IncludeAction(table.SchemaActions, SchemaAction.Export)) { - script.Add(table.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(table.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); script.AddRange(table.SqlCommentStrings(dialect, defaultCatalog, defaultSchema)); } } @@ -963,7 +956,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { foreach (var uk in table.UniqueKeyIterator) { - string constraintString = uk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema); + string constraintString = uk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema); if (constraintString != null) { script.Add(constraintString); @@ -973,7 +966,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) foreach (var index in table.IndexIterator) { - script.Add(index.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(index.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } if (dialect.SupportsForeignKeyConstraintInAlterTable) @@ -982,7 +975,7 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { if (fk.IsGenerated(dialect) && IncludeAction(fk.ReferencedTable.SchemaActions, SchemaAction.Export)) { - script.Add(fk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(fk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } } } @@ -999,18 +992,18 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect) { if (auxDbObj.AppliesToDialect(dialect)) { - script.Add(auxDbObj.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(auxDbObj.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } } return script.ToArray(); } - private void Validate() + private void Validate(IMapping mapping) { - ValidateEntities(); + ValidateEntities(mapping); - ValidateCollections(); + ValidateCollections(mapping); ValidateFilterDefs(); } @@ -1064,7 +1057,7 @@ private void ValidateFilterDefs() } } - private void ValidateCollections() + private void ValidateCollections(IMapping mapping) { foreach (var col in collections.Values) { @@ -1072,7 +1065,7 @@ private void ValidateCollections() } } - private void ValidateEntities() + private void ValidateEntities(IMapping mapping) { bool validateProxy = PropertiesHelper.GetBoolean(Environment.UseProxyValidator, properties, true); HashSet allProxyErrors = null; @@ -1286,8 +1279,7 @@ protected virtual void ConfigureProxyFactoryFactory() //http://nhibernate.jira.com/browse/NH-975 var ipff = Environment.BytecodeProvider as IInjectableProxyFactoryFactory; - string pffClassName; - properties.TryGetValue(Environment.ProxyFactoryFactoryClass, out pffClassName); + properties.TryGetValue(Environment.ProxyFactoryFactoryClass, out var pffClassName); if (ipff != null && !string.IsNullOrEmpty(pffClassName)) { ipff.SetProxyFactoryFactory(pffClassName); @@ -1304,33 +1296,21 @@ protected virtual void ConfigureProxyFactoryFactory() /// An instance. public ISessionFactory BuildSessionFactory() { - var dynamicDialectMapping = mapping; // Use a mapping which does store the dialect instead of instantiating a new one // at each access. The dialect does not change while building a session factory. // It furthermore allows some hack on NHibernate.Spatial side to go on working, // See nhibernate/NHibernate.Spatial#104 - mapping = new StaticDialectMappingWrapper(mapping); - try - { - ConfigureProxyFactoryFactory(); - SecondPassCompile(); - Validate(); - Environment.VerifyProperties(properties); - Settings settings = BuildSettings(); + var settings = BuildSettings(); + var mapping = BuildMapping(settings.Dialect); + ConfigureProxyFactoryFactory(); + SecondPassCompile(); + Validate(mapping); + Environment.VerifyProperties(properties); - // Ok, don't need schemas anymore, so free them - Schemas = null; + // Ok, don't need schemas anymore, so free them + Schemas = null; - return new SessionFactoryImpl( - this, - mapping, - settings, - GetInitializedEventListeners()); - } - finally - { - mapping = dynamicDialectMapping; - } + return new SessionFactoryImpl(this, mapping, settings, GetInitializedEventListeners()); } /// @@ -2363,13 +2343,13 @@ private static T[] AppendListeners(T[] existing, T[] listenersToAdd) /// public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMetadata databaseMetadata) { + var mapping = BuildMapping(dialect); SecondPassCompile(); var defaultCatalog = GetQuotedDefaultCatalog(dialect); var defaultSchema = GetQuotedDefaultSchema(dialect); var script = new List(50); - var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); foreach (var table in TableMappings) { if (table.IsPhysicalTable && IncludeAction(table.SchemaActions, SchemaAction.Update)) @@ -2378,11 +2358,11 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet table.Catalog ?? defaultCatalog, table.IsQuoted); if (tableInfo == null) { - script.Add(table.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(table.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } else { - string[] alterDDL = table.SqlAlterStrings(dialect, staticDialectMapping, tableInfo, defaultCatalog, defaultSchema); + string[] alterDDL = table.SqlAlterStrings(dialect, mapping, tableInfo, defaultCatalog, defaultSchema); script.AddRange(alterDDL); } @@ -2410,7 +2390,7 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet && (!(dialect is MySQLDialect) || tableInfo.GetIndexMetadata(fk.Name) == null)); if (create) { - script.Add(fk.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(fk.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } } } @@ -2420,7 +2400,7 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet { if (tableInfo == null || tableInfo.GetIndexMetadata(index.Name) == null) { - script.Add(index.SqlCreateString(dialect, staticDialectMapping, defaultCatalog, defaultSchema)); + script.Add(index.SqlCreateString(dialect, mapping, defaultCatalog, defaultSchema)); } } } @@ -2444,9 +2424,9 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet public void ValidateSchema(Dialect.Dialect dialect, IDatabaseMetadata databaseMetadata) { + var mapping = BuildMapping(dialect); SecondPassCompile(); - var staticDialectMapping = new StaticDialectMappingWrapper(mapping, dialect); var defaultCatalog = GetQuotedDefaultCatalog(dialect); var defaultSchema = GetQuotedDefaultSchema(dialect); @@ -2473,7 +2453,7 @@ public void ValidateSchema(Dialect.Dialect dialect, IDatabaseMetadata databaseMe } else { - validationErrors.AddRange(table.ValidateColumns(dialect, staticDialectMapping, tableInfo)); + validationErrors.AddRange(table.ValidateColumns(dialect, mapping, tableInfo)); } } } From fca2fe9e454a7049b1cbac37b10c6b9f05a93844 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 16 Aug 2023 09:20:29 +0300 Subject: [PATCH 041/128] Remove redundant collection BeforeAssemble call from query cache (#3410) --- .../Async/CacheTest/BatchableCacheFixture.cs | 48 +++++++++++++++++++ .../CacheTest/BatchableCacheFixture.cs | 48 +++++++++++++++++++ .../Generic/PersistentGenericBag.cs | 17 +++++-- .../Generic/PersistentGenericIdentifierBag.cs | 19 ++++++-- .../Generic/PersistentGenericList.cs | 17 +++++-- .../Generic/PersistentGenericMap.cs | 19 ++++++-- .../Generic/PersistentGenericSet.cs | 17 +++++-- .../Async/Collection/PersistentArrayHolder.cs | 13 ++++- .../Generic/PersistentGenericBag.cs | 16 +++++-- .../Generic/PersistentGenericIdentifierBag.cs | 18 +++++-- .../Generic/PersistentGenericList.cs | 16 +++++-- .../Generic/PersistentGenericMap.cs | 18 +++++-- .../Generic/PersistentGenericSet.cs | 16 +++++-- .../Collection/PersistentArrayHolder.cs | 12 ++++- 14 files changed, 246 insertions(+), 48 deletions(-) diff --git a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs index 3fe00c5e385..94ebca5e031 100644 --- a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs @@ -1588,6 +1588,54 @@ public async Task CollectionLazyInitializationFromCacheIsBatchedAsync() Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); } + [Test] + public async Task CollectionLazyInitializationFromCacheIsBatched_FillCacheByQueryCacheAsync() + { + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + int id; + using (var s = OpenSession()) + { + id = await (s.Query().Select(x => x.Id).FirstAsync()); + var readOnly = (await (s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToListAsync())) + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + using (var s = OpenSession()) + { + var readOnly = (await (s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToListAsync())) + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + + + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(id)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private async Task AssertMultipleCacheCallsAsync(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken)) where TEntity : CacheEntity diff --git a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs index a18e7b616ca..d3f06568cd6 100644 --- a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs @@ -1576,6 +1576,54 @@ public void CollectionLazyInitializationFromCacheIsBatched() Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); } + [Test] + public void CollectionLazyInitializationFromCacheIsBatched_FillCacheByQueryCache() + { + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + int id; + using (var s = OpenSession()) + { + id = s.Query().Select(x => x.Id).First(); + var readOnly = s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToList() + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + using (var s = OpenSession()) + { + var readOnly = s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToList() + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + + + using (var s = OpenSession()) + { + var readOnly = s.Get(id); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private void AssertMultipleCacheCalls(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null) where TEntity : CacheEntity diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs index 7ffa1b41fb9..687700d44fd 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs @@ -111,10 +111,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); - } + await (BeforeAssembleAsync(elementType, array, cancellationToken)).ConfigureAwait(false); for (var i = 0; i < size; i++) { @@ -126,6 +123,18 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist } } + private async Task BeforeAssembleAsync(IType elementType, object[] array, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + } + public override Task NeedsInsertingAsync(object entry, int i, IType elemType, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs index 1b8a8f57502..cb5c7bcc41b 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -47,11 +47,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist var identifierType = persister.IdentifierType; var elementType = persister.ElementType; - for (int i = 0; i < size; i += 2) - { - await (identifierType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); - await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); - } + await (BeforeAssembleAsync(identifierType, elementType, array, cancellationToken)).ConfigureAwait(false); for (int i = 0; i < size; i += 2) { @@ -60,6 +56,19 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist } } + private async Task BeforeAssembleAsync(IType identifierType, IType elementType, object[] array, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i += 2) + { + await (identifierType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); + } + } + public override async Task DisassembleAsync(ICollectionPersister persister, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs index 6ac827ecfa0..626fe414d3c 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs @@ -100,10 +100,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); - } + await (BeforeAssembleAsync(elementType, array, cancellationToken)).ConfigureAwait(false); for (int i = 0; i < size; i++) { @@ -112,6 +109,18 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist } } + private async Task BeforeAssembleAsync(IType elementType, object[] array, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + } + public override async Task DisassembleAsync(ICollectionPersister persister, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs index 3348087744a..18526b4d09d 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs @@ -97,11 +97,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist var indexType = persister.IndexType; var elementType = persister.ElementType; - for (int i = 0; i < size; i += 2) - { - await (indexType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); - await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); - } + await (BeforeAssembleAsync(indexType, elementType, array, cancellationToken)).ConfigureAwait(false); for (int i = 0; i < size; i += 2) { @@ -110,6 +106,19 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist } } + private async Task BeforeAssembleAsync(IType indexType, IType elementType, object[] array, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i += 2) + { + await (indexType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + await (elementType.BeforeAssembleAsync(array[i + 1], Session, cancellationToken)).ConfigureAwait(false); + } + } + public override async Task DisassembleAsync(ICollectionPersister persister, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs b/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs index c567ea44d86..848e918ef5e 100644 --- a/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs +++ b/src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs @@ -86,10 +86,7 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); - } + await (BeforeAssembleAsync(elementType, array, cancellationToken)).ConfigureAwait(false); for (int i = 0; i < size; i++) { @@ -102,6 +99,18 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist SetInitialized(); } + private async Task BeforeAssembleAsync(IType elementType, object[] array, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + await (elementType.BeforeAssembleAsync(array[i], Session, cancellationToken)).ConfigureAwait(false); + } + } + public override async Task ReadFromAsync(DbDataReader rs, ICollectionPersister role, ICollectionAliases descriptor, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Async/Collection/PersistentArrayHolder.cs b/src/NHibernate/Async/Collection/PersistentArrayHolder.cs index a08d2e6e96e..6fb58819c4d 100644 --- a/src/NHibernate/Async/Collection/PersistentArrayHolder.cs +++ b/src/NHibernate/Async/Collection/PersistentArrayHolder.cs @@ -95,14 +95,23 @@ public override async Task InitializeFromCacheAsync(ICollectionPersister persist array = System.Array.CreateInstance(persister.ElementClass, cached.Length); var elementType = persister.ElementType; + await (BeforeAssembleAsync(elementType, cached, cancellationToken)).ConfigureAwait(false); + for (int i = 0; i < cached.Length; i++) { - await (elementType.BeforeAssembleAsync(cached[i], Session, cancellationToken)).ConfigureAwait(false); + array.SetValue(await (elementType.AssembleAsync(cached[i], Session, owner, cancellationToken)).ConfigureAwait(false), i); } + } + + private async Task BeforeAssembleAsync(IType elementType, object[] cached, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; for (int i = 0; i < cached.Length; i++) { - array.SetValue(await (elementType.AssembleAsync(cached[i], Session, owner, cancellationToken)).ConfigureAwait(false), i); + await (elementType.BeforeAssembleAsync(cached[i], Session, cancellationToken)).ConfigureAwait(false); } } diff --git a/src/NHibernate/Collection/Generic/PersistentGenericBag.cs b/src/NHibernate/Collection/Generic/PersistentGenericBag.cs index 6530936f613..74740304845 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericBag.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericBag.cs @@ -402,10 +402,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - elementType.BeforeAssemble(array[i], Session); - } + BeforeAssemble(elementType, array); for (var i = 0; i < size; i++) { @@ -417,6 +414,17 @@ public override void InitializeFromCache(ICollectionPersister persister, object } } + private void BeforeAssemble(IType elementType, object[] array) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + elementType.BeforeAssemble(array[i], Session); + } + } + public override bool IsSnapshotEmpty(object snapshot) { return ((ICollection) snapshot).Count == 0; diff --git a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs index 59769257121..f66980aa8b6 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericIdentifierBag.cs @@ -78,11 +78,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object var identifierType = persister.IdentifierType; var elementType = persister.ElementType; - for (int i = 0; i < size; i += 2) - { - identifierType.BeforeAssemble(array[i], Session); - elementType.BeforeAssemble(array[i + 1], Session); - } + BeforeAssemble(identifierType, elementType, array); for (int i = 0; i < size; i += 2) { @@ -91,6 +87,18 @@ public override void InitializeFromCache(ICollectionPersister persister, object } } + private void BeforeAssemble(IType identifierType, IType elementType, object[] array) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i += 2) + { + identifierType.BeforeAssemble(array[i], Session); + elementType.BeforeAssemble(array[i + 1], Session); + } + } + private object GetIdentifier(int index) { // NH specific : To emulate IDictionary behavior but using Dictionary (without boxing/unboxing for index) diff --git a/src/NHibernate/Collection/Generic/PersistentGenericList.cs b/src/NHibernate/Collection/Generic/PersistentGenericList.cs index 2c08510c311..c8756cf504b 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericList.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericList.cs @@ -162,10 +162,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - elementType.BeforeAssemble(array[i], Session); - } + BeforeAssemble(elementType, array); for (int i = 0; i < size; i++) { @@ -174,6 +171,17 @@ public override void InitializeFromCache(ICollectionPersister persister, object } } + private void BeforeAssemble(IType elementType, object[] array) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + elementType.BeforeAssemble(array[i], Session); + } + } + public override object Disassemble(ICollectionPersister persister) { int length = WrappedList.Count; diff --git a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs index 24c4c30568e..da27836713b 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericMap.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericMap.cs @@ -166,11 +166,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object var indexType = persister.IndexType; var elementType = persister.ElementType; - for (int i = 0; i < size; i += 2) - { - indexType.BeforeAssemble(array[i], Session); - elementType.BeforeAssemble(array[i + 1], Session); - } + BeforeAssemble(indexType, elementType, array); for (int i = 0; i < size; i += 2) { @@ -179,6 +175,18 @@ public override void InitializeFromCache(ICollectionPersister persister, object } } + private void BeforeAssemble(IType indexType, IType elementType, object[] array) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i += 2) + { + indexType.BeforeAssemble(array[i], Session); + elementType.BeforeAssemble(array[i + 1], Session); + } + } + public override object Disassemble(ICollectionPersister persister) { object[] result = new object[WrappedMap.Count * 2]; diff --git a/src/NHibernate/Collection/Generic/PersistentGenericSet.cs b/src/NHibernate/Collection/Generic/PersistentGenericSet.cs index f2736a8d21c..9a686724e41 100644 --- a/src/NHibernate/Collection/Generic/PersistentGenericSet.cs +++ b/src/NHibernate/Collection/Generic/PersistentGenericSet.cs @@ -156,10 +156,7 @@ public override void InitializeFromCache(ICollectionPersister persister, object BeforeInitialize(persister, size); var elementType = persister.ElementType; - for (int i = 0; i < size; i++) - { - elementType.BeforeAssemble(array[i], Session); - } + BeforeAssemble(elementType, array); for (int i = 0; i < size; i++) { @@ -172,6 +169,17 @@ public override void InitializeFromCache(ICollectionPersister persister, object SetInitialized(); } + private void BeforeAssemble(IType elementType, object[] array) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; + + for (int i = 0; i < array.Length; i++) + { + elementType.BeforeAssemble(array[i], Session); + } + } + public override bool Empty { get { return WrappedSet.Count == 0; } diff --git a/src/NHibernate/Collection/PersistentArrayHolder.cs b/src/NHibernate/Collection/PersistentArrayHolder.cs index 1bd42dc42ce..aaa8ab2625d 100644 --- a/src/NHibernate/Collection/PersistentArrayHolder.cs +++ b/src/NHibernate/Collection/PersistentArrayHolder.cs @@ -197,14 +197,22 @@ public override void InitializeFromCache(ICollectionPersister persister, object array = System.Array.CreateInstance(persister.ElementClass, cached.Length); var elementType = persister.ElementType; + BeforeAssemble(elementType, cached); + for (int i = 0; i < cached.Length; i++) { - elementType.BeforeAssemble(cached[i], Session); + array.SetValue(elementType.Assemble(cached[i], Session, owner), i); } + } + + private void BeforeAssemble(IType elementType, object[] cached) + { + if (Session.PersistenceContext.BatchFetchQueue.QueryCacheQueue != null) + return; for (int i = 0; i < cached.Length; i++) { - array.SetValue(elementType.Assemble(cached[i], Session, owner), i); + elementType.BeforeAssemble(cached[i], Session); } } From 20ec2405afa6fd73bca5d2acbb7df1e8b3be5e48 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 17 Aug 2023 00:13:35 +1000 Subject: [PATCH 042/128] Remove ISessionFactoryImplementor parameter from TableGroupJoinHelper (#3411) --- src/NHibernate/Engine/JoinSequence.cs | 6 +++--- src/NHibernate/Engine/TableGroupJoinHelper.cs | 2 +- src/NHibernate/Loader/JoinWalker.cs | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/NHibernate/Engine/JoinSequence.cs b/src/NHibernate/Engine/JoinSequence.cs index 83c8baf0aaa..7fcfc9eb86b 100644 --- a/src/NHibernate/Engine/JoinSequence.cs +++ b/src/NHibernate/Engine/JoinSequence.cs @@ -187,11 +187,11 @@ internal virtual JoinFragment ToJoinFragment( { Join join = joins[i]; - withClauses[i] = GetWithClause(enabledFilters, ref withClauseFragment, join, last); + withClauses[i] = GetWithClause(enabledFilters, join, last, ref withClauseFragment); last = join.Joinable; } - if (rootJoinable == null && !IsThetaStyle && TableGroupJoinHelper.ProcessAsTableGroupJoin(joins, withClauses, includeAllSubclassJoins, joinFragment, alias => IsIncluded(alias), factory)) + if (rootJoinable == null && !IsThetaStyle && TableGroupJoinHelper.ProcessAsTableGroupJoin(joins, withClauses, includeAllSubclassJoins, joinFragment, alias => IsIncluded(alias))) { return joinFragment; } @@ -223,7 +223,7 @@ internal virtual JoinFragment ToJoinFragment( return joinFragment; } - private SqlString GetWithClause(IDictionary enabledFilters, ref SqlString withClauseFragment, Join join, IJoinable last) + private SqlString GetWithClause(IDictionary enabledFilters, Join join, IJoinable last, ref SqlString withClauseFragment) { string on = join.AssociationType.GetOnCondition(join.Alias, factory, enabledFilters); var withConditions = new List(); diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 132a677fee3..c47e74cfac3 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -17,7 +17,7 @@ namespace NHibernate.Engine // ) ON person0_.Id = individual1_.PersonID AND individual1_1_.Deleted = @p0 internal class TableGroupJoinHelper { - internal static bool ProcessAsTableGroupJoin(IReadOnlyList tableGroupJoinables, SqlString[] withClauseFragments, bool includeAllSubclassJoins, JoinFragment joinFragment, Func isSubclassIncluded, ISessionFactoryImplementor sessionFactoryImplementor) + internal static bool ProcessAsTableGroupJoin(IReadOnlyList tableGroupJoinables, SqlString[] withClauseFragments, bool includeAllSubclassJoins, JoinFragment joinFragment, Func isSubclassIncluded) { if (!NeedsTableGroupJoin(tableGroupJoinables, withClauseFragments, includeAllSubclassJoins, isSubclassIncluded)) return false; diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index 9d28bd9d61c..bbe9d93a1bb 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -898,8 +898,7 @@ protected JoinFragment MergeOuterJoins(IList associati new[] {oj.On, entityAssociation.On, string.IsNullOrEmpty(f) ? SqlString.Empty : new SqlString(f)}, true, outerjoin, - alias => true, - factory)) + _ => true)) { index++; continue; @@ -921,7 +920,7 @@ protected JoinFragment MergeOuterJoins(IList associati } } - if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] {oj}, new[] {oj.On, filter}, true, outerjoin, alias => true, factory)) + if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] {oj}, new[] {oj.On, filter}, true, outerjoin, _ => true)) continue; oj.AddJoins(outerjoin); From 8ad3d1fbee67c9a357d590ebea751971f388275b Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sat, 19 Aug 2023 09:54:10 +0300 Subject: [PATCH 043/128] Revive hql ParsingFixture (#3412) Various tests for hql parser generated by Hql.g --- src/NHibernate.Test/Hql/Ast/ParsingFixture.cs | 297 +- src/NHibernate.Test/Hql/Ast/TestQueries.xml | 3006 ----------------- .../Hql/Ast/TestQueriesWithResults.xml | 26 +- src/NHibernate.Test/NHibernate.Test.csproj | 3 + 4 files changed, 145 insertions(+), 3187 deletions(-) delete mode 100644 src/NHibernate.Test/Hql/Ast/TestQueries.xml diff --git a/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs b/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs index 45be4789f1c..3af770191d5 100644 --- a/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs +++ b/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs @@ -1,176 +1,137 @@ using System; using System.Collections.Generic; -using log4net.Config; -using NHibernate.Cfg; -using NHibernate.Engine; +using System.IO; +using System.Xml.Linq; using NHibernate.Hql.Ast.ANTLR; -using NHibernate.Tool.hbm2ddl; using NUnit.Framework; namespace NHibernate.Test.Hql.Ast { - // This test need the new NUnit - //[TestFixture] - //public class ParsingFixture - //{ - // /// - // /// Key test for HQL strings -> HQL AST's - takes the query and returns a string - // /// representation of the resultant tree - // /// - // /// - // /// - // [Test] - // [TestCaseSource(typeof(QueryFactoryClass), "TestCases")] - // public string HqlParse(string query) - // { - // // This test need the new NUnit - // var p = new HqlParseEngine(query, false, null); - // p.Parse(); - - // return " " + p.Ast.ToStringTree(); - // } - - // /// - // /// Used to test individual queries "by hand", since td.net doesn't let me run a - // /// single test out of a data set - // /// - // [Test] - // public void ManualTest() - // { - // var p = new HqlParseEngine(@"select all s, s.Other from s in class Simple where s = :s", false, null); - - // p.Parse(); - - // Console.WriteLine(p.Ast.ToStringTree()); - // } - - // /// - // /// Helper "test" to display queries that are ignored - // /// - // [Test] - // public void ShowIgnoredQueries() - // { - // foreach (string query in QueryFactoryClass.GetIgnores) - // { - // Console.WriteLine(query); - // } - // } - - // /// - // /// Helper "test" to display queries that don't parse in H3 - // /// - // [Test] - // public void ShowExceptionQueries() - // { - // foreach (string query in QueryFactoryClass.GetExceptions) - // { - // Console.WriteLine(query); - // } - // } - - // /// - // /// Goes all the way to the DB and back. Just here until there's a better place to put it... - // /// - // [Test] - // public void BasicQuery() - // { - // string input = "select o.id, li.id from NHibernate.Test.CompositeId.Order o join o.LineItems li";// join o.LineItems li"; - - // ISessionFactoryImplementor sfi = SetupSFI(); - - // ISession session = sfi.OpenSession(); - // session.CreateQuery(input).List(); - // /* - // foreach (Animal o in session.CreateQuery(input).Enumerable()) - // { - // Console.WriteLine(o.Description); - // }*/ - // } - - // ISessionFactoryImplementor SetupSFI() - // { - // Configuration cfg = new Configuration(); - // cfg.AddAssembly(this.GetType().Assembly); - // new SchemaExport(cfg).Create(false, true); - // return (ISessionFactoryImplementor)cfg.BuildSessionFactory(); - // } - - // /// - // /// Class used by Nunit 2.5 to drive the data into the HqlParse test - // /// - // public class QueryFactoryClass - // { - // public static IEnumerable TestCases - // { - // get - // { - // // TODO - need to handle Ignore better (it won't show in results...) - // return EnumerateTests(td => !td.Ignore && !td.Result.StartsWith("Exception"), - // td => new TestCaseData(td.Query) - // .Returns(td.Result) - // .SetCategory(td.Category) - // .SetName(td.Name) - // .SetDescription(td.Description)); - // } - // } - - // public static IEnumerable GetIgnores - // { - // get - // { - // return EnumerateTests(td => td.Ignore, - // td => td.Query); - // } - // } - - // public static IEnumerable GetExceptions - // { - // get - // { - // return EnumerateTests(td => td.Result.StartsWith("Exception"), - // td => td.Query); - // } - // } - - // static IEnumerable EnumerateTests(Func predicate, Func projection) - // { - // XDocument doc = XDocument.Load(@"HQL Parsing\TestQueriesWithResults.xml"); - - // foreach (XElement testGroup in doc.Element("Tests").Elements("TestGroup")) - // { - // string category = testGroup.Attribute("Name").Value; - - // foreach (XElement test in testGroup.Elements("Test")) - // { - // QueryTestData testData = new QueryTestData(category, test); - - // if (predicate(testData)) - // { - // yield return projection(testData); - // } - // } - // } - // } - - // class QueryTestData - // { - // internal QueryTestData(string category, XElement xml) - // { - // Category = category; - // Query = xml.Element("Query").Value; - // Result = xml.Element("Result") != null ? xml.Element("Result").Value : "barf"; - // Name = xml.Element("Name") != null ? xml.Element("Name").Value : null; - // Description = xml.Element("Description") != null ? xml.Element("Description").Value : null; - // Ignore = xml.Attribute("Ignore") != null ? bool.Parse(xml.Attribute("Ignore").Value) : false; - // } - - // internal string Category; - // internal string Query; - // internal string Result; - // internal string Name; - // internal string Description; - // internal bool Ignore; - // } - // } - //} + [TestFixture] + public class ParsingFixture + { + /// + /// Key test for HQL strings -> HQL AST's - takes the query and returns a string + /// representation of the resultant tree + /// + /// + /// + [Test] + [TestCaseSource(typeof(QueryFactoryClass), nameof(QueryFactoryClass.TestCases))] + public string HqlParse(string query) + { + var p = new HqlParseEngine(query, false, null); + var result = p.Parse().ToStringTree(); + + return " " + result; + } + + /// + /// Used to test individual queries "by hand", since td.net doesn't let me run a + /// single test out of a data set + /// + [Test, Explicit] + public void ManualTest() + { + var p = new HqlParseEngine(@"select all s, s.Other from s in class Simple where s = :s", false, null); + + var result = p.Parse().ToStringTree(); + + Console.WriteLine(result); + } + + /// + /// Helper "test" to display queries that are ignored + /// + [Test, Explicit] + public void ShowIgnoredQueries() + { + foreach (string query in QueryFactoryClass.GetIgnores) + { + Console.WriteLine(query); + } + } + + /// + /// Helper "test" to display queries that don't parse in H3 + /// + [Test, Explicit] + public void ShowExceptionQueries() + { + foreach (string query in QueryFactoryClass.GetExceptions) + { + Console.WriteLine(query); + } + } + + /// + /// Class used by NUnit to drive the data into the HqlParse test. + /// + public class QueryFactoryClass + { + public static IEnumerable TestCases => + // TODO - need to handle Ignore better (it won't show in results...) + EnumerateTests( + td => !td.Ignore && !td.Result.StartsWith("Exception"), + td => new TestCaseData(td.Query) + .Returns(td.Result) + .SetCategory(td.Category) + .SetName(td.Name) + .SetDescription(td.Description)); + + public static IEnumerable GetIgnores => + EnumerateTests( + td => td.Ignore, + td => td.Query); + + public static IEnumerable GetExceptions => + EnumerateTests( + td => td.Result.StartsWith("Exception"), + td => td.Query); + + static IEnumerable EnumerateTests( + Func predicate, + Func projection) + { + + XDocument doc = XDocument.Load( + Path.Combine(Path.GetDirectoryName(typeof(ParsingFixture).Assembly.Location), @"Hql/Ast/TestQueriesWithResults.xml")); + + foreach (XElement testGroup in doc.Element("Tests").Elements("TestGroup")) + { + string category = testGroup.Attribute("Name").Value; + + foreach (XElement test in testGroup.Elements("Test")) + { + QueryTestData testData = new QueryTestData(category, test); + + if (predicate(testData)) + { + yield return projection(testData); + } + } + } + } + + class QueryTestData + { + internal QueryTestData(string category, XElement xml) + { + Category = category; + Query = xml.Element("Query").Value.Trim(); + Result = xml.Element("Result")?.Value; + Name = xml.Element("Name")?.Value; + Description = xml.Element("Description")?.Value.Trim() ?? string.Empty; + Ignore = bool.Parse(xml.Attribute("Ignore")?.Value ?? "false"); + } + + internal string Category; + internal string Query; + internal string Result; + internal string Name; + internal string Description; + internal bool Ignore; + } + } + } } diff --git a/src/NHibernate.Test/Hql/Ast/TestQueries.xml b/src/NHibernate.Test/Hql/Ast/TestQueries.xml deleted file mode 100644 index 5b0488ae037..00000000000 --- a/src/NHibernate.Test/Hql/Ast/TestQueries.xml +++ /dev/null @@ -1,3006 +0,0 @@ - - - - - all baz.IntArray.indices]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - current_date]]> - - - 100]]> - - - 10000]]> - - - - 100]]> - - - 10000]]> - - - - - - - - - - - - - all elements(p.scores)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100 - order by count(kitten) asc, sum(kitten.weight) desc - ]]> - - - - - - - = all ( - select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate) group by ord - having sum(price.amount) > :minAmount order by sum(price.amount) desc - ]]> - - - - :minAmount order by sum(price.amount) desc - ]]> - - - - PaymentStatus.AWAITING_APPROVAL or ( - statusChange.timeStamp = ( select max(change.timeStamp) - from PaymentStatusChange change where change.payment = payment - ) and statusChange.user <> :currentUser ) - group by status.name, status.sortOrder order by status.sortOrder - ]]> - - - PaymentStatus.AWAITING_APPROVAL - or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser - group by status.name, status.sortOrder order by status.sortOrder - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ( select avg(cat.weight) from eg.DomesticCat cat)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.1415e3]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - parse( - "SELECT DISTINCT bar FROM eg.mypackage.Cat qat left join com.multijoin.JoinORama as bar, com.toadstool.Foo f join net.sf.blurb.Blurb"); - - - - - - - - - - - - - 5]]> - - - 5]]> - - - - - - - - - - - - 10]]> - - - 10 and an.bodyWeight < 100) or an.bodyWeight is null - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Added quote quote is an escape - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - 'a' or foo2.id <'a' - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ? or bar.short = 1 or bar.string = 'ff ? bb']]> - - - - - - - - - - - - - - - - - - '0' order by s.foo]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'a']]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TODO: "count" is reserved - - - - TODO: "count" is reserved - - - - TODO: "count" is reserved - - - - - - - - - - 0]]> - - - 0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - :count]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - - - - 'a']]> - - - - - - - - - - - - - - - - - - - - - 'a']]> - - - 'a']]> - - - - - - - - - - - - - - - -1 and s.name is null]]> - - - - - - -1 and s.name is null]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - ]]> - - - 0 and m.extraProp is not null]]> - - - 0 and m.name is not null]]> - - - - - - - - - 0.0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Added '?' as a valid expression. - - - - - - - - - Added collectionExpr as a valid 'in' clause. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cover NOT optimization in HqlParser - - - - - 1 )]]> - - - = 1 )]]> - - - - - - - - - - - - - - - double "NOT" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - -1 and this.name is null]]> - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - - - - - - - - - - - - no member of - - - - - - - - - - - - - - - - The keyword 'order' used as a property name. - - - - The keyword 'order' and 'count' used as a property name. - 3]]> - - - - The keywords 'where', 'order' and 'count' used as a property name. - 3]]> - - - - - - - - - - - - - Super evil badness... a legitimate keyword! - - - - - - - - - - - - - - - - - - - - - - - - - - Okay, now this is getting silly. - - - - - - - - - - - - - - - 'where' as a package name - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TODO support .NET identifier NH-685; won't fix ? - - - - - - - TODO Some SQLs have function names with package qualifiers. - - - - - - - - - - - - - - - - - won't fix - - :dateenow ]]> - - - - - - - - - - - - - - 1]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [Test, Ignore("Not supported")] - - - TODO InnerClass but for NET - the problem with inner class is that in .NET the "separator" is '+' and - Path+Identifier is a valid MathAddExpression - because this is a special case and the use of entity-name is a valid workaroud we can wait - to support it or we can choose another character to query inner-classes (the same of JAVA '$' is a valid choice) - - - - - - - - - - - TODO Support Unicode in StringLiteral - - - - - - - - from NHibernate tests - - - - - - - - 1]]> - - - - - - 0]]> - - - - - - 0]]> - - - - - - 0]]> - - - - - - 0]]> - - - - from NHibernate tests - - - - - - - - - - - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - 0]]> - - - 0]]> - - - - from NHibernate tests - - - - - - - - - - - - - - from NHibernate tests - - - - - 10]]> - - - - - from NHibernate tests - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - 0]]> - - - - - - - - - - - from NHibernate tests - - - - - - - from NHibernate tests - - - - - 0]]> - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - from NHibernate tests - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - 0]]> - - - 3]]> - - - 0]]> - - - - \ No newline at end of file diff --git a/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml b/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml index c7d8efb5a52..03fa3aa7a5e 100644 --- a/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml +++ b/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml @@ -269,14 +269,14 @@ select cat.color, sum(cat.weight), count(cat) from eg.Cat cat group by cat.color having cat.color in (eg.Color.TABBY, eg.Color.BLACK) ]]> - + 100 order by count(kitten) asc, sum(kitten.weight) desc ]]> - ( avg ( . kitten weight ) ) 100 ) ) ) ( order ( count kitten ) asc ( sum ( . kitten weight ) ) desc ) )]]> + ( avg ( . kitten weight ) ) 100 ) ) ( order ( count kitten ) asc ( sum ( . kitten weight ) ) desc ) )]]> @@ -290,7 +290,7 @@ select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate) group by ord having sum(price.amount) > :minAmount order by sum(price.amount) desc ]]> - = ( . catalog effectiveDate ) ( all ( query ( SELECT_FROM ( from ( RANGE Catalog cat ) ) ( select ( . cat effectiveDate ) ) ) ( where ( < ( . cat effectiveDate ) sysdate ) ) ) ) ) ) ) ( group ord ( having ( > ( sum ( . price amount ) ) ( : minAmount ) ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> + = ( . catalog effectiveDate ) ( all ( query ( SELECT_FROM ( from ( RANGE Catalog cat ) ) ( select ( . cat effectiveDate ) ) ) ( where ( < ( . cat effectiveDate ) sysdate ) ) ) ) ) ) ) ( group ord ) ( having ( > ( sum ( . price amount ) ) ( : minAmount ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> :minAmount order by sum(price.amount) desc ]]> - ( sum ( . price amount ) ) ( : minAmount ) ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> + ( sum ( . price amount ) ) ( : minAmount ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> 10]]> - ( sum ( . s count ) ) 10 ) ) ) )]]> + ( sum ( . s count ) ) 10 ) ) )]]> - + @@ -3510,7 +3510,7 @@ 0]]> - ( ( abs ( exprList ( * ( . a BodyWeight ) ( - 1 ) ) ) ) 0 ) ) ) )]]> + ( ( abs ( exprList ( * ( . a BodyWeight ) ( - 1 ) ) ) ) 0 ) ) )]]> @@ -3551,7 +3551,7 @@ - + @@ -3568,7 +3568,7 @@ - + @@ -3615,15 +3615,15 @@ 0]]> - ( ( cast ( exprList ( . a BodyWeight ) Double ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( . a BodyWeight ) Double ) ) 0 ) ) )]]> 0]]> - ( ( cast ( exprList ( - ( + 7 123.3 ) ( * 1 ( . a BodyWeight ) ) ) int ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( - ( + 7 123.3 ) ( * 1 ( . a BodyWeight ) ) ) int ) ) 0 ) ) )]]> 0]]> - ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) int ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) int ) ) 0 ) ) )]]> @@ -3718,7 +3718,7 @@ 0]]> - ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) Double ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) Double ) ) 0 ) ) )]]> diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index a3770c40cbf..43e244811b9 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -34,6 +34,9 @@ Always + + PreserveNewest + From 555d34047e3f63cee9746164fca3c175593801d0 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Mon, 21 Aug 2023 04:33:01 +0300 Subject: [PATCH 044/128] Downgrade dependency System.Data.SQLite.Core 1.0.118 -> 1.0.117 (#3413) --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 43e244811b9..501131de1e1 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -65,7 +65,7 @@ - + From a842cbe95c5f7e97d7eff0c376e65d644b6225aa Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Tue, 22 Aug 2023 19:39:23 +0200 Subject: [PATCH 045/128] Reenable use of SelectClauseVisitor for subqueries (#3414) --- src/NHibernate.Test/Async/Linq/WhereTests.cs | 13 +++++++++++++ src/NHibernate.Test/Linq/WhereTests.cs | 13 +++++++++++++ src/NHibernate/Linq/Visitors/QueryModelVisitor.cs | 6 +----- .../Linq/Visitors/SelectClauseNominator.cs | 4 ++-- src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs | 6 ++++-- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/Async/Linq/WhereTests.cs b/src/NHibernate.Test/Async/Linq/WhereTests.cs index aceda381352..365ad00de7f 100644 --- a/src/NHibernate.Test/Async/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Async/Linq/WhereTests.cs @@ -659,6 +659,19 @@ where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) Assert.That(query.Count, Is.EqualTo(1)); } + [Test] + public async Task TimesheetsWithProjectionInSubqueryAsync() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = await ((from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToListAsync()); + + Assert.That(query.Count, Is.EqualTo(2)); + } + [Test] public async Task ContainsSubqueryWithCoalesceStringEnumSelectAsync() { diff --git a/src/NHibernate.Test/Linq/WhereTests.cs b/src/NHibernate.Test/Linq/WhereTests.cs index 5fffc56c052..90981dbc4d1 100644 --- a/src/NHibernate.Test/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Linq/WhereTests.cs @@ -660,6 +660,19 @@ where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) Assert.That(query.Count, Is.EqualTo(1)); } + [Test] + public void TimesheetsWithProjectionInSubquery() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = (from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToList(); + + Assert.That(query.Count, Is.EqualTo(2)); + } + [Test] public void ContainsSubqueryWithCoalesceStringEnumSelect() { diff --git a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs index c9f2a054bb1..43720cb12fb 100644 --- a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs +++ b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs @@ -476,13 +476,9 @@ public override void VisitSelectClause(SelectClause selectClause, QueryModel que private HqlSelect GetSelectClause(Expression selectClause) { - if (!_root) - return _hqlTree.TreeBuilder.Select( - HqlGeneratorExpressionVisitor.Visit(selectClause, VisitorParameters).AsExpression()); - var visitor = new SelectClauseVisitor(typeof(object[]), VisitorParameters); - visitor.VisitSelector(selectClause); + visitor.VisitSelector(selectClause, !_root); if (visitor.ProjectionExpression != null) { diff --git a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs index 52bf954101d..0ab0dc25e4d 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs @@ -43,13 +43,13 @@ public SelectClauseHqlNominator(VisitorParameters parameters) _parameters = parameters; } - internal Expression Nominate(Expression expression) + internal Expression Nominate(Expression expression, bool isSubQuery = false) { HqlCandidates = new HashSet(); ContainsUntranslatedMethodCalls = false; _canBeCandidate = true; _stateStack = new Stack(); - _stateStack.Push(false); + _stateStack.Push(isSubQuery); return Visit(expression); } diff --git a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs index df1cdfb3daa..a5155415dfd 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs @@ -34,7 +34,9 @@ public IEnumerable GetHqlNodes() return _hqlTreeNodes; } - public void VisitSelector(Expression expression) + public void VisitSelector(Expression expression) => VisitSelector(expression, false); + + public void VisitSelector(Expression expression, bool isSubQuery) { var distinct = expression as NhDistinctExpression; if (distinct != null) @@ -44,7 +46,7 @@ public void VisitSelector(Expression expression) // Find the sub trees that can be expressed purely in HQL var nominator = new SelectClauseHqlNominator(_parameters); - expression = nominator.Nominate(expression); + expression = nominator.Nominate(expression, isSubQuery); _hqlNodes = nominator.HqlCandidates; // Linq2SQL ignores calls to local methods. Linq2EF seems to not support From c65a78f264bfbe9093bed7e374859012ba734b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:40:49 +0200 Subject: [PATCH 046/128] Enable dev builds for 5.4.6 --- build-common/NHibernate.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 73ae769c705..1f193e3510b 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,9 +3,9 @@ 5.4 - 5 + 6 - + dev 9.0 $(NhVersion).$(VersionPatch) From 98bd644946933e6d4a37659114856daf576bbcaf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 17:06:35 +0200 Subject: [PATCH 047/128] Update dependency Npgsql to v7 (#3202) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 501131de1e1..32ceeff6e74 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -72,7 +72,7 @@ - + From ccff7845429de63a7f0bc0eb786a3492aaf06b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 27 Aug 2023 20:07:49 +0200 Subject: [PATCH 048/128] Release 5.4.6 (#3419) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 1f193e3510b..7fd65db2f30 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.4 6 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index a612526094e..2f999a17b66 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,20 @@ -Build 5.4.5 +Build 5.4.6 +============================= + +Release notes - NHibernate - Version 5.4.6 + +2 issues were resolved in this release. + +** Bug + + * #3414 Reenable use of SelectClauseVisitor for subqueries + +** Task + + * #3419 Release 5.4.6 + + +Build 5.4.5 ============================= Release notes - NHibernate - Version 5.4.5 @@ -7,8 +23,8 @@ Release notes - NHibernate - Version 5.4.5 ** Task - * #3408 Release 5.4.4 - * #3407 Release Merge 5.3.19 in 5.4.x + * #3408 Release 5.4.5 + * #3407 Merge 5.3.19 in 5.4.x Build 5.4.4 From 98d170a769be9dcc973e6a65f2379063f94a80a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:43:39 +1000 Subject: [PATCH 049/128] Update actions/checkout action to v4 (#3423) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/GenerateAsyncCode.yml | 2 +- .github/workflows/NetCoreTests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/GenerateAsyncCode.yml b/.github/workflows/GenerateAsyncCode.yml index 2a28aa4e5dd..07ede3704e9 100644 --- a/.github/workflows/GenerateAsyncCode.yml +++ b/.github/workflows/GenerateAsyncCode.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index 478eabf8f9a..9cf09a1671d 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -47,7 +47,7 @@ jobs: steps: - name: Set up ${{matrix.DB}} run: ${{matrix.DB_INIT}} - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v3 with: From 7a86566437b8bcad019213f83f9b63c02af559a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Mon, 18 Sep 2023 03:44:47 +0200 Subject: [PATCH 050/128] Explicit how to use advanced Redis strategies (#3429) --- doc/reference/modules/nhibernate_caches.xml | 32 ++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/doc/reference/modules/nhibernate_caches.xml b/doc/reference/modules/nhibernate_caches.xml index 997b5ff1a0b..3b3c1f5c0b7 100644 --- a/doc/reference/modules/nhibernate_caches.xml +++ b/doc/reference/modules/nhibernate_caches.xml @@ -818,6 +818,14 @@ Extends NHibernate.Caches.StackExchangeRedis.DefaultRegionStrategy and uses an additional local memory cache for faster readings. The local caches are invalidated by using Redis pub/sub mechanism. This strategy should be used only for regions that have few write operations and a high expiration time. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + This strategy inherits additional settings from DefaultRegionStrategy and also has its own settings: cache.region_strategy.two_layer_cache.use_pipelining @@ -848,7 +856,16 @@ Extends NHibernate.Caches.StackExchangeRedis.FastRegionStrategy and uses an additional local memory cache for faster readings. The local caches are invalidated by using Redis pub/sub mechanism. This strategy does not support ICache.Clear operation and should be used only for regions that have - few write operations and a high expiration time. This strategy has additional settings: + few write operations and a high expiration time. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + + This strategy has additional settings: cache.region_strategy.fast_two_layer_cache.use_pipelining @@ -880,9 +897,16 @@ operation was performed. When two operations have the same DateTime.Ticks, then the client with the highest id wins. This strategy should be used only for regions that have few write operations and a high expiration time. It is recommended to use NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy, when the instances where the strategy - would run are often restarted/recycled. In order to use this strategy a custom ICacheRegionStrategyFactory - has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a custom - RegionMemoryCacheBase implementation. This strategy has additional settings: + would run are often restarted/recycled. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + + This strategy has additional settings: cache.region_strategy.distributed_local_cache.use_pipelining From f3031ae6d36d2e7e755fbe5a87f10e8d3a5ea1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:07:44 +0100 Subject: [PATCH 051/128] Fix DB2/400 schema generation on 5.3.x (#3451) Co-authored-by: Roman Artiukhin --- .github/workflows/GenerateAsyncCode.yml | 2 +- src/NHibernate/Dialect/DB2400Dialect.cs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/GenerateAsyncCode.yml b/.github/workflows/GenerateAsyncCode.yml index dd2badb26c4..e505bf91508 100644 --- a/.github/workflows/GenerateAsyncCode.yml +++ b/.github/workflows/GenerateAsyncCode.yml @@ -27,7 +27,7 @@ jobs: run: | dotnet restore "./Tools/packages.csproj" --packages ./Tools pushd src - dotnet restore ./NHibernate.sln + dotnet restore ./NHibernate.sln /p:TreatWarningsAsErrors=false dotnet $(find ./../Tools/csharpasyncgenerator.commandline -name AsyncGenerator.CommandLine.dll) popd diff --git a/src/NHibernate/Dialect/DB2400Dialect.cs b/src/NHibernate/Dialect/DB2400Dialect.cs index aa306a0d05a..91a23b1a219 100644 --- a/src/NHibernate/Dialect/DB2400Dialect.cs +++ b/src/NHibernate/Dialect/DB2400Dialect.cs @@ -1,4 +1,6 @@ -using NHibernate.Cfg; +using System; +using System.Data.Common; +using NHibernate.Dialect.Schema; using NHibernate.SqlCommand; namespace NHibernate.Dialect @@ -23,7 +25,13 @@ public class DB2400Dialect : DB2Dialect { public DB2400Dialect() { - DefaultProperties[Environment.ConnectionDriver] = "NHibernate.Driver.DB2400Driver"; + DefaultProperties[Cfg.Environment.ConnectionDriver] = "NHibernate.Driver.DB2400Driver"; + } + + public override IDataBaseSchema GetDataBaseSchema(DbConnection connection) + { + // The DB2 implementation is not valid for DB2400. + throw new NotSupportedException(); } public override bool SupportsSequences @@ -61,4 +69,4 @@ public override bool SupportsVariableLimit get { return false; } } } -} \ No newline at end of file +} From 6d47db4ab4f117c40ebc8fb0d2332d30a9cfab87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:18:38 +0100 Subject: [PATCH 052/128] Release 5.3.20 (#3454) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 6cad2a32da7..2bc8d025dcf 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.3 - 19 + 20 diff --git a/releasenotes.txt b/releasenotes.txt index c7317d2b4f6..732c2ca7df4 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,20 @@ -Build 5.3.19 +Build 5.3.20 +============================= + +Release notes - NHibernate - Version 5.3.20 + +2 issues were resolved in this release. + +** Bug + + * #3438 DB2/400: ArgumentException Column 'SQL_TYPE_NAME' does not belong to table DataTypes + +** Task + + * #3454 Release 5.3.20 + + +Build 5.3.19 ============================= Release notes - NHibernate - Version 5.3.19 From 37f80d9cd1382a05bb8e65ef6c5e1a85b5f1e3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:35:26 +0100 Subject: [PATCH 053/128] Migrate appveyor build to MySql 8 (#3453) Co-authored-by: Roman Artiukhin --- appveyor.yml | 4 ++-- src/NHibernate.Test/Async/Linq/MethodCallTests.cs | 8 +++++++- src/NHibernate.Test/Extralazy/UserGroup.hbm.xml | 2 +- src/NHibernate.Test/Linq/MethodCallTests.cs | 8 +++++++- .../NHSpecificTest/NH2113/Mappings.hbm.xml | 2 +- .../NHSpecificTest/NH2907/Mappings.hbm.xml | 4 ++-- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 7 files changed, 21 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index eb6fc4b2fc9..c9703d631ab 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,10 +39,10 @@ before_test: Pop-Location } 'MySQL' { - Start-Service 'MySQL57' + Start-Service 'MySQL80' # Create nhibernate database (not handled by NHibernate.TestDatabaseSetup.dll) $env:MYSQL_PWD = 'Password12!' - & 'C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql' -e 'CREATE DATABASE nhibernate CHARACTER SET utf8 COLLATE utf8_general_ci;' --user=root + & 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql' -e 'CREATE DATABASE nhibernate CHARACTER SET utf8 COLLATE utf8_general_ci;' --user=root } 'Odbc' { Start-Service 'MSSQL$SQL2017' } 'PostgreSQL' { diff --git a/src/NHibernate.Test/Async/Linq/MethodCallTests.cs b/src/NHibernate.Test/Async/Linq/MethodCallTests.cs index b3ba92bef4f..621aed6d57c 100644 --- a/src/NHibernate.Test/Async/Linq/MethodCallTests.cs +++ b/src/NHibernate.Test/Async/Linq/MethodCallTests.cs @@ -59,6 +59,7 @@ public async Task CanExecuteCountWithOrderByArgumentsAsync() public async Task CanSelectPropertiesIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Name, u.InvalidLoginAttempts}) .FirstAsync()); @@ -71,6 +72,7 @@ public async Task CanSelectPropertiesIntoObjectArrayAsync() public async Task CanSelectComponentsIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Component, u.Component.OtherComponent}) .FirstAsync()); @@ -106,6 +108,7 @@ public async Task CanSelectConstantsIntoObjectArrayAsync() const string name = "Julian"; var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, pi, name, DateTime.MinValue}) .FirstAsync()); @@ -119,6 +122,7 @@ public async Task CanSelectConstantsIntoObjectArrayAsync() public async Task CanSelectPropertiesFromAssociationsIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Role.Name, u.Role.Entity.Output}) .FirstAsync()); @@ -131,6 +135,7 @@ public async Task CanSelectPropertiesFromAssociationsIntoObjectArrayAsync() public async Task CanSelectPropertiesIntoObjectArrayInPropertyAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new object[] { u.Id, u.Name, new object[u.Id] } }) .FirstAsync()); @@ -144,6 +149,7 @@ public async Task CanSelectPropertiesIntoObjectArrayInPropertyAsync() public async Task CanSelectPropertiesIntoPropertyListInPropertyAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new List { u.Id, u.Name, new object[u.Id] } }) .FirstAsync()); @@ -156,7 +162,7 @@ public async Task CanSelectPropertiesIntoPropertyListInPropertyAsync() [Test, Description("NH-2744")] public async Task CanSelectPropertiesIntoNestedObjectArraysAsync() { - var query = db.Users.Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); + var query = db.Users.OrderBy(u => u.Id).Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); var result = await (query.FirstAsync()); Assert.That(result.Length, Is.EqualTo(2)); diff --git a/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml b/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml index 2dd3fb6433d..0bd06b06d9e 100644 --- a/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml +++ b/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml @@ -4,7 +4,7 @@ assembly="NHibernate.Test" namespace="NHibernate.Test.Extralazy"> - + diff --git a/src/NHibernate.Test/Linq/MethodCallTests.cs b/src/NHibernate.Test/Linq/MethodCallTests.cs index c330b0944da..05abb79c0af 100644 --- a/src/NHibernate.Test/Linq/MethodCallTests.cs +++ b/src/NHibernate.Test/Linq/MethodCallTests.cs @@ -47,6 +47,7 @@ public void CanExecuteCountWithOrderByArguments() public void CanSelectPropertiesIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Name, u.InvalidLoginAttempts}) .First(); @@ -59,6 +60,7 @@ public void CanSelectPropertiesIntoObjectArray() public void CanSelectComponentsIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Component, u.Component.OtherComponent}) .First(); @@ -94,6 +96,7 @@ public void CanSelectConstantsIntoObjectArray() const string name = "Julian"; var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, pi, name, DateTime.MinValue}) .First(); @@ -107,6 +110,7 @@ public void CanSelectConstantsIntoObjectArray() public void CanSelectPropertiesFromAssociationsIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Role.Name, u.Role.Entity.Output}) .First(); @@ -119,6 +123,7 @@ public void CanSelectPropertiesFromAssociationsIntoObjectArray() public void CanSelectPropertiesIntoObjectArrayInProperty() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new object[] { u.Id, u.Name, new object[u.Id] } }) .First(); @@ -132,6 +137,7 @@ public void CanSelectPropertiesIntoObjectArrayInProperty() public void CanSelectPropertiesIntoPropertyListInProperty() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new List { u.Id, u.Name, new object[u.Id] } }) .First(); @@ -144,7 +150,7 @@ public void CanSelectPropertiesIntoPropertyListInProperty() [Test, Description("NH-2744")] public void CanSelectPropertiesIntoNestedObjectArrays() { - var query = db.Users.Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); + var query = db.Users.OrderBy(u => u.Id).Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); var result = query.First(); Assert.That(result.Length, Is.EqualTo(2)); diff --git a/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml index 64151c2d8bc..d5e799d7c91 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml @@ -15,7 +15,7 @@ - + diff --git a/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml index bb35dc0ba6a..95c5fdeec3d 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml @@ -12,11 +12,11 @@ - + - \ No newline at end of file + diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 80b7b5f6b24..e5e553f5b30 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -67,7 +67,7 @@ - + From 9613ffed1293c67d8927df5b1aa5022ee54300d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:36:55 +0100 Subject: [PATCH 054/128] Release 5.4.7 (#3459) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 7fd65db2f30..b36961fc58a 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.4 - 6 + 7 9.0 diff --git a/releasenotes.txt b/releasenotes.txt index e08c3b4eb23..f9fbf217f26 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,18 @@ -Build 5.4.6 +Build 5.4.7 +============================= + +Release notes - NHibernate - Version 5.4.7 + +3 issues were resolved in this release. + +** Task + + * #3459 Release 5.4.7 + * #3458 Merge 5.3.20 into 5.4.x + * #3453 Migrate appveyor build to MySql 8 + + +Build 5.4.6 ============================= Release notes - NHibernate - Version 5.4.6 From 1a960b0d0d01efb6984cc7fce9995e7b217fe75c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Dec 2023 11:36:28 +1000 Subject: [PATCH 055/128] Update NUnit to v3.14.0 (#3440) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../NHibernate.Test.VisualBasic.vbproj | 4 ++-- src/NHibernate.Test/NHibernate.Test.csproj | 4 ++-- .../NHibernate.TestDatabaseSetup.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index b21426b8b58..af019d9d1e5 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -27,11 +27,11 @@ - + - + diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index eba67c4aadd..91c13c43b92 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -68,7 +68,7 @@ - + @@ -92,7 +92,7 @@ - + diff --git a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj index 1eab7c9ff7b..60d56bb7401 100644 --- a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj +++ b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj @@ -15,11 +15,11 @@ - + - + From 6933bf0fabce38c3b8a96f73724e20e23d66ba82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:12:58 +0100 Subject: [PATCH 056/128] Release 5.5.0 (#3446) Co-authored-by: Alex Zaytsev Co-authored-by: Evgeny Akhtimirov --- build-common/NHibernate.props | 2 +- releasenotes.txt | 92 ++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 5575d231ce4..ebcef0dafce 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.5 0 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index f9fbf217f26..58536eebaa0 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,94 @@ -Build 5.4.7 +Build 5.5.0 +============================= + +Release notes - NHibernate - Version 5.5.0 + + ##### Possible Breaking Changes ##### + * `Object.Finalize` is no more proxified when the entity base class has a destructor. See #3205. + * Default not-found behavior now works correctly on many-to-many Criteria fetch. It now throws + ObjectNotFoundException exception for not found records. See #2687. + +62 issues were resolved in this release. + +** Bug + + * #3413 Downgrade dependency System.Data.SQLite.Core 1.0.118 -> 1.0.117 + * #3406 Fix orphan removal for detached one-to-one + * #3392 Partial fix fetching lazy property after Select in Linq + * #3360 Incorrect parameter length for char types in MicrosoftDataSqlClientDriver + * #3334 Exception executing HQL query with uncorrelated left joins in subselect + * #3327 HqlParser does not correctly negate EXISTS-nodes below an AND/OR + * #3325 Cascading orphan delete may not work on versioned entity + * #3311 NamedQuery ignores and any other + * #3264 Fix collection filter on subclass columns + * #3256 Invalid SQL is generated for string Enum used in conditional LINQ + * #3205 `Object.Finalize` should not be proxiable + * #2687 Use table group joins for many-to-many in Criteria and Entity loaders + * #1267 NH-3047 - Lazy=no-proxy ignores join fetch + +** New Feature + + * #3242 Linq: add enum Equals and object Equals support + * #3165 Add support for Firebird 4 + * #829 NH-3365 - Support for HasFlag method for enums with Flags attribute applied + +** Improvement + + * #3429 Explicit how to use advanced Redis strategies + * #3410 Remove redundant collection BeforeAssemble call from query cache + * #3398 Do not store mapping field in Configuration + * #3396 Get rid of select queries for each ManyToMany not found ignored element in Criteria and lazy loading + * #3395 Remove ConstantConverter + * #3394 Get rid of select queries for each ManyToMany not found ignored element in hql + * #3390 Enable Not node handling in HqlParser.NegateNode + * #3384 Improve path rule handling with reserved words in Hql.g + * #3377 Move HqlToken.PossibleId to HqlParser.IsPossibleId method and remove castings + * #3374 Simplify aggregateDistinctAll rule in Hql.g + * #3373 Refactor sequential select related members in AbstractEntityPersister + * #3341 Apply fromFragment processing only when required in ProcessDynamicFilterParameters + * #3340 SqlString.Trim should return the same instance for not modified string + * #3253 Do not throw for unknown type in hql case node + * #3230 Add cached boxed boolean values to BooleanType + * #3209 Allow custom query loader + +** Task + + * #3460 Merge 5.4.7 in master + * #3445 Release 5.5.0 + * #3440 Update NUnit to v3.14.0 + * #3423 Update actions/checkout action to v4 + * #3420 Merge 5.4.6 in master + * #3411 Remove ISessionFactoryImplementor parameter from TableGroupJoinHelper + * #3409 Merge 5.4.5 in master + * #3387 Merge 5.4.4 in master + * #3379 Remove NHibernate.Example.Web project + * #3362 Update dependency NUnit3TestAdapter to v4.5.0 + * #3361 Update dependency NUnit.Console to v3.16.3 + * #3353 Migrate renovate config + * #3351 Merge 5.4.3 in master + * #3284 Update NHibernate.Caches to v5.9.0 + * #3283 Update dependency NSubstitute to v5 + * #3280 Add tests for Microsoft.Data.SqlClient driver + * #3275 Migrate dev packages to Cloudsmith + * #3241 Exclude generated files from Deepsource analisys + * #3236 Add MySQL8Dialect and MySQL8InnoDBDialect + * #3223 Simplify GitHub Actions Tests DB initialization + * #3206 Update actions/setup-dotnet action to v3 + * #3202 Update dependency Npgsql to v7 + * #3129 [Security] Update Oracle.ManagedDataAccess + * #3122 Update dependency FirebirdSql.Data.FirebirdClient to v9 + * #3102 Update dependency Microsoft.Data.SqlClient to v3.1.3 + * #3099 [Security] Update dependency System.Linq.Dynamic.Core to v1.3.3 + * #3098 Update dependency System.Data.SQLite.Core to v1.0.118 + * #3092 Update dependency Microsoft.AspNetCore.OData to v7.7.0 + * #3088 Update NUnit to v3.13.3 + +** Tests + + * #3412 Revive hql ParsingFixture + + +Build 5.4.7 ============================= Release notes - NHibernate - Version 5.4.7 From 07c367fb859086970737c35f24fe66c089a034e2 Mon Sep 17 00:00:00 2001 From: hieucckha Date: Mon, 25 Dec 2023 04:00:36 +0700 Subject: [PATCH 057/128] Remove duplicate entry in dialects documentation (#3464) --- doc/reference/modules/configuration.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/reference/modules/configuration.xml b/doc/reference/modules/configuration.xml index 15656f556c1..dd0c4bd6a63 100644 --- a/doc/reference/modules/configuration.xml +++ b/doc/reference/modules/configuration.xml @@ -1515,12 +1515,6 @@ in the parameter binding. NHibernate.Dialect.PostgreSQLDialect - - PostgreSQL - NHibernate.Dialect.PostgreSQLDialect - - - PostgreSQL 8.1 NHibernate.Dialect.PostgreSQL81Dialect From 6fc008a41288a1846469fc8bb952b5a4a217cfb4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:13:06 +0100 Subject: [PATCH 058/128] Update dependency NSubstitute to v5.1.0 (#3477) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 91c13c43b92..d9e03d0df6b 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -67,7 +67,7 @@ - + From e444856770894f52f990326ca0342d5a5785ce6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:44:53 +0100 Subject: [PATCH 059/128] Adjust the doc about flush on commit (#3475) --- doc/reference/modules/manipulating_data.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/reference/modules/manipulating_data.xml b/doc/reference/modules/manipulating_data.xml index c65f9fe6ffe..c57952af1f9 100644 --- a/doc/reference/modules/manipulating_data.xml +++ b/doc/reference/modules/manipulating_data.xml @@ -838,9 +838,11 @@ sess.Lock(pk, LockMode.Upgrade);]]> It is possible to change the default behavior so that flush occurs less frequently. The FlushMode class defines three different modes: only flush at commit time (and only when the NHibernate ITransaction - API is used, or inside a transaction scope), flush automatically using the explained - routine (will only work inside an explicit NHibernate ITransaction or - inside a transaction scope), or never flush unless + API is used, or inside a transaction scope with a legacy option enabled - see + ), flush automatically using the explained + routine (will only work inside an explicit NHibernate ITransaction, or + inside a transaction scope with limitations for flushes on commit - see + ), or never flush unless Flush() is called explicitly. The last mode is useful for long running units of work, where an ISession is kept open and disconnected for a long time (see ). From 8aae0b773f07e93b17d98f562f9203d4147042b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:47:04 +0100 Subject: [PATCH 060/128] Do not append from element when already in from (#3476) --- .../Async/NHSpecificTest/GH3465/Fixture.cs | 31 +++++++++++++++++++ .../NHSpecificTest/GH3465/Entities.cs | 20 ++++++++++++ .../NHSpecificTest/GH3465/Fixture.cs | 20 ++++++++++++ .../NHSpecificTest/GH3465/Mappings.hbm.xml | 18 +++++++++++ .../Hql/Ast/ANTLR/Tree/FromElement.cs | 2 +- 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs new file mode 100644 index 00000000000..8d4b62bb325 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [Test] + public void ThetaJoinSubQueryAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var query = session.CreateQuery("select e.Id from EntityA e where exists (from e.Children b, EntityC c)"); + Assert.DoesNotThrowAsync(() => query.ListAsync()); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs new file mode 100644 index 00000000000..3a325ed9ba8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + class EntityA + { + public virtual Guid Id { get; set; } + public virtual ISet Children { get; set; } + } + class EntityB + { + public virtual Guid Id { get; set; } + public virtual EntityA Parent { get; set; } + } + class EntityC + { + public virtual Guid Id { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs new file mode 100644 index 00000000000..e51af1211d9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs @@ -0,0 +1,20 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void ThetaJoinSubQuery() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var query = session.CreateQuery("select e.Id from EntityA e where exists (from e.Children b, EntityC c)"); + Assert.DoesNotThrow(() => query.List()); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml new file mode 100644 index 00000000000..b89c139fa29 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index a22c13e84ff..ade63aaa929 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -716,7 +716,7 @@ public void SetOrigin(FromElement origin, bool manyToMany) JoinSequence.SetUseThetaStyle(true); } } - else + else if (Walker.CurrentClauseType != HqlSqlWalker.FROM) { FromClause.AppendFromElement(this); } From c1c8627ce81ec7ba623678bae0e1be17f74ff8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:52:28 +0100 Subject: [PATCH 061/128] Enable dev builds for v5.5.1 --- build-common/NHibernate.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index ebcef0dafce..11300e597e8 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,9 +3,9 @@ 5.5 - 0 + 1 - + dev 9.0 $(NhVersion).$(VersionPatch) From 04cec6dbcae7e0f724ef34b0462f4191cac479e0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 20:37:12 +0100 Subject: [PATCH 062/128] Update actions/setup-dotnet action to v4 (#3479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- .github/workflows/GenerateAsyncCode.yml | 2 +- .github/workflows/NetCoreTests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/GenerateAsyncCode.yml b/.github/workflows/GenerateAsyncCode.yml index 07ede3704e9..e879a670073 100644 --- a/.github/workflows/GenerateAsyncCode.yml +++ b/.github/workflows/GenerateAsyncCode.yml @@ -19,7 +19,7 @@ jobs: token: ${{ secrets.NHIBERNATE_BOT_TOKEN }} - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 6.0.x diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index 9cf09a1671d..28ab82cc595 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -49,7 +49,7 @@ jobs: run: ${{matrix.DB_INIT}} - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 6.0.x From 0978f4cabb0b41611d7927939e368023acfc42fe Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sun, 4 Feb 2024 19:38:30 +1000 Subject: [PATCH 063/128] Fix null reference exception when running tests with Npgsql 8 (#3480) --- .../PostgresExceptionConverterExample.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs b/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs index e4142c32f7f..ee794f0b9de 100644 --- a/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs +++ b/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs @@ -1,6 +1,6 @@ using System; -using System.Data.Common; using NHibernate.Exceptions; +using Npgsql; namespace NHibernate.Test.ExceptionsTest { @@ -10,23 +10,23 @@ public class PostgresExceptionConverterExample : ISQLExceptionConverter public Exception Convert(AdoExceptionContextInfo exInfo) { - var sqle = ADOExceptionHelper.ExtractDbException(exInfo.SqlException) as DbException; - if (sqle != null) + if (ADOExceptionHelper.ExtractDbException(exInfo.SqlException) is PostgresException pge) { - string code = (string)sqle.GetType().GetProperty("Code").GetValue(sqle, null); - + string code = pge.SqlState; if (code == "23503") { - return new ConstraintViolationException(exInfo.Message, sqle.InnerException, exInfo.Sql, null); + return new ConstraintViolationException(exInfo.Message, pge.InnerException, exInfo.Sql, null); } + if (code == "42P01") { - return new SQLGrammarException(exInfo.Message, sqle.InnerException, exInfo.Sql); + return new SQLGrammarException(exInfo.Message, pge.InnerException, exInfo.Sql); } } + return SQLStateConverter.HandledNonSpecificException(exInfo.SqlException, exInfo.Message, exInfo.Sql); } #endregion } -} \ No newline at end of file +} From a958ff160ff83eb09ac89412bead86ed88507177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:17:06 +0100 Subject: [PATCH 064/128] Fix Clear forgetting the non lazy collections (#3482) --- .../Async/NHSpecificTest/GH3424/Fixture.cs | 60 +++++++++++++++++++ .../NHSpecificTest/GH3424/Entities.cs | 18 ++++++ .../NHSpecificTest/GH3424/Fixture.cs | 49 +++++++++++++++ .../NHSpecificTest/GH3424/Mappings.hbm.xml | 19 ++++++ .../Engine/StatefulPersistenceContext.cs | 1 + 5 files changed, 147 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs new file mode 100644 index 00000000000..ef60ff14aac --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// +// 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.Collections.Generic; +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var c1 = new Child { Name = "Rob" }; + session.Save(c1); + var e1 = new Entity { Name = "Bob", Children = new HashSet { c1 } }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete Child").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task QueryingAfterFutureThenClearAsync() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var futureBob = session.Query().Where(e => e.Name == "Bob").ToFutureValue(q => q.FirstOrDefault()); + var bob = await (futureBob.GetValueAsync()); + Assert.That(bob, Is.Not.Null); + session.Clear(); + + var allQuery = session.Query(); + Assert.That(() => allQuery.ToListAsync(), Has.Count.EqualTo(1)); + await (transaction.CommitAsync()); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs new file mode 100644 index 00000000000..e72fe68c43c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } + } + + class Child + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs new file mode 100644 index 00000000000..5c829ce5c2d --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var c1 = new Child { Name = "Rob" }; + session.Save(c1); + var e1 = new Entity { Name = "Bob", Children = new HashSet { c1 } }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete Child").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void QueryingAfterFutureThenClear() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var futureBob = session.Query().Where(e => e.Name == "Bob").ToFutureValue(q => q.FirstOrDefault()); + var bob = futureBob.Value; + Assert.That(bob, Is.Not.Null); + session.Clear(); + + var allQuery = session.Query(); + Assert.That(() => allQuery.ToList(), Has.Count.EqualTo(1)); + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml new file mode 100644 index 00000000000..e692e287c11 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate/Engine/StatefulPersistenceContext.cs b/src/NHibernate/Engine/StatefulPersistenceContext.cs index 7819a59989b..f912c9b8bdc 100644 --- a/src/NHibernate/Engine/StatefulPersistenceContext.cs +++ b/src/NHibernate/Engine/StatefulPersistenceContext.cs @@ -264,6 +264,7 @@ public void Clear() entityEntries.Clear(); entitySnapshotsByKey.Clear(); collectionsByKey.Clear(); + nonlazyCollections.Clear(); collectionEntries.Clear(); if (unownedCollections != null) { From e65ab36b5ca92aaf37acc6abed0c4185837c9340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 6 Feb 2024 13:07:35 +0100 Subject: [PATCH 065/128] Support an arbitrary length for CultureInfoType (#3481) --- doc/reference/modules/basic_mapping.xml | 3 +- .../TypesTest/AbstractDateTimeTypeFixture.cs | 12 +- .../Async/TypesTest/CultureInfoTypeFixture.cs | 105 ++++++++++++++++++ .../TypesTest/DateTimeOffsetTypeFixture.cs | 20 ++-- .../Async/TypesTest/DecimalTypeFixture.cs | 12 -- .../Async/TypesTest/EnumStringTypeFixture.cs | 8 -- .../TypesTest/GenericEnumStringTypeFixture.cs | 8 -- .../Async/TypesTest/StringTypeFixture.cs | 8 -- .../TypesTest/TimeAsTimeSpanTypeFixture.cs | 12 -- .../TypesTest/AbstractDateTimeTypeFixture.cs | 12 +- .../TypesTest/CultureInfoClass.cs | 12 ++ .../TypesTest/CultureInfoClass.hbm.xml | 9 ++ .../TypesTest/CultureInfoTypeFixture.cs | 102 +++++++++++++++++ .../TypesTest/DateTimeOffsetTypeFixture.cs | 20 ++-- .../TypesTest/DecimalTypeFixture.cs | 12 -- .../TypesTest/EnumStringTypeFixture.cs | 8 -- .../TypesTest/GenericEnumStringTypeFixture.cs | 8 -- .../TypesTest/StringTypeFixture.cs | 8 -- .../TypesTest/TimeAsTimeSpanTypeFixture.cs | 12 -- .../TypesTest/TypeFixtureBase.cs | 25 ++--- src/NHibernate/Type/CultureInfoType.cs | 8 +- src/NHibernate/Type/TypeFactory.cs | 9 +- 22 files changed, 274 insertions(+), 159 deletions(-) create mode 100644 src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs create mode 100644 src/NHibernate.Test/TypesTest/CultureInfoClass.cs create mode 100644 src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml create mode 100644 src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs diff --git a/doc/reference/modules/basic_mapping.xml b/doc/reference/modules/basic_mapping.xml index 122def3f62f..2056bbe27a4 100644 --- a/doc/reference/modules/basic_mapping.xml +++ b/doc/reference/modules/basic_mapping.xml @@ -3919,7 +3919,8 @@ CultureInfo System.Globalization.CultureInfo - DbType.String - 5 chars for culture + DbType.String - 5 chars for culture by default; + can be modified by the length mapping attribute. Default when no type attribute specified. diff --git a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs index 4588e8d1017..4307080f4cf 100644 --- a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs @@ -69,14 +69,10 @@ protected override void OnSetUp() protected override void OnTearDown() { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); - t.Commit(); - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); + t.Commit(); } protected override void DropSchema() diff --git a/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs new file mode 100644 index 00000000000..4ec37748718 --- /dev/null +++ b/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// +// 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.Globalization; +using NHibernate.Dialect; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.TypesTest +{ + using System.Threading.Tasks; + [TestFixture] + public class CultureInfoTypeFixtureAsync : TypeFixtureBase + { + protected override string TypeName => "CultureInfo"; + + [Test] + public async Task ReadWriteBasicCultureAsync() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US") }; + await (s.SaveAsync(entity)); + id = entity.Id; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture, Is.Not.Null); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("en-US")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US"))); + entity.BasicCulture = CultureInfo.GetCultureInfo("fr-BE"); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("fr-BE")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("fr-BE"))); + entity.BasicCulture = null; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture, Is.Null); + await (t.CommitAsync()); + } + } + + [Test] + public async Task ReadWriteExtendedCultureAsync() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { ExtendedCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + await (s.SaveAsync(entity)); + id = entity.Id; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.ExtendedCulture, Is.Not.Null); + // Under Windows, it is named en-US-posix, but en-US-POSIX under Linux. + Assert.That(entity.ExtendedCulture.Name, Is.EqualTo("en-US-posix").IgnoreCase); + Assert.That(entity.ExtendedCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US-posix"))); + await (t.CommitAsync()); + } + } + + [Test] + public async Task WriteTooLongCultureAsync() + { + if (Dialect is SQLiteDialect) + Assert.Ignore("SQLite has no length limited string type."); + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + await (s.SaveAsync(entity)); + Assert.That(t.Commit, Throws.Exception); + } + } +} diff --git a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs index 64e62c0e326..1c604513d85 100644 --- a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs @@ -69,18 +69,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeOffsetClass").ExecuteUpdate(); - t.Commit(); - } - } - protected override void DropSchema() { (Sfi.ConnectionProvider.Driver as ClientDriverWithParamsStats)?.CleanUp(); @@ -354,6 +342,14 @@ public class DateTimeOffsetTypeWithScaleFixtureAsync : DateTimeOffsetTypeFixture // The timestamp rounding in seeding does not account scale. protected override bool RevisionCheck => false; + protected override void OnTearDown() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete DateTimeOffsetClass").ExecuteUpdate(); + t.Commit(); + } + [Test] public async Task LowerDigitsAreIgnoredAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs index c4ab2a0c6f0..1917cbd0b4b 100644 --- a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs @@ -54,18 +54,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DecimalClass").ExecuteUpdate(); - t.Commit(); - } - } - [Test] public async Task ReadWriteAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs index 255951b0b7a..1733fd0bce8 100644 --- a/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs @@ -40,14 +40,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from EnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public async Task ReadFromLoadAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs index 699ef01850b..06aa32c1ab7 100644 --- a/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs @@ -42,14 +42,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from GenericEnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public async Task ReadFromLoadAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs index a7d74e58e4d..0808ca7e837 100644 --- a/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs @@ -26,14 +26,6 @@ protected override string TypeName get { return "String"; } } - protected override void OnTearDown() - { - using (var s = OpenSession()) - { - s.CreateQuery("delete from StringClass").ExecuteUpdate(); - } - } - [Test] public async Task InsertNullValueAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs index 134fdee1b32..f9c585d7956 100644 --- a/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs @@ -50,18 +50,6 @@ protected override string TypeName get { return "TimeAsTimeSpan"; } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var tx = s.BeginTransaction()) - { - s.CreateQuery("delete from TimeAsTimeSpanClass").ExecuteUpdate(); - tx.Commit(); - } - } - [Test] public async Task SavingAndRetrievingAsync() { diff --git a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs index 67b36a0d2cc..0d95535b947 100644 --- a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs @@ -57,14 +57,10 @@ protected override void OnSetUp() protected override void OnTearDown() { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); - t.Commit(); - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); + t.Commit(); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/CultureInfoClass.cs b/src/NHibernate.Test/TypesTest/CultureInfoClass.cs new file mode 100644 index 00000000000..601cf00fbda --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoClass.cs @@ -0,0 +1,12 @@ +using System; +using System.Globalization; + +namespace NHibernate.Test.TypesTest +{ + public class CultureInfoClass + { + public Guid Id { get; set; } + public CultureInfo BasicCulture { get; set; } + public CultureInfo ExtendedCulture { get; set; } + } +} diff --git a/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml b/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml new file mode 100644 index 00000000000..8472d89d7f0 --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs b/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs new file mode 100644 index 00000000000..d860c04ba1f --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs @@ -0,0 +1,102 @@ +using System; +using System.Globalization; +using NHibernate.Dialect; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.TypesTest +{ + [TestFixture] + public class CultureInfoTypeFixture : TypeFixtureBase + { + protected override string TypeName => "CultureInfo"; + + [Test] + public void ReadWriteBasicCulture() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US") }; + s.Save(entity); + id = entity.Id; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture, Is.Not.Null); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("en-US")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US"))); + entity.BasicCulture = CultureInfo.GetCultureInfo("fr-BE"); + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("fr-BE")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("fr-BE"))); + entity.BasicCulture = null; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture, Is.Null); + t.Commit(); + } + } + + [Test] + public void ReadWriteExtendedCulture() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { ExtendedCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + s.Save(entity); + id = entity.Id; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.ExtendedCulture, Is.Not.Null); + // Under Windows, it is named en-US-posix, but en-US-POSIX under Linux. + Assert.That(entity.ExtendedCulture.Name, Is.EqualTo("en-US-posix").IgnoreCase); + Assert.That(entity.ExtendedCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US-posix"))); + t.Commit(); + } + } + + [Test] + public void WriteTooLongCulture() + { + if (Dialect is SQLiteDialect) + Assert.Ignore("SQLite has no length limited string type."); + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + s.Save(entity); + Assert.That(t.Commit, Throws.Exception); + } + + [Test] + public void AutoDiscoverFromNetType() + { + // integration test to be 100% sure + var propertyType = Sfi.GetEntityPersister(typeof(CultureInfoClass).FullName).GetPropertyType(nameof(CultureInfoClass.BasicCulture)); + Assert.That(propertyType, Is.InstanceOf()); + } + } +} diff --git a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs index 0881a08e878..b38475b3a40 100644 --- a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs @@ -57,18 +57,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeOffsetClass").ExecuteUpdate(); - t.Commit(); - } - } - protected override void DropSchema() { (Sfi.ConnectionProvider.Driver as ClientDriverWithParamsStats)?.CleanUp(); @@ -382,6 +370,14 @@ public class DateTimeOffsetTypeWithScaleFixture : DateTimeOffsetTypeFixture // The timestamp rounding in seeding does not account scale. protected override bool RevisionCheck => false; + protected override void OnTearDown() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete DateTimeOffsetClass").ExecuteUpdate(); + t.Commit(); + } + [Test] public void LowerDigitsAreIgnored() { diff --git a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs index 72561fc7008..4f839a39df8 100644 --- a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs @@ -45,18 +45,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DecimalClass").ExecuteUpdate(); - t.Commit(); - } - } - /// /// Test that two decimal fields that are exactly equal are returned /// as Equal by the DecimalType. diff --git a/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs b/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs index ca3a07797df..9574983a65b 100644 --- a/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs @@ -29,14 +29,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from EnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public void ReadFromLoad() { diff --git a/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs b/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs index ea64fc18a2c..1ff4f62313a 100644 --- a/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs @@ -31,14 +31,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from GenericEnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public void ReadFromLoad() { diff --git a/src/NHibernate.Test/TypesTest/StringTypeFixture.cs b/src/NHibernate.Test/TypesTest/StringTypeFixture.cs index e544390e5ca..7a970476cfa 100644 --- a/src/NHibernate.Test/TypesTest/StringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/StringTypeFixture.cs @@ -14,14 +14,6 @@ protected override string TypeName get { return "String"; } } - protected override void OnTearDown() - { - using (var s = OpenSession()) - { - s.CreateQuery("delete from StringClass").ExecuteUpdate(); - } - } - [Test] public void InsertNullValue() { diff --git a/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs b/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs index 5c0e2c364f0..4684693f498 100644 --- a/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs @@ -38,18 +38,6 @@ protected override string TypeName get { return "TimeAsTimeSpan"; } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var tx = s.BeginTransaction()) - { - s.CreateQuery("delete from TimeAsTimeSpanClass").ExecuteUpdate(); - tx.Commit(); - } - } - [Test] public void PropertiesHasExpectedType() { diff --git a/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs b/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs index 048a3670b2d..6f83d6f8127 100644 --- a/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs +++ b/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections; - namespace NHibernate.Test.TypesTest { /// @@ -13,20 +10,16 @@ public abstract class TypeFixtureBase : TestCase { protected abstract string TypeName { get; } - protected override string MappingsAssembly - { - get { return "NHibernate.Test"; } - } + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { $"TypesTest.{TypeName}Class.hbm.xml" }; - protected override string[] Mappings + protected override void OnTearDown() { - get - { - return new string[] - { - String.Format("TypesTest.{0}Class.hbm.xml", TypeName) - }; - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery($"delete {TypeName}Class").ExecuteUpdate(); + t.Commit(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Type/CultureInfoType.cs b/src/NHibernate/Type/CultureInfoType.cs index 47daf666588..417e4b2ef89 100644 --- a/src/NHibernate/Type/CultureInfoType.cs +++ b/src/NHibernate/Type/CultureInfoType.cs @@ -8,12 +8,12 @@ namespace NHibernate.Type { /// - /// Maps a Property + /// Maps a Property /// to a column. /// /// /// CultureInfoType stores the culture name (not the Culture ID) of the - /// in the DB. + /// in the DB. /// [Serializable] public partial class CultureInfoType : ImmutableType, ILiteralType @@ -22,6 +22,10 @@ internal CultureInfoType() : base(new StringSqlType(5)) { } + internal CultureInfoType(StringSqlType sqlType) : base(sqlType) + { + } + /// public override object Get(DbDataReader rs, int index, ISessionImplementor session) { diff --git a/src/NHibernate/Type/TypeFactory.cs b/src/NHibernate/Type/TypeFactory.cs index 758353c48a4..0fd384d25c9 100644 --- a/src/NHibernate/Type/TypeFactory.cs +++ b/src/NHibernate/Type/TypeFactory.cs @@ -292,7 +292,9 @@ private static void RegisterDefaultNetTypes() RegisterType(typeof (Boolean), NHibernateUtil.Boolean, new[] { "boolean", "bool" }); RegisterType(typeof (Byte), NHibernateUtil.Byte, new[]{ "byte"}); RegisterType(typeof (Char), NHibernateUtil.Character, new[] {"character", "char"}); - RegisterType(typeof (CultureInfo), NHibernateUtil.CultureInfo, new[]{ "locale"}); + RegisterType(typeof (CultureInfo), NHibernateUtil.CultureInfo, new[] { "locale" }, + l => GetType(NHibernateUtil.CultureInfo, l, len => new CultureInfoType(SqlTypeFactory.GetString(len))), + false); RegisterType(typeof (DateTime), NHibernateUtil.DateTime, new[] { "datetime" }, s => GetType(NHibernateUtil.DateTime, s, scale => new DateTimeType(SqlTypeFactory.GetDateTime((byte)scale))), false); @@ -344,11 +346,10 @@ private static void RegisterDefaultNetTypes() } /// - /// Register other NO Default .NET type + /// Register types which are not a default for a .NET type. /// /// - /// These type will be used only when the "type" attribute was is specified in the mapping. - /// These are in here because needed to NO override default CLR types and be available in mappings + /// These types will be used only when the "type" attribute is specified in the mapping. /// private static void RegisterBuiltInTypes() { From 2742b573e49856e8b0c858aba38930a5e555a405 Mon Sep 17 00:00:00 2001 From: Ndiaye Pape ngagne Date: Tue, 6 Feb 2024 22:57:58 +0100 Subject: [PATCH 066/128] Test Case for Invalid SQL with property-ref on property using a formula (#3309) --- .../Async/NHSpecificTest/GH1313/Fixture.cs | 61 +++++++++++++++++++ .../NHSpecificTest/GH1313/Account.cs | 9 +++ .../NHSpecificTest/GH1313/Fixture.cs | 49 +++++++++++++++ .../NHSpecificTest/GH1313/HoldClose.cs | 11 ++++ .../NHSpecificTest/GH1313/Mappings.hbm.xml | 18 ++++++ 5 files changed, 148 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs new file mode 100644 index 00000000000..1a5d5f38c88 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var account = new Account { Id = 1, Name = "Account_1", OldAccountNumber = 1 }; + var order = new HoldClose + { + Account = account, + CloseDate = new DateTime(2023, 1, 1) + }; + + session.Save(account); + session.Save(order); + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + transaction.Commit(); + } + + [Test] + [Explicit("Not fixed yet")] + public async Task ManyToOneTargettingAFormulaAsync() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session.Query(); + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); + await (transaction.CommitAsync()); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs new file mode 100644 index 00000000000..55833dc3612 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + public class Account + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual int OldAccountNumber { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs new file mode 100644 index 00000000000..da097ba72d8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var account = new Account { Id = 1, Name = "Account_1", OldAccountNumber = 1 }; + var order = new HoldClose + { + Account = account, + CloseDate = new DateTime(2023, 1, 1) + }; + + session.Save(account); + session.Save(order); + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + transaction.Commit(); + } + + [Test] + [Explicit("Not fixed yet")] + public void ManyToOneTargettingAFormula() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session.Query(); + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs new file mode 100644 index 00000000000..007c768dbb9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs @@ -0,0 +1,11 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + public class HoldClose + { + public virtual int Id { get; set; } + public virtual Account Account { get; set; } + public virtual DateTime CloseDate { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml new file mode 100644 index 00000000000..04b321cd7f6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + convert(int,substring([Oldaccountnumber],3,8)) + + + + From cd2e8ea4be5337b60f607dd712e19c8085f1464f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:16:33 +0100 Subject: [PATCH 067/128] Fix implied commits for Oracle and MySQL (#3485) --- .../Async/NHSpecificTest/GH3474/Fixture.cs | 81 +++++++++++++++++++ .../NHSpecificTest/GH3474/Entities.cs | 30 +++++++ .../NHSpecificTest/GH3474/Fixture.cs | 69 ++++++++++++++++ .../NHSpecificTest/GH3474/Mappings.hbm.xml | 21 +++++ .../ANTLR/Exec/AbstractStatementExecutor.cs | 2 +- src/NHibernate/Dialect/Dialect.cs | 41 +++++----- src/NHibernate/Dialect/MySQLDialect.cs | 3 + src/NHibernate/Dialect/Oracle8iDialect.cs | 5 ++ .../ANTLR/Exec/AbstractStatementExecutor.cs | 2 +- 9 files changed, 233 insertions(+), 21 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs new file mode 100644 index 00000000000..6aacc68bcbc --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 }; + session.Save(e1); + + var e2 = new ChequePayment { Bank = "CA", Amount = 32 }; + session.Save(e2); + + var e3 = new CashPayment { Amount = 18.5m }; + session.Save(e3); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task PolymorphicUpdateShouldNotCommitAsync() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var payment = await (session.Query().FirstAsync()); + payment.Amount = 100; + await (session.FlushAsync()); + + await (session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdateAsync()); + + await (transaction.RollbackAsync()); + } + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + IPayment payment = await (session.Query().FirstAsync()); + Assert.That(payment.Amount, Is.EqualTo(50m)); + + payment = await (session.Query().FirstAsync()); + Assert.That(payment.Amount, Is.EqualTo(32m)); + + await (transaction.CommitAsync()); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs new file mode 100644 index 00000000000..d00828d29f2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs @@ -0,0 +1,30 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + public interface IPayment + { + public Guid Id { get; set; } + public decimal Amount { get; set; } + } + + public class CreditCardPayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + public virtual string CreditCardType { get; set; } + } + + public class CashPayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + } + + public class ChequePayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + public virtual string Bank { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs new file mode 100644 index 00000000000..fd76cad70f8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs @@ -0,0 +1,69 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 }; + session.Save(e1); + + var e2 = new ChequePayment { Bank = "CA", Amount = 32 }; + session.Save(e2); + + var e3 = new CashPayment { Amount = 18.5m }; + session.Save(e3); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void PolymorphicUpdateShouldNotCommit() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var payment = session.Query().First(); + payment.Amount = 100; + session.Flush(); + + session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdate(); + + transaction.Rollback(); + } + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + IPayment payment = session.Query().First(); + Assert.That(payment.Amount, Is.EqualTo(50m)); + + payment = session.Query().First(); + Assert.That(payment.Amount, Is.EqualTo(32m)); + + transaction.Commit(); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml new file mode 100644 index 00000000000..6ea3fc8c2b2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate/Async/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs b/src/NHibernate/Async/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs index 26e84fd0b65..0dac2ade9f0 100644 --- a/src/NHibernate/Async/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs +++ b/src/NHibernate/Async/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs @@ -162,7 +162,7 @@ public async Task DoWorkAsync(DbConnection connection, DbTransaction transaction { stmnt = connection.CreateCommand(); stmnt.Transaction = transaction; - stmnt.CommandText = "drop table " + persister.TemporaryIdTableName; + stmnt.CommandText = $"{session.Factory.Dialect.DropTemporaryTableString} {persister.TemporaryIdTableName}"; await (stmnt.ExecuteNonQueryAsync(cancellationToken)).ConfigureAwait(false); session.Factory.Settings.SqlStatementLogger.LogCommand(stmnt, FormatStyle.Ddl); } diff --git a/src/NHibernate/Dialect/Dialect.cs b/src/NHibernate/Dialect/Dialect.cs index 9a4db11880e..b917a708db2 100644 --- a/src/NHibernate/Dialect/Dialect.cs +++ b/src/NHibernate/Dialect/Dialect.cs @@ -717,28 +717,28 @@ public virtual string GenerateTemporaryTableName(string baseTableName) /// /// Does the dialect require that temporary table DDL statements occur in - /// isolation from other statements? This would be the case if the creation + /// isolation from other statements? This would be the case if the creation /// would cause any current transaction to get committed implicitly. - /// - /// see the result matrix above. + /// + /// See the result matrix in the remarks. /// - /// JDBC defines a standard way to query for this information via the - /// {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()} - /// method. However, that does not distinguish between temporary table - /// DDL and other forms of DDL; MySQL, for example, reports DDL causing a - /// transaction commit via its driver, even though that is not the case for - /// temporary table DDL. - ///

- /// Possible return values and their meanings:

    - ///
  • {@link Boolean#TRUE} - Unequivocally, perform the temporary table DDL in isolation.
  • - ///
  • {@link Boolean#FALSE} - Unequivocally, do not perform the temporary table DDL in isolation.
  • - ///
  • null - defer to the JDBC driver response in regards to {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}
  • - ///
+ /// Possible return values and their meanings: + /// + /// + /// + /// Unequivocally, perform the temporary table DDL in isolation. + /// + /// + /// + /// Unequivocally, do not perform the temporary table DDL in isolation. + /// + /// + /// + /// Defer to . + /// + /// ///
- public virtual bool? PerformTemporaryTableDDLInIsolation() - { - return null; - } + public virtual bool? PerformTemporaryTableDDLInIsolation() => null; /// Do we need to drop the temporary table after use? public virtual bool DropTemporaryTableAfterUse() @@ -2471,6 +2471,9 @@ public virtual string CreateTemporaryTableString get { return "create table"; } } + /// Command used to drop a temporary table. + public virtual string DropTemporaryTableString => "drop table"; + /// /// Get any fragments needing to be postfixed to the command for /// temporary table creation. diff --git a/src/NHibernate/Dialect/MySQLDialect.cs b/src/NHibernate/Dialect/MySQLDialect.cs index d7b4be07d63..09a5ba03072 100644 --- a/src/NHibernate/Dialect/MySQLDialect.cs +++ b/src/NHibernate/Dialect/MySQLDialect.cs @@ -451,6 +451,9 @@ public override string CreateTemporaryTableString get { return "create temporary table if not exists"; } } + /// + public override string DropTemporaryTableString => "drop temporary table"; + protected virtual void RegisterCastTypes() { // According to the MySql documentation (http://dev.mysql.com/doc/refman/4.1/en/cast-functions.html) diff --git a/src/NHibernate/Dialect/Oracle8iDialect.cs b/src/NHibernate/Dialect/Oracle8iDialect.cs index 9bbe3e7dfb9..2843db5e58f 100644 --- a/src/NHibernate/Dialect/Oracle8iDialect.cs +++ b/src/NHibernate/Dialect/Oracle8iDialect.cs @@ -532,6 +532,11 @@ public override string GenerateTemporaryTableName(String baseTableName) return name.Length > 30 ? name.Substring(1, (30) - (1)) : name; } + /// + /// Oracle does commit any pending transaction prior to executing any DDL, + /// included for temporary tables. + public override bool? PerformTemporaryTableDDLInIsolation() => true; + public override bool DropTemporaryTableAfterUse() { return false; diff --git a/src/NHibernate/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs b/src/NHibernate/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs index 9c2f86a4fd0..eb6a46f1265 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs @@ -298,7 +298,7 @@ public void DoWork(DbConnection connection, DbTransaction transaction) { stmnt = connection.CreateCommand(); stmnt.Transaction = transaction; - stmnt.CommandText = "drop table " + persister.TemporaryIdTableName; + stmnt.CommandText = $"{session.Factory.Dialect.DropTemporaryTableString} {persister.TemporaryIdTableName}"; stmnt.ExecuteNonQuery(); session.Factory.Settings.SqlStatementLogger.LogCommand(stmnt, FormatStyle.Ddl); } From 8b71b852f35649842be95e68d0931069011cfd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 8 Feb 2024 02:42:29 +0100 Subject: [PATCH 068/128] Modernize the test case example (#3484) --- .../Async/NHSpecificTest/GH0000/Fixture.cs | 54 ++++++++--------- .../NHSpecificTest/GH0000/FixtureByCode.cs | 60 +++++++++---------- .../NHSpecificTest/GH0000/Fixture.cs | 58 +++++++++--------- .../NHSpecificTest/GH0000/FixtureByCode.cs | 60 +++++++++---------- 4 files changed, 112 insertions(+), 120 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs index 29c4aabe5cc..40ebdcc36ba 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs @@ -20,47 +20,45 @@ public class FixtureAsync : BugTestCase { protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity {Name = "Bob"}; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - var e2 = new Entity {Name = "Sally"}; - session.Save(e2); + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - transaction.Commit(); - } + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public async Task YourTestNameAsync() { - using (var session = OpenSession()) - using (session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - } + await (transaction.CommitAsync()); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs index 073d534694a..0e4b4057d80 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs @@ -21,12 +21,12 @@ namespace NHibernate.Test.NHSpecificTest.GH0000 /// Fixture using 'by code' mappings /// /// - /// This fixture is identical to except the mapping is performed + /// This fixture is identical to except the mapping is performed /// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach /// if you prefer. /// [TestFixture] - public class ByCodeFixtureAsync : TestCaseMappingByCode + public class FixtureByCodeAsync : TestCaseMappingByCode { protected override HbmMapping GetMappings() { @@ -42,48 +42,46 @@ protected override HbmMapping GetMappings() protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity { Name = "Bob" }; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - var e2 = new Entity { Name = "Sally" }; - session.Save(e2); + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); - transaction.Commit(); - } + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHbernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public async Task YourTestNameAsync() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - await (transaction.CommitAsync()); - } + await (transaction.CommitAsync()); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs index 58c728c7028..a89c48bf64c 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs @@ -8,47 +8,45 @@ public class Fixture : BugTestCase { protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity {Name = "Bob"}; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - var e2 = new Entity {Name = "Sally"}; - session.Save(e2); + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - transaction.Commit(); - } + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); - - transaction.Commit(); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); } [Test] public void YourTestName() { - using (var session = OpenSession()) - using (session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; - - Assert.That(result.ToList(), Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + + transaction.Commit(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs index 2bc1953e095..a80b787db3d 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs @@ -9,12 +9,12 @@ namespace NHibernate.Test.NHSpecificTest.GH0000 /// Fixture using 'by code' mappings ///
/// - /// This fixture is identical to except the mapping is performed + /// This fixture is identical to except the mapping is performed /// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach /// if you prefer. /// [TestFixture] - public class ByCodeFixture : TestCaseMappingByCode + public class FixtureByCode : TestCaseMappingByCode { protected override HbmMapping GetMappings() { @@ -30,48 +30,46 @@ protected override HbmMapping GetMappings() protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity { Name = "Bob" }; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - var e2 = new Entity { Name = "Sally" }; - session.Save(e2); + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); - transaction.Commit(); - } + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHbernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public void YourTestName() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); - Assert.That(result.ToList(), Has.Count.EqualTo(1)); - transaction.Commit(); - } + transaction.Commit(); } } } From c9de443cce6059b054fbd305fee993710f0a1d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:44:14 +0100 Subject: [PATCH 069/128] Enable dev builds for 5.6 --- build-common/NHibernate.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index ebcef0dafce..bbea7b75c22 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -2,10 +2,10 @@ - 5.5 + 5.6 0 - + dev 9.0 $(NhVersion).$(VersionPatch) From ff7d4b5dccf578a30e868260c11a73dd61ef6218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sat, 10 Feb 2024 00:18:13 +0100 Subject: [PATCH 070/128] Fix a failing test for SQL Server CE (#3488) --- src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs | 6 ++++++ src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs index 6aacc68bcbc..63c89db566d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs @@ -50,6 +50,12 @@ protected override void OnTearDown() transaction.Commit(); } + protected override bool AppliesTo(Dialect.Dialect dialect) + { + // Polymorphic updates require support of temp tables. + return Dialect.SupportsTemporaryTables; + } + [Test] public async Task PolymorphicUpdateShouldNotCommitAsync() { diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs index fd76cad70f8..65c7b8a6e19 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs @@ -38,6 +38,12 @@ protected override void OnTearDown() transaction.Commit(); } + protected override bool AppliesTo(Dialect.Dialect dialect) + { + // Polymorphic updates require support of temp tables. + return Dialect.SupportsTemporaryTables; + } + [Test] public void PolymorphicUpdateShouldNotCommit() { From 567511066cfd5870c47d54fb4b4664948295a9c7 Mon Sep 17 00:00:00 2001 From: Evgeny Akhtimirov Date: Tue, 13 Feb 2024 15:22:02 -0500 Subject: [PATCH 071/128] Allocation free iterators for LinkedHashMap (#3487) --- ...ashMapFixture.cs => LinkHashMapFixture.cs} | 41 +- src/NHibernate.Test/NHibernate.Test.csproj | 1 + .../UtilityTest/LinkHashMapFixture.cs | 477 +++++++++++++ .../UtilityTest/LinkedHashMapFixture.cs | 415 ------------ .../Async/Engine/BatchFetchQueue.cs | 2 +- .../Cfg/XmlHbmBinding/NamedQueryBinder.cs | 5 +- src/NHibernate/Engine/BatchFetchQueue.cs | 6 +- src/NHibernate/Mapping/Table.cs | 2 +- src/NHibernate/SqlCommand/CaseFragment.cs | 4 +- src/NHibernate/SqlCommand/SqlInsertBuilder.cs | 2 +- src/NHibernate/SqlCommand/SqlUpdateBuilder.cs | 2 +- src/NHibernate/Util/CollectionHelper.cs | 4 +- src/NHibernate/Util/LinkHashMap.cs | 624 ++++++++++++++++++ src/NHibernate/Util/LinkedHashMap.cs | 2 + 14 files changed, 1141 insertions(+), 446 deletions(-) rename src/NHibernate.Test/Async/UtilityTest/{LinkedHashMapFixture.cs => LinkHashMapFixture.cs} (73%) create mode 100644 src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs delete mode 100644 src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs create mode 100644 src/NHibernate/Util/LinkHashMap.cs diff --git a/src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs b/src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs similarity index 73% rename from src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs rename to src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs index ff1e2011664..99fcfedf320 100644 --- a/src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs +++ b/src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs @@ -9,6 +9,7 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; @@ -19,17 +20,21 @@ namespace NHibernate.Test.UtilityTest { using System.Threading.Tasks; [TestFixture] - public class LinkedHashMapFixtureAsync + public class LinkHashMapFixtureAsync { - private static readonly Player[] players = { - new Player("12341", "Boeta Dippenaar"), new Player("23432", "Gary Kirsten"), - new Player("23411", "Graeme Smith"), new Player("55221", "Jonty Rhodes"), - new Player("61234", "Monde Zondeki"), new Player("23415", "Paul Adams") - }; + private static readonly Player[] players = + { + new Player("12341", "Boeta Dippenaar"), + new Player("23432", "Gary Kirsten"), + new Player("23411", "Graeme Smith"), + new Player("55221", "Jonty Rhodes"), + new Player("61234", "Monde Zondeki"), + new Player("23415", "Paul Adams") + }; private static void Fill(IDictionary lhm) { - foreach (Player player in players) + foreach (var player in players) lhm.Add(player.Id, player); } @@ -37,11 +42,11 @@ private static void Fill(IDictionary lhm) public async Task ShowDiffAsync() { IDictionary dict = new Dictionary(); - IDictionary lhm = new LinkedHashMap(); + IDictionary lhm = new LinkHashMap(); Fill(dict); Fill(lhm); // Override the first element - Player o = new Player("12341", "Ovirride"); + var o = new Player("12341", "Override"); dict[o.Id] = o; lhm[o.Id] = o; await (Console.Out.WriteLineAsync("Dictionary order:")); @@ -49,7 +54,7 @@ public async Task ShowDiffAsync() { Console.Out.WriteLine("Key->{0}", pair.Key); } - await (Console.Out.WriteLineAsync("LinkedHashMap order:")); + await (Console.Out.WriteLineAsync("LinkHashMap order:")); foreach (KeyValuePair pair in lhm) { Console.Out.WriteLine("Key->{0}", pair.Key); @@ -65,18 +70,18 @@ public async Task PerformanceAsync() int numOfEntries = Int16.MaxValue; - long[] dictPopulateTicks = new long[numOfRuns]; - long[] dictItemTicks = new long[numOfRuns]; + var dictPopulateTicks = new long[numOfRuns]; + var dictItemTicks = new long[numOfRuns]; - long[] linkPopulateTicks = new long[numOfRuns]; - long[] linkItemTicks = new long[numOfRuns]; + var linkPopulateTicks = new long[numOfRuns]; + var linkItemTicks = new long[numOfRuns]; - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) { string key; object value; IDictionary dictionary = new Dictionary(); - IDictionary linked = new LinkedHashMap(); + IDictionary linked = new LinkHashMap(); long dictStart = DateTime.Now.Ticks; @@ -118,12 +123,12 @@ public async Task PerformanceAsync() linked.Clear(); } - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) { decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); - string message = string.Format("LinkedHashMap vs Dictionary (Run-{0}) :",runIndex+1); + string message = string.Format("LinkHashMap vs Dictionary (Run-{0}) :",runIndex+1); message += "\n POPULATE:"; message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index d9e03d0df6b..5a3b08cdfc5 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -55,6 +55,7 @@ UtilityTest\AsyncReaderWriterLock.cs + UtilityTest\SetSnapShot.cs diff --git a/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs b/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs new file mode 100644 index 00000000000..30002757113 --- /dev/null +++ b/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs @@ -0,0 +1,477 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using NHibernate.Util; +using NUnit.Framework; + +namespace NHibernate.Test.UtilityTest +{ + [TestFixture] + public class LinkHashMapFixture + { + private static readonly Player[] players = + { + new Player("12341", "Boeta Dippenaar"), + new Player("23432", "Gary Kirsten"), + new Player("23411", "Graeme Smith"), + new Player("55221", "Jonty Rhodes"), + new Player("61234", "Monde Zondeki"), + new Player("23415", "Paul Adams") + }; + + private static void Fill(IDictionary lhm) + { + foreach (var player in players) + lhm.Add(player.Id, player); + } + + [Test] + public void Add() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + lhm.Add("55555", new Player("55555", "Monde Zondeki")); + + Assert.That(lhm.Count, Is.EqualTo(7)); + } + + [Test] + public void LastKeyLastValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.LastKey, Is.EqualTo(players[players.Length - 1].Id)); + Assert.That(lhm.LastValue, Is.EqualTo(players[players.Length - 1])); + + // override + var antWithSameId = new Player("12341", "Another"); + lhm[antWithSameId.Id] = antWithSameId; + Assert.That(lhm.LastKey, Is.EqualTo(antWithSameId.Id)); + Assert.That(lhm.LastValue, Is.EqualTo(antWithSameId)); + } + + [Test] + public void FirstKeyFirstValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.FirstKey, Is.EqualTo(players[0].Id)); + Assert.That(lhm.FirstValue, Is.EqualTo(players[0])); + + // override First + var antWithSameId = new Player("12341", "Another"); + lhm[antWithSameId.Id] = antWithSameId; + Assert.That(lhm.FirstKey, Is.EqualTo(players[1].Id)); + Assert.That(lhm.FirstValue, Is.EqualTo(players[1])); + } + + [Test] + public void Clear() + { + IDictionary lhm = new LinkHashMap(); + var p = new Player("78945", "Someone"); + lhm[p.Id] = p; + + lhm.Clear(); + Assert.That(lhm, Is.Empty); + + foreach (KeyValuePair pair in lhm) + Assert.Fail("Should not be any entries but found Key = " + pair.Key + " and Value = " + pair.Value); + } + + [Test] + public void Contains() + { + var lhm = new LinkHashMap(); + Fill(lhm); + + Assert.That(lhm.Contains("12341"), Is.True); + Assert.That(lhm.Contains("55555"), Is.False); + } + + [Test] + public void GetEnumerator() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + int index = 0; + foreach (KeyValuePair pair in lhm) + { + Assert.That(pair.Key, Is.EqualTo(players[index].Id)); + Assert.That(pair.Value, Is.EqualTo(players[index])); + index++; + } + + Assert.That(index, Is.EqualTo(6)); + } + + [Test] + public void GetEnumeratorEmpty() + { + IDictionary lhm = new LinkHashMap(); + Assert.That(lhm, Is.Empty); + + int entries = 0; + foreach (KeyValuePair pair in lhm) + entries++; + foreach (string s in lhm.Keys) + entries++; + foreach (Player value in lhm.Values) + entries++; + + Assert.That(entries, Is.Zero, "should not have any entries in the enumerators"); + } + + [Test] + public void GetEnumeratorModifyExceptionFromAdd() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm["78945"] = new Player("78945", "Someone"); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void GetEnumeratorModifyExceptionFromRemove() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm.Remove(pair.Key); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void GetEnumeratorModifyExceptionFromUpdate() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm["123"] = new Player("123", "aaaaaaa"); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void EnumeratorInstanceShouldNotBeNonGenericIEnumerator() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType, Is.Not.EqualTo(typeof(IEnumerator))); + } + + [Test] + public void EnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void KeysEnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.Keys.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void ValuesEnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.Values.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void Remove() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + + // remove an item that exists + bool removed = lhm.Remove("23411"); + Assert.That(removed, Is.True); + Assert.That(lhm.Count, Is.EqualTo(5)); + + // try to remove an item that does not exist + removed = lhm.Remove("65432"); + Assert.That(removed, Is.False); + Assert.That(lhm.Count, Is.EqualTo(5)); + } + + [Test] + public void ContainsValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.ContainsValue(new Player("55221", "Jonty Rhodes")), Is.True); + Assert.That(lhm.ContainsValue(new Player("55221", "SameKeyDiffName")), Is.False); + } + + [Test] + public void CopyTo() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var destArray = new KeyValuePair[lhm.Count + 1]; + destArray[0] = new KeyValuePair("999", new Player("999", "The number nine")); + lhm.CopyTo(destArray, 1); + + for (var i = 1; i < destArray.Length; i++) + { + Assert.That(destArray[i].Key, Is.EqualTo(players[i - 1].Id)); + Assert.That(destArray[i].Value, Is.EqualTo(players[i - 1])); + } + } + + [Test] + public void Keys() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var index = 0; + foreach (string s in lhm.Keys) + { + Assert.That(s, Is.EqualTo(players[index].Id)); + index++; + } + } + + [Test] + public void Values() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var index = 0; + foreach (Player p in lhm.Values) + { + Assert.That(p, Is.EqualTo(players[index])); + index++; + } + } + + [Test] + public void Serialization() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + + var stream = new MemoryStream(); + var f = new BinaryFormatter + { +#if !NETFX + SurrogateSelector = new SerializationHelper.SurrogateSelector() +#endif + }; + f.Serialize(stream, lhm); + stream.Position = 0; + + var dlhm = (LinkHashMap)f.Deserialize(stream); + stream.Close(); + + Assert.That(dlhm.Count, Is.EqualTo(6)); + var index = 0; + foreach (var pair in dlhm) + { + Assert.That(pair.Key, Is.EqualTo(players[index].Id)); + Assert.That(pair.Value, Is.EqualTo(players[index])); + index++; + } + + Assert.That(index, Is.EqualTo(6)); + } + + [Test, Explicit] + public void ShowDiff() + { + IDictionary dict = new Dictionary(); + IDictionary lhm = new LinkHashMap(); + Fill(dict); + Fill(lhm); + // Override the first element + var o = new Player("12341", "Override"); + dict[o.Id] = o; + lhm[o.Id] = o; + Console.Out.WriteLine("Dictionary order:"); + foreach (KeyValuePair pair in dict) + { + Console.Out.WriteLine("Key->{0}", pair.Key); + } + Console.Out.WriteLine("LinkHashMap order:"); + foreach (KeyValuePair pair in lhm) + { + Console.Out.WriteLine("Key->{0}", pair.Key); + } + } + + [Test, Explicit] + public void Performance() + { + // Take care with this test because the result is not the same every times + + int numOfRuns = 4; + + int numOfEntries = Int16.MaxValue; + + var dictPopulateTicks = new long[numOfRuns]; + var dictItemTicks = new long[numOfRuns]; + + var linkPopulateTicks = new long[numOfRuns]; + var linkItemTicks = new long[numOfRuns]; + + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) + { + string key; + object value; + IDictionary dictionary = new Dictionary(); + IDictionary linked = new LinkHashMap(); + + long dictStart = DateTime.Now.Ticks; + + for (int i = 0; i < numOfEntries; i++) + { + dictionary.Add("test" + i, new object()); + } + + dictPopulateTicks[runIndex] = DateTime.Now.Ticks - dictStart; + + dictStart = DateTime.Now.Ticks; + for (int i = 0; i < numOfEntries; i++) + { + key = "test" + i; + value = dictionary[key]; + } + dictItemTicks[runIndex] = DateTime.Now.Ticks - dictStart; + + dictionary.Clear(); + + long linkStart = DateTime.Now.Ticks; + + for (int i = 0; i < numOfEntries; i++) + { + linked.Add("test" + i, new object()); + } + + linkPopulateTicks[runIndex] = DateTime.Now.Ticks - linkStart; + + linkStart = DateTime.Now.Ticks; + for (int i = 0; i < numOfEntries; i++) + { + key = "test" + i; + value = linked[key]; + } + + linkItemTicks[runIndex] = DateTime.Now.Ticks - linkStart; + + linked.Clear(); + } + + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) + { + decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); + decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); + + string message = string.Format("LinkHashMap vs Dictionary (Run-{0}) :",runIndex+1); + message += "\n POPULATE:"; + message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; + message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; + message += "\n\t for an overhead of " + linkPopulateOverhead; + message += "\n RETRIVE:"; + message += "\n\t linked took " + linkItemTicks[runIndex] + " ticks."; + message += "\n\t dictionary took " + dictItemTicks[runIndex] + " ticks."; + message += "\n\t for an overhead of " + linkItemOverhead; + + Console.Out.WriteLine(message); + Console.Out.WriteLine(); + } + } + } + + internal static class LinkHashMapFixtureHelpers + { + public static System.Type GetVariableType(this T _) => typeof(T); + + public static bool IsStruct(this System.Type type) + { + return !type.IsClass && !type.IsInterface; + } + } + + [Serializable] + public class Player + { + private string id; + private string name; + + public Player(string id, string name) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + + this.id = id; + this.name = name; + } + + public string Id + { + get { return id; } + set { id = value; } + } + + public string Name + { + get { return name; } + set { name = value; } + } + + public override int GetHashCode() + { + return id.GetHashCode() ^ name.GetHashCode(); + } + + public override bool Equals(object obj) + { + Player that = obj as Player; + if (that == null) return false; + return id.Equals(that.id) && name.Equals(that.name); + } + + public override string ToString() + { + return $"<{id}>{name}"; + } + } +} diff --git a/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs b/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs deleted file mode 100644 index bfa995e190e..00000000000 --- a/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs +++ /dev/null @@ -1,415 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using NHibernate.Util; -using NUnit.Framework; - -namespace NHibernate.Test.UtilityTest -{ - [TestFixture] - public class LinkedHashMapFixture - { - private static readonly Player[] players = { - new Player("12341", "Boeta Dippenaar"), new Player("23432", "Gary Kirsten"), - new Player("23411", "Graeme Smith"), new Player("55221", "Jonty Rhodes"), - new Player("61234", "Monde Zondeki"), new Player("23415", "Paul Adams") - }; - - private static void Fill(IDictionary lhm) - { - foreach (Player player in players) - lhm.Add(player.Id, player); - } - - [Test] - public void Add() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - lhm.Add("55555", new Player("55555", "Monde Zondeki")); - - Assert.AreEqual(7, lhm.Count); - } - - [Test] - public void LastKeyLastValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.AreEqual(players[players.Length - 1].Id, lhm.LastKey); - Assert.AreEqual(players[players.Length-1], lhm.LastValue); - - // override - Player antWithSameId = new Player("12341", "Another"); - lhm[antWithSameId.Id] = antWithSameId; - Assert.AreEqual(antWithSameId.Id, lhm.LastKey); - Assert.AreEqual(antWithSameId, lhm.LastValue); - } - - [Test] - public void FirstKeyFirstValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.AreEqual(players[0].Id, lhm.FirstKey); - Assert.AreEqual(players[0], lhm.FirstValue); - - // override First - Player antWithSameId = new Player("12341", "Another"); - lhm[antWithSameId.Id] = antWithSameId; - Assert.AreEqual(players[1].Id, lhm.FirstKey); - Assert.AreEqual(players[1], lhm.FirstValue); - } - - [Test] - public void Clear() - { - IDictionary lhm = new LinkedHashMap(); - Player p = new Player("78945", "Someone"); - lhm[p.Id] = p; - - lhm.Clear(); - Assert.AreEqual(0, lhm.Count); - - foreach (KeyValuePair pair in lhm) - Assert.Fail("Should not be any entries but found Key = " + pair.Key + " and Value = " + pair.Value); - } - - [Test] - public void Contains() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - - Assert.IsTrue(lhm.Contains("12341")); - Assert.IsFalse(lhm.Contains("55555")); - } - - [Test] - public void GetEnumerator() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (KeyValuePair pair in lhm) - { - Assert.AreEqual(players[index].Id, pair.Key); - Assert.AreEqual(players[index], pair.Value); - index++; - } - - Assert.AreEqual(6, index); - } - - [Test] - public void GetEnumeratorEmpty() - { - IDictionary lhm = new LinkedHashMap(); - Assert.AreEqual(0, lhm.Count); - - int entries = 0; - foreach (KeyValuePair pair in lhm) - entries++; - foreach (string s in lhm.Keys) - entries++; - foreach (Player value in lhm.Values) - entries++; - - Assert.AreEqual(0, entries, "should not have any entries in the enumerators"); - } - - [Test] - public void GetEnumeratorModifyExceptionFromAdd() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm["78945"] = new Player("78945", "Someone"); - } - }); - } - - [Test] - public void GetEnumeratorModifyExceptionFromRemove() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm.Remove(pair.Key); - } - }); - } - - [Test] - public void GetEnumeratorModifyExceptionFromUpdate() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm["123"] = new Player("123", "aaaaaaa"); - } - }); - } - - [Test] - public void Remove() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - - // remove an item that exists - bool removed =lhm.Remove("23411"); - Assert.IsTrue(removed); - Assert.AreEqual(5, lhm.Count); - - // try to remove an item that does not exist - removed= lhm.Remove("65432"); - Assert.IsFalse(removed); - Assert.AreEqual(5, lhm.Count); - } - - [Test] - public void ContainsValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.IsTrue(lhm.ContainsValue(new Player("55221", "Jonty Rhodes"))); - Assert.IsFalse(lhm.ContainsValue(new Player("55221", "SameKeyDiffName"))); - } - - [Test] - public void CopyTo() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - KeyValuePair[] destArray = new KeyValuePair[lhm.Count + 1]; - destArray[0] = new KeyValuePair("999", new Player("999", "The number nine")); - lhm.CopyTo(destArray, 1); - - for (int i = 1; i < destArray.Length; i++) - { - Assert.AreEqual(players[i-1].Id, destArray[i].Key); - Assert.AreEqual(players[i-1], destArray[i].Value); - } - } - - [Test] - public void Keys() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (string s in lhm.Keys) - { - Assert.AreEqual(players[index].Id, s); - index++; - } - } - - [Test] - public void Values() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (Player p in lhm.Values) - { - Assert.AreEqual(players[index], p); - index++; - } - } - - [Test] - public void Serialization() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - - MemoryStream stream = new MemoryStream(); - var f = new BinaryFormatter - { -#if !NETFX - SurrogateSelector = new SerializationHelper.SurrogateSelector() -#endif - }; - f.Serialize(stream, lhm); - stream.Position = 0; - - LinkedHashMap dlhm = (LinkedHashMap)f.Deserialize(stream); - stream.Close(); - - Assert.AreEqual(6, dlhm.Count); - int index = 0; - foreach (KeyValuePair pair in dlhm) - { - Assert.AreEqual(players[index].Id, pair.Key); - Assert.AreEqual(players[index], pair.Value); - index++; - } - - Assert.AreEqual(6, index); - } - - [Test, Explicit] - public void ShowDiff() - { - IDictionary dict = new Dictionary(); - IDictionary lhm = new LinkedHashMap(); - Fill(dict); - Fill(lhm); - // Override the first element - Player o = new Player("12341", "Ovirride"); - dict[o.Id] = o; - lhm[o.Id] = o; - Console.Out.WriteLine("Dictionary order:"); - foreach (KeyValuePair pair in dict) - { - Console.Out.WriteLine("Key->{0}", pair.Key); - } - Console.Out.WriteLine("LinkedHashMap order:"); - foreach (KeyValuePair pair in lhm) - { - Console.Out.WriteLine("Key->{0}", pair.Key); - } - } - - [Test, Explicit] - public void Performance() - { - // Take care with this test because the result is not the same every times - - int numOfRuns = 4; - - int numOfEntries = Int16.MaxValue; - - long[] dictPopulateTicks = new long[numOfRuns]; - long[] dictItemTicks = new long[numOfRuns]; - - long[] linkPopulateTicks = new long[numOfRuns]; - long[] linkItemTicks = new long[numOfRuns]; - - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) - { - string key; - object value; - IDictionary dictionary = new Dictionary(); - IDictionary linked = new LinkedHashMap(); - - long dictStart = DateTime.Now.Ticks; - - for (int i = 0; i < numOfEntries; i++) - { - dictionary.Add("test" + i, new object()); - } - - dictPopulateTicks[runIndex] = DateTime.Now.Ticks - dictStart; - - dictStart = DateTime.Now.Ticks; - for (int i = 0; i < numOfEntries; i++) - { - key = "test" + i; - value = dictionary[key]; - } - dictItemTicks[runIndex] = DateTime.Now.Ticks - dictStart; - - dictionary.Clear(); - - long linkStart = DateTime.Now.Ticks; - - for (int i = 0; i < numOfEntries; i++) - { - linked.Add("test" + i, new object()); - } - - linkPopulateTicks[runIndex] = DateTime.Now.Ticks - linkStart; - - linkStart = DateTime.Now.Ticks; - for (int i = 0; i < numOfEntries; i++) - { - key = "test" + i; - value = linked[key]; - } - - linkItemTicks[runIndex] = DateTime.Now.Ticks - linkStart; - - linked.Clear(); - } - - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) - { - decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); - decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); - - string message = string.Format("LinkedHashMap vs Dictionary (Run-{0}) :",runIndex+1); - message += "\n POPULATE:"; - message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; - message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; - message += "\n\t for an overhead of " + linkPopulateOverhead; - message += "\n RETRIVE:"; - message += "\n\t linked took " + linkItemTicks[runIndex] + " ticks."; - message += "\n\t dictionary took " + dictItemTicks[runIndex] + " ticks."; - message += "\n\t for an overhead of " + linkItemOverhead; - - Console.Out.WriteLine(message); - Console.Out.WriteLine(); - } - } - } - - [Serializable] - public class Player - { - private string id; - private string name; - public Player(string id, string name) - { - if (string.IsNullOrEmpty(id)) - throw new ArgumentNullException("id"); - - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - this.id = id; - this.name = name; - } - - public string Id - { - get { return id; } - set { id = value; } - } - - public string Name - { - get { return name; } - set { name = value; } - } - - public override int GetHashCode() - { - return id.GetHashCode() ^ name.GetHashCode(); - } - - public override bool Equals(object obj) - { - Player that = obj as Player; - if(that==null) return false; - return id.Equals(that.id) && name.Equals(that.name); - } - - public override string ToString() - { - return string.Format("<{0}>{1}", id, name); - } - } -} diff --git a/src/NHibernate/Async/Engine/BatchFetchQueue.cs b/src/NHibernate/Async/Engine/BatchFetchQueue.cs index 4500f7eca55..9f7cf11e586 100644 --- a/src/NHibernate/Async/Engine/BatchFetchQueue.cs +++ b/src/NHibernate/Async/Engine/BatchFetchQueue.cs @@ -72,7 +72,7 @@ internal async Task GetCollectionBatchAsync(ICollectionPersister colle return keys; } - foreach (KeyValuePair me in map) + foreach (var me in map) { cancellationToken.ThrowIfCancellationRequested(); if (ProcessKey(me) ?? await (CheckCacheAndProcessResultAsync()).ConfigureAwait(false)) diff --git a/src/NHibernate/Cfg/XmlHbmBinding/NamedQueryBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/NamedQueryBinder.cs index b008b52d4f5..63e15fbc61e 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/NamedQueryBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/NamedQueryBinder.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using NHibernate.Cfg.MappingSchema; using NHibernate.Engine; using NHibernate.Util; @@ -31,7 +30,7 @@ public void AddQuery(HbmQuery querySchema) ? querySchema.cachemode.ToCacheMode() : null; - IDictionary parameterTypes = new LinkedHashMap(); + var parameterTypes = new LinkHashMap(); var namedQuery = new NamedQueryDefinition(queryText, cacheable, region, timeout, fetchSize, flushMode, cacheMode, readOnly, comment, parameterTypes); @@ -39,4 +38,4 @@ public void AddQuery(HbmQuery querySchema) mappings.AddQuery(queryName, namedQuery); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Engine/BatchFetchQueue.cs b/src/NHibernate/Engine/BatchFetchQueue.cs index d9bc7068108..3e5bb08d576 100644 --- a/src/NHibernate/Engine/BatchFetchQueue.cs +++ b/src/NHibernate/Engine/BatchFetchQueue.cs @@ -31,7 +31,7 @@ public partial class BatchFetchQueue /// private readonly Dictionary subselectsByEntityKey = new Dictionary(8); - private readonly Dictionary> batchLoadableCollections = new Dictionary>(8); + private readonly Dictionary> batchLoadableCollections = new(8); /// /// The owning persistence context. /// @@ -164,7 +164,7 @@ public void AddBatchLoadableCollection(IPersistentCollection collection, Collect if (!batchLoadableCollections.TryGetValue(persister.Role, out var map)) { - map = new LinkedHashMap(); + map = new LinkHashMap(); batchLoadableCollections.Add(persister.Role, map); } map[ce] = collection; @@ -245,7 +245,7 @@ internal object[] GetCollectionBatch(ICollectionPersister collectionPersister, o return keys; } - foreach (KeyValuePair me in map) + foreach (var me in map) { if (ProcessKey(me) ?? CheckCacheAndProcessResult()) { diff --git a/src/NHibernate/Mapping/Table.cs b/src/NHibernate/Mapping/Table.cs index 3082a9c02b0..5311ece174d 100644 --- a/src/NHibernate/Mapping/Table.cs +++ b/src/NHibernate/Mapping/Table.cs @@ -27,7 +27,7 @@ public enum SchemaAction public class Table : IRelationalModel { private readonly List checkConstraints = new List(); - private readonly LinkedHashMap columns = new LinkedHashMap(); + private readonly LinkHashMap columns = new(); private readonly Dictionary foreignKeys = new Dictionary(); private readonly Dictionary indexes = new Dictionary(); private int? uniqueInteger; diff --git a/src/NHibernate/SqlCommand/CaseFragment.cs b/src/NHibernate/SqlCommand/CaseFragment.cs index 5a4a0ff3c1f..a7d1240cc60 100644 --- a/src/NHibernate/SqlCommand/CaseFragment.cs +++ b/src/NHibernate/SqlCommand/CaseFragment.cs @@ -9,7 +9,7 @@ public abstract class CaseFragment protected internal readonly Dialect.Dialect dialect; protected internal string returnColumnName; - protected internal IDictionary cases = new LinkedHashMap(); + protected internal IDictionary cases = new LinkHashMap(); protected CaseFragment(Dialect.Dialect dialect) { @@ -35,4 +35,4 @@ public virtual CaseFragment AddWhenColumnNotNull(string alias, string columnName public abstract string ToSqlStringFragment(); } -} \ No newline at end of file +} diff --git a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs index d73f98fd4d5..0a8f88883f8 100644 --- a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs @@ -19,7 +19,7 @@ public class SqlInsertBuilder : ISqlStringBuilder private string comment; // columns-> (ColumnName, Value) or (ColumnName, SqlType) for parametrized column - private readonly LinkedHashMap columns = new LinkedHashMap(); + private readonly LinkHashMap columns = new(); public SqlInsertBuilder(ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs index c9b7ccd1352..80c154ffdf8 100644 --- a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs @@ -19,7 +19,7 @@ public class SqlUpdateBuilder : SqlBaseBuilder, ISqlStringBuilder private string comment; // columns-> (ColumnName, Value) or (ColumnName, SqlType) for parametrized column - private readonly LinkedHashMap columns = new LinkedHashMap(); + private readonly LinkHashMap columns = new(); private List whereStrings = new List(); private readonly List whereParameterTypes = new List(); diff --git a/src/NHibernate/Util/CollectionHelper.cs b/src/NHibernate/Util/CollectionHelper.cs index e6ed9842065..6f40567923c 100644 --- a/src/NHibernate/Util/CollectionHelper.cs +++ b/src/NHibernate/Util/CollectionHelper.cs @@ -733,8 +733,9 @@ public static bool DictionaryEquals(IDictionary m1, IDictionary.Default) : m1.All(kv => m2.TryGetValue(kv.Key, out var value) && comparer.Equals(kv.Value, value))); +#if !NETCOREAPP2_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER //It's added to make use of optimized .NET Core Dictionary.Remove(key, out value) method - internal static bool Remove(this Dictionary dic, TKey key, out TValue value) + public static bool Remove(this Dictionary dic, TKey key, out TValue value) { if (!dic.TryGetValue(key, out value)) return false; @@ -742,6 +743,7 @@ internal static bool Remove(this Dictionary dic, TKe dic.Remove(key); return true; } +#endif private static bool? FastCheckEquality(IEnumerable c1, IEnumerable c2) { diff --git a/src/NHibernate/Util/LinkHashMap.cs b/src/NHibernate/Util/LinkHashMap.cs new file mode 100644 index 00000000000..26d3e147506 --- /dev/null +++ b/src/NHibernate/Util/LinkHashMap.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Text; +using NHibernate.DebugHelpers; + +namespace NHibernate.Util +{ + /// + /// A map of objects whose mapping entries are sequenced based on the order in which they were + /// added. This data structure has fast O(1) search time, deletion time, and insertion time + /// + /// + /// This class is not thread safe. + /// This class is not really a replication of JDK LinkedHashMap{K, V}, + /// this class is an adaptation of SequencedHashMap with generics. + /// + [DebuggerTypeProxy(typeof(CollectionProxy<>))] + [Serializable] + internal class LinkHashMap : IDictionary, IDeserializationCallback + { + [Serializable] + protected class Entry + { + public Entry(TKey key, TValue value) + { + Key = key; + Value = value; + } + + public TKey Key { get; } + + public TValue Value { get; set; } + + public Entry Next { get; set; } + + public Entry Prev { get; set; } + + #region System.Object Members + + public override int GetHashCode() + { + return Key == null ? 0 : Key.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as Entry; + if (other == null) return false; + if (other == this) return true; + + return (Key == null ? other.Key == null : Key.Equals(other.Key)) && + (Value == null ? other.Value == null : Value.Equals(other.Value)); + } + + public override string ToString() + { + return "[" + Key + "=" + Value + "]"; + } + + #endregion + } + + private readonly Entry _header; + private readonly Dictionary _entries; + private long _version; + + /// + /// Initializes a new instance of the class that is empty, + /// has the default initial capacity, and uses the default equality comparer for the key type. + /// + public LinkHashMap() + : this(0, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, + /// has the specified initial capacity, and uses the default equality comparer for the key type. + /// + /// The initial number of elements that the can contain. + public LinkHashMap(int capacity) + : this(capacity, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the default initial capacity, and uses the specified . + /// + /// The implementation to use when comparing keys, or null to use the default EqualityComparer for the type of the key. + public LinkHashMap(IEqualityComparer equalityComparer) + : this(0, equalityComparer) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the specified . + /// + /// The initial number of elements that the can contain. + /// The implementation to use when comparing keys, or null to use the default EqualityComparer for the type of the key. + public LinkHashMap(int capacity, IEqualityComparer equalityComparer) + { + _header = CreateSentinel(); + _entries = new Dictionary(capacity, equalityComparer); + } + + #region IDictionary Members + + public virtual bool ContainsKey(TKey key) + { + return _entries.ContainsKey(key); + } + + public virtual void Add(TKey key, TValue value) + { + var e = new Entry(key, value); + _entries.Add(key, e); + _version++; + InsertEntry(e); + } + + public virtual bool Remove(TKey key) + { + return RemoveImpl(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + var result = _entries.TryGetValue(key, out var entry); + if (result) + value = entry.Value; + else + value = default; + + return result; + } + + public TValue this[TKey key] + { + get + { + return _entries[key].Value; + } + set + { + if (_entries.TryGetValue(key, out var e)) + OverrideEntry(e, value); + else + Add(key, value); + } + } + + private void OverrideEntry(Entry e, TValue value) + { + _version++; + RemoveEntry(e); + e.Value = value; + InsertEntry(e); + } + + public KeyCollection Keys => new KeyCollection(this); + + ICollection IDictionary.Keys => new KeyCollection(this); + + public virtual ValueCollection Values => new ValueCollection(this); + + ICollection IDictionary.Values => new ValueCollection(this); + + #endregion + + #region ICollection> Members + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public virtual void Clear() + { + _version++; + + _entries.Clear(); + + _header.Next = _header; + _header.Prev = _header; + } + + public bool Contains(KeyValuePair item) + { + return Contains(item.Key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + foreach (var pair in this) + array.SetValue(pair, arrayIndex++); + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + public virtual int Count => _entries.Count; + + public virtual bool IsReadOnly => false; + + #endregion + + public Enumerator GetEnumerator() => new Enumerator(this); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(this); + } + + #endregion + + #region IEnumerable> Members + + IEnumerator> IEnumerable>.GetEnumerator() + { + return new Enumerator(this); + } + + #endregion + + #region LinkHashMap Members + + private bool IsEmpty + { + get { return _header.Next == _header; } + } + + public virtual bool IsFixedSize => false; + + public virtual TKey FirstKey + { + get { return First == null ? default : First.Key; } + } + + public virtual TValue FirstValue + { + get { return First == null ? default : First.Value; } + } + + public virtual TKey LastKey + { + get { return Last == null ? default : Last.Key; } + } + + public virtual TValue LastValue + { + get { return Last == null ? default : Last.Value; } + } + + public virtual bool Contains(TKey key) + { + return ContainsKey(key); + } + + public virtual bool ContainsValue(TValue value) + { + if (value == null) + { + for (var entry = _header.Next; entry != _header; entry = entry.Next) + { + if (entry.Value == null) return true; + } + } + else + { + for (var entry = _header.Next; entry != _header; entry = entry.Next) + { + if (value.Equals(entry.Value)) return true; + } + } + return false; + } + + #endregion + + private static Entry CreateSentinel() + { + var s = new Entry(default, default); + s.Prev = s; + s.Next = s; + return s; + } + + private static void RemoveEntry(Entry entry) + { + entry.Next.Prev = entry.Prev; + entry.Prev.Next = entry.Next; + } + + private void InsertEntry(Entry entry) + { + entry.Next = _header; + entry.Prev = _header.Prev; + _header.Prev.Next = entry; + _header.Prev = entry; + } + + private Entry First + { + get { return IsEmpty ? null : _header.Next; } + } + + private Entry Last + { + get { return IsEmpty ? null : _header.Prev; } + } + + private bool RemoveImpl(TKey key) + { + if (!_entries.Remove(key, out var e)) + return false; + + _version++; + RemoveEntry(e); + return true; + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + ((IDeserializationCallback)_entries).OnDeserialization(sender); + } + + #region System.Object Members + + public override string ToString() + { + var buf = new StringBuilder(); + buf.Append('['); + for (Entry pos = _header.Next; pos != _header; pos = pos.Next) + { + buf.Append(pos.Key); + buf.Append('='); + buf.Append(pos.Value); + if (pos.Next != _header) + { + buf.Append(','); + } + } + buf.Append(']'); + + return buf.ToString(); + } + + #endregion + + public class KeyCollection : ICollection + { + private readonly LinkHashMap _dictionary; + + public KeyCollection(LinkHashMap dictionary) + { + _dictionary = dictionary; + } + + #region ICollection Members + + void ICollection.Add(TKey item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + void ICollection.Clear() + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + bool ICollection.Contains(TKey item) + { + foreach (var key in this) + { + if (key.Equals(item)) + return true; + } + return false; + } + + public void CopyTo(TKey[] array, int arrayIndex) + { + foreach (var key in this) + array.SetValue(key, arrayIndex++); + } + + bool ICollection.Remove(TKey item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + public int Count => _dictionary.Count; + + bool ICollection.IsReadOnly => true; + + #endregion + + public Enumerator GetEnumerator() => new(_dictionary); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + public struct Enumerator : IEnumerator + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public TKey Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return _current.Key; + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } + + public class ValueCollection : ICollection + { + private readonly LinkHashMap _dictionary; + + public ValueCollection(LinkHashMap dictionary) + { + _dictionary = dictionary; + } + + #region ICollection Members + + void ICollection.Add(TValue item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + void ICollection.Clear() + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + bool ICollection.Contains(TValue item) + { + foreach (var value in this) + { + if (value.Equals(item)) + return true; + } + return false; + } + + public void CopyTo(TValue[] array, int arrayIndex) + { + foreach (var value in this) + array.SetValue(value, arrayIndex++); + } + + bool ICollection.Remove(TValue item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + public int Count => _dictionary.Count; + + bool ICollection.IsReadOnly => true; + + #endregion + + public Enumerator GetEnumerator() => new Enumerator(_dictionary); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + public struct Enumerator : IEnumerator + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public TValue Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return _current.Value; + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } + + public struct Enumerator : IEnumerator> + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public KeyValuePair Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return new KeyValuePair(_current.Key, _current.Value); + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } +} diff --git a/src/NHibernate/Util/LinkedHashMap.cs b/src/NHibernate/Util/LinkedHashMap.cs index 5487204deee..e2ce34b60f2 100644 --- a/src/NHibernate/Util/LinkedHashMap.cs +++ b/src/NHibernate/Util/LinkedHashMap.cs @@ -19,6 +19,8 @@ namespace NHibernate.Util /// [DebuggerTypeProxy(typeof(CollectionProxy<>))] [Serializable] + // Since 5.6 + [Obsolete("This class has no more usages and will be removed in a future version.")] public class LinkedHashMap : IDictionary, IDeserializationCallback { [Serializable] From f9382392dc3acb162012faa997eb6d2f56a219d4 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 28 Feb 2024 05:27:27 +1000 Subject: [PATCH 072/128] Add NUnit analyzers (#3492) --- .editorconfig | 18 +++++-- .../Async/CompositeId/CompositeIdFixture.cs | 4 +- .../Async/Criteria/CriteriaQueryTest.cs | 2 +- .../Criteria/SelectModeTest/SelectModeTest.cs | 2 +- .../Projection/ProjectionSqlFixture.cs | 16 +++--- .../Async/FilterTest/DynamicFilterTest.cs | 2 +- .../Async/Legacy/FooBarTest.cs | 10 ++-- .../Async/Legacy/MasterDetailTest.cs | 2 +- .../Async/Legacy/SQLLoaderTest.cs | 2 +- .../Async/Linq/ByMethod/AverageTests.cs | 2 +- src/NHibernate.Test/Async/Linq/PagingTests.cs | 8 +-- .../Async/NHSpecificTest/GH1754/Fixture.cs | 41 +++++++-------- .../NH1098/FilterParameterOrderFixture.cs | 2 +- .../Async/NHSpecificTest/NH1394/Fixture.cs | 12 ++--- .../Async/NHSpecificTest/NH1413/PagingTest.cs | 2 +- .../Async/NHSpecificTest/NH1679/Fixture.cs | 2 +- .../Async/NHSpecificTest/NH1688/Fixture.cs | 2 +- .../Async/NHSpecificTest/NH1821/Fixture.cs | 10 ++-- .../Async/NHSpecificTest/NH1859/SampleTest.cs | 2 +- .../Async/NHSpecificTest/NH2092/Fixture.cs | 2 +- .../Async/NHSpecificTest/NH2093/Fixture.cs | 2 +- .../Properties/CompositePropertyRefTest.cs | 10 ++-- .../SqlTest/Custom/CustomSQLSupportTest.cs | 6 +-- .../Custom/CustomStoredProcSupportTest.cs | 12 ++--- .../SqlTest/Query/NativeSQLQueriesFixture.cs | 38 +++++++------- .../SubselectFetchFixture.cs | 40 +++++++-------- .../Async/TypeParameters/TypeParameterTest.cs | 18 +++---- .../Unionsubclass/UnionSubclassFixture.cs | 2 +- .../Async/VersionTest/VersionFixture.cs | 2 +- .../CompositeId/CompositeIdFixture.cs | 4 +- .../Criteria/CriteriaQueryTest.cs | 2 +- .../Criteria/Lambda/LambdaFixtureBase.cs | 2 +- .../Criteria/SelectModeTest/SelectModeTest.cs | 2 +- .../Projection/ProjectionSqlFixture.cs | 16 +++--- .../FilterTest/DynamicFilterTest.cs | 2 +- .../FilterTest/FilterConfig.cs | 6 +-- src/NHibernate.Test/Legacy/FooBarTest.cs | 10 ++-- .../Legacy/MasterDetailTest.cs | 2 +- src/NHibernate.Test/Legacy/SQLLoaderTest.cs | 2 +- .../Linq/ByMethod/AverageTests.cs | 2 +- src/NHibernate.Test/Linq/PagingTests.cs | 10 ++-- .../Linq/PreEvaluationTests.cs | 8 +-- .../BasicMappingOfSimpleClass.cs | 2 +- .../ComponentAsIdTests.cs | 2 +- .../OptimisticLockModeTests.cs | 2 +- .../IntegrationTests/NH3110/Fixture.cs | 2 +- ...odelExplicitDeclarationsHolderMergeTest.cs | 50 +++++++++---------- .../NHSpecificTest/GH1754/Fixture.cs | 43 ++++++++-------- .../NH1098/FilterParameterOrderFixture.cs | 2 +- .../NHSpecificTest/NH1394/Fixture.cs | 12 ++--- .../NHSpecificTest/NH1413/PagingTest.cs | 2 +- .../NHSpecificTest/NH1679/Fixture.cs | 2 +- .../NHSpecificTest/NH1688/Fixture.cs | 2 +- .../NHSpecificTest/NH1821/Fixture.cs | 10 ++-- .../NHSpecificTest/NH1859/SampleTest.cs | 2 +- .../NHSpecificTest/NH2092/Fixture.cs | 2 +- .../NHSpecificTest/NH2093/Fixture.cs | 2 +- .../NHSpecificTest/NH3004/Fixture.cs | 4 +- .../Properties/CompositePropertyRefTest.cs | 10 ++-- src/NHibernate.Test/NHibernate.Test.csproj | 1 + .../SqlCommandTest/SqlStringFixture.cs | 3 +- .../SqlTest/Custom/CustomSQLSupportTest.cs | 6 +-- .../Custom/CustomStoredProcSupportTest.cs | 12 ++--- .../SqlTest/Query/NativeSQLQueriesFixture.cs | 38 +++++++------- .../SubselectFetchFixture.cs | 40 +++++++-------- .../TypeParameters/TypeParameterTest.cs | 18 +++---- .../Unionsubclass/UnionSubclassFixture.cs | 2 +- .../VersionTest/VersionFixture.cs | 2 +- 68 files changed, 310 insertions(+), 304 deletions(-) diff --git a/.editorconfig b/.editorconfig index cdafebe60ab..9315aa4e45e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,20 @@ csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true +dotnet_diagnostic.NUnit1032.severity = suggestion +dotnet_diagnostic.NUnit1028.severity = none +dotnet_diagnostic.NUnit2045.severity = none +# Consider using the constraint model, Assert.That +dotnet_diagnostic.NUnit2005.severity = suggestion +dotnet_diagnostic.NUnit2006.severity = suggestion +dotnet_diagnostic.NUnit2015.severity = suggestion +dotnet_diagnostic.NUnit2031.severity = suggestion +dotnet_diagnostic.NUnit2049.severity = suggestion +# NUnit 4 no longer supports string.Format specification for Assert +dotnet_diagnostic.NUnit2050.severity = suggestion +# The SameAs constraint always fails on value types as the actual and the expected value cannot be the same reference +dotnet_diagnostic.NUnit2040.severity = suggestion + [*.xsd] indent_style = tab @@ -34,9 +48,5 @@ indent_size = 2 indent_style = space indent_size = 2 -[*.cshtml] -indent_style = space -indent_size = 4 - [*.g] indent_style = tab diff --git a/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs b/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs index c2a78d82e16..647e0cb39d8 100644 --- a/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs +++ b/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs @@ -199,8 +199,8 @@ public async Task MultipleCollectionFetchAsync() Assert.AreEqual(2, c.Orders.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[0]).LineItems)); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[1]).LineItems)); - Assert.AreEqual(((Order) c.Orders[0]).LineItems.Count, 2); - Assert.AreEqual(((Order) c.Orders[1]).LineItems.Count, 2); + Assert.AreEqual(2, ((Order) c.Orders[0]).LineItems.Count); + Assert.AreEqual(2, ((Order) c.Orders[1]).LineItems.Count); await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs index ef2bbf8dae0..8801c0e79c5 100644 --- a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs @@ -3093,7 +3093,7 @@ public async Task CanSetLockModeOnDetachedCriteriaAsync() var countExec = CriteriaTransformer.TransformToRowCount(ec); var countRes = await (countExec.UniqueResultAsync()); - Assert.AreEqual(countRes, 1); + Assert.AreEqual(1, countRes); } } } diff --git a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs index b06fde747f1..a54bec846f6 100644 --- a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs @@ -347,7 +347,7 @@ public async Task SelectModeFetchLazyPropertiesForEntityJoinAsync() Assert.That(NHibernateUtil.IsInitialized(rootChild), Is.True); Assert.That(NHibernateUtil.IsInitialized(parentJoin), Is.True); - Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.Not.Null.Or.Empty); + Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.True); Assert.That(parentJoin.LazyProp, Is.Not.Null.Or.Empty); Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected"); diff --git a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs index 86b59bbe491..dac7fb16092 100644 --- a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs +++ b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs @@ -74,9 +74,9 @@ public async Task QueryTestWithStrongTypeReturnValueAsync() .Add(Projections.Min("Pay"))); c.SetResultTransformer(trans); ProjectionReport report = await (c.UniqueResultAsync()); - Assert.AreEqual(report.AvgPay, 2.5); - Assert.AreEqual(report.MaxPay, 4); - Assert.AreEqual(report.MinPay, 1); + Assert.AreEqual(2.5, report.AvgPay); + Assert.AreEqual(4, report.MaxPay); + Assert.AreEqual(1, report.MinPay); } } @@ -97,10 +97,10 @@ public async Task QueryTest1Async() Assert.IsTrue(result[0] is object[], "expected object[] as result, but found " + result[0].GetType().Name); object[] results = (object[])result[0]; - Assert.AreEqual(results.Length, 3); - Assert.AreEqual(results[0], 2.5); - Assert.AreEqual(results[1], 4); - Assert.AreEqual(results[2], 1); + Assert.AreEqual(3, results.Length); + Assert.AreEqual(2.5, results[0]); + Assert.AreEqual(4, results[1]); + Assert.AreEqual(1, results[2]); } } @@ -119,7 +119,7 @@ public async Task SelectSqlProjectionTestAsync() IList result = await (c.ListAsync()); // c.UniqueResult(); Assert.IsTrue(result.Count == 1); object results = result[0]; - Assert.AreEqual(results, 2.5); + Assert.AreEqual(2.5, results); } } } diff --git a/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs b/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs index 2b4a25c95a0..f0418657911 100644 --- a/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs +++ b/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs @@ -108,7 +108,7 @@ public async Task CombinedClassAndCollectionFiltersEnabledAsync() salespersons = await (session.CreateQuery("select s from Salesperson as s left join fetch s.Orders").ListAsync()); Assert.AreEqual(1, salespersons.Count, "Incorrect salesperson count"); sp = (Salesperson) salespersons[0]; - Assert.AreEqual(sp.Orders.Count, 1, "Incorrect order count"); + Assert.AreEqual(1, sp.Orders.Count, "Incorrect order count"); } } diff --git a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs index f7f7f1a2b8f..8be620d638f 100644 --- a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs @@ -1078,8 +1078,8 @@ public async Task PropertyRefAsync() using (ISession s = OpenSession()) { Holder h = (Holder) await (s.LoadAsync(typeof(Holder), hid)); - Assert.AreEqual(h.Name, "foo"); - Assert.AreEqual(h.OtherHolder.Name, "bar"); + Assert.AreEqual("foo", h.Name); + Assert.AreEqual("bar", h.OtherHolder.Name); object[] res = (object[]) (await (s.CreateQuery("from Holder h join h.OtherHolder oh where h.OtherHolder.Name = 'bar'").ListAsync()))[0]; Assert.AreSame(h, res[0]); @@ -1430,7 +1430,7 @@ public async Task SortablesAsync() // DictionaryEntry key - not the index. foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } @@ -1446,7 +1446,7 @@ public async Task SortablesAsync() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } await (s.FlushAsync()); @@ -1461,7 +1461,7 @@ public async Task SortablesAsync() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } await (s.DeleteAsync(b)); diff --git a/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs b/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs index 97d7277918f..d96bd6deacb 100644 --- a/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs +++ b/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs @@ -184,7 +184,7 @@ public async Task CopyCascadeAsync() // Save parent and cascade update detached child Category persistentParent = await (s.MergeAsync(parent)); Assert.IsTrue(persistentParent.Subcategories.Count == 1); - Assert.AreEqual(((Category) persistentParent.Subcategories[0]).Name, "child2"); + Assert.AreEqual("child2", ((Category) persistentParent.Subcategories[0]).Name); await (s.FlushAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs b/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs index 3d9119be986..9e539f3e7fd 100644 --- a/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs +++ b/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs @@ -481,7 +481,7 @@ public async Task ComponentNoStarAsync() IQuery q = session.CreateSQLQuery(sql).AddEntity("comp", typeof(Componentizable)); IList list = await (q.ListAsync(cancellationToken)); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); Componentizable co = (Componentizable) list[0]; diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs index 14e4fdf91ef..e71660b4b1d 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs @@ -25,7 +25,7 @@ public async Task CanGetAverageOfIntegersAsDoubleAsync() //NH-2429 var average = await (db.Products.AverageAsync(x => x.UnitsOnOrder)); - Assert.AreEqual(average, 10.129870d, 0.000001d); + Assert.AreEqual(10.129870d, average, 0.000001d); } } } diff --git a/src/NHibernate.Test/Async/Linq/PagingTests.cs b/src/NHibernate.Test/Async/Linq/PagingTests.cs index 6c72ddd1f4d..c4ea2530d11 100644 --- a/src/NHibernate.Test/Async/Linq/PagingTests.cs +++ b/src/NHibernate.Test/Async/Linq/PagingTests.cs @@ -136,7 +136,7 @@ public async Task Customers11to20Async() var query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); } @@ -146,19 +146,19 @@ public async Task Customers11to20And21to30ShouldNoCacheQueryAsync() var query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(20).Take(10).ToListAsync()); - Assert.AreNotEqual(query[0], "BSBEV"); + Assert.AreNotEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(20).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(20, query.Count); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs index 2f2e042fa1d..1245739aa76 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -86,7 +87,7 @@ public async Task CanAddChildAfterFlushAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -104,7 +105,7 @@ public async Task CanAddChildAfterFlushWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -132,7 +133,7 @@ public async Task CanMergeWithTransientChildAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -153,7 +154,7 @@ public async Task CanMergeWithTransientChildWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -179,7 +180,7 @@ public async Task CanChangeOwnershipOnFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -192,7 +193,7 @@ public async Task CanChangeOwnershipOnFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -215,7 +216,7 @@ public async Task CanChangeOwnershipOnFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -228,7 +229,7 @@ public async Task CanChangeOwnershipOnFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -254,7 +255,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -267,7 +268,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -290,7 +291,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -303,7 +304,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -329,7 +330,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -342,7 +343,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -365,7 +366,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -378,7 +379,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -404,7 +405,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -417,7 +418,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -440,7 +441,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -453,7 +454,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs index 8be29780dca..700e2ed4714 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs @@ -204,7 +204,7 @@ public async Task QueryMapElementsAsync() var a = await (query.UniqueResultAsync()); - Assert.AreEqual(a.C[1], "Text1"); + Assert.AreEqual("Text1", a.C[1]); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs index 641113b1e29..aba848d70a5 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs @@ -105,9 +105,9 @@ public async Task CanOrderBySubqueryProjectionAsync() // Oracle order NULL Last (ASC) nullRelationOffSet = 0; } - Assert.AreEqual(list[nullRelationOffSet].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet + 1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet + 2].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet + 1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet + 2].Name); } } } @@ -133,9 +133,9 @@ public async Task CanOrderBySubqueryProjectionDescAsync() // Oracle order NULL First (DESC) nullRelationOffSet = 2; } - Assert.AreEqual(list[nullRelationOffSet+2].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet+1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet+2].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet+1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet].Name); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs index 22143a7fb7b..e6959c4d31a 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs @@ -39,7 +39,7 @@ public async Task BugAsync() ICriteria icriteria = criteria.GetExecutableCriteria(session); icriteria.SetFirstResult(0); icriteria.SetMaxResults(2); - Assert.That(2, Is.EqualTo((await (icriteria.ListAsync())).Count)); + Assert.That((await (icriteria.ListAsync())).Count, Is.EqualTo(2)); } using (ISession session = OpenSession()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs index 44a2c9f957c..469bad0eb6d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs @@ -64,7 +64,7 @@ protected override void OnTearDown() action.Invoke(criteria); IList l = await (criteria.GetExecutableCriteria(session).ListAsync(cancellationToken)); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs index 63de1264791..2fbaf5b2351 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs @@ -73,7 +73,7 @@ protected override void OnTearDown() action.Invoke(criteria); IList l = await (criteria.GetExecutableCriteria(session).ListAsync(cancellationToken)); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs index 689c84707e9..1d7a0faa961 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs @@ -41,13 +41,9 @@ from Entity Regex whitespaces = new Regex(@"\s+", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); - Assert.AreEqual( - string.Compare( - whitespaces.Replace(sql, " ").Trim(), - whitespaces.Replace(renderedSql, " ").Trim(), - true - ), - 0 + Assert.That( + whitespaces.Replace(renderedSql, " ").Trim(), + Is.EqualTo(whitespaces.Replace(sql, " ").Trim()).IgnoreCase ); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs index a30b6a2a669..c5dc5444b8e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs @@ -44,7 +44,7 @@ public async Task NativeQueryWithTwoCommentsAsync() IQuery qry = session.CreateSQLQuery("select /* first comment */ o.* /* second comment*/ from domainclass o") .AddEntity("o", typeof (DomainClass)); var res = await (qry.ListAsync()); - Assert.AreEqual(res[0].Id, 1); + Assert.AreEqual(1, res[0].Id); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs index d963532aa81..dfa2b97b05f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs @@ -38,7 +38,7 @@ public async Task ConstrainedLazyLoadedOneToOneUsingCastleProxyAsync() Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.False); - Assert.That("Person1", Is.EqualTo(employee.Person.Name)); + Assert.That(employee.Person.Name, Is.EqualTo("Person1")); Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.True); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs index 84072f3b7ee..05478d74fba 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs @@ -87,7 +87,7 @@ public async Task CanUseFieldInterceptingProxyAsHQLArgumentAsync() .SetEntity("p", person) .ListAsync()); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); } } finally diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs index 31de09b83e7..e2cb3c1821c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs @@ -72,7 +72,7 @@ public async Task MappingOuterJoinAsync() Assert.IsNull(p2.Address); Assert.IsNotNull(p.Address); var l = await (s.CreateQuery("from Person").ListAsync()); //pull address references for cache - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsTrue(l.Contains(p) && l.Contains(p2)); } } @@ -86,7 +86,7 @@ public async Task AddressBySequentialSelectAsync() using (s.BeginTransaction()) { var l = await (s.CreateQuery("from Person p order by p.Name").ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsNull(l[0].Address); Assert.IsNotNull(l[1].Address); } @@ -101,7 +101,7 @@ public async Task AddressOuterJoinAsync() using (s.BeginTransaction()) { var l = await (s.CreateQuery("from Person p left join fetch p.Address a order by a.Country").ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); if (l[0].Name.Equals("Max")) { Assert.IsNull(l[0].Address); @@ -146,11 +146,11 @@ public async Task AccountsOuterJoinVerifyInitializationAsync() var l = await (s.CreateQuery("from Person p left join fetch p.Accounts a order by p.Name").ListAsync()); var p0 = l[0]; Assert.IsTrue(NHibernateUtil.IsInitialized(p0.Accounts)); - Assert.AreEqual(p0.Accounts.Count, 1); + Assert.AreEqual(1, p0.Accounts.Count); Assert.AreSame(p0.Accounts.First().User, p0); var p1 = l[1]; Assert.IsTrue(NHibernateUtil.IsInitialized(p1.Accounts)); - Assert.AreEqual(p1.Accounts.Count, 0); + Assert.AreEqual(0, p1.Accounts.Count); } } } diff --git a/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs b/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs index fad2a72a99d..6beef5e6769 100644 --- a/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs @@ -59,10 +59,10 @@ public async Task HandSQLAsync() s = OpenSession(); t = s.BeginTransaction(); jboss = (Organization)await (s.GetAsync(typeof(Organization), orgId)); - Assert.AreEqual(jboss.Employments.Count, 2); + Assert.AreEqual(2, jboss.Employments.Count); emp = (Employment)GetFirstItem(jboss.Employments); gavin = emp.Employee; - Assert.AreEqual(gavin.Name, "GAVIN"); + Assert.AreEqual("GAVIN", gavin.Name); Assert.AreEqual(s.GetCurrentLockMode(gavin), LockMode.Upgrade); emp.EndDate = DateTime.Today; Employment emp3 = new Employment(gavin, jboss, "US"); @@ -75,7 +75,7 @@ public async Task HandSQLAsync() IEnumerator iter = (await (s.GetNamedQuery("allOrganizationsWithEmployees").ListAsync())).GetEnumerator(); Assert.IsTrue(iter.MoveNext()); Organization o = (Organization)iter.Current; - Assert.AreEqual(o.Employments.Count, 3); + Assert.AreEqual(3, o.Employments.Count); foreach (Employment e in o.Employments) { diff --git a/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs b/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs index 5e91ba4870b..659f9eb4257 100644 --- a/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs @@ -26,8 +26,8 @@ public async Task ScalarStoredProcedureAsync() namedQuery.SetInt64("number", 43L); IList list = await (namedQuery.ListAsync()); object[] o = (object[])list[0]; - Assert.AreEqual(o[0], "getAll"); - Assert.AreEqual(o[1], 43L); + Assert.AreEqual("getAll", o[0]); + Assert.AreEqual(43L, o[1]); s.Close(); } @@ -41,16 +41,16 @@ public async Task ParameterHandlingAsync() namedQuery.SetInt64(1, 20L); IList list = await (namedQuery.ListAsync()); object[] o = (Object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); namedQuery = s.GetNamedQuery("paramhandling_mixed"); namedQuery.SetInt64(0, 10L); namedQuery.SetInt64("second", 20L); list = await (namedQuery.ListAsync()); o = (object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); s.Close(); } diff --git a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs index 6beefe2afa8..021c6e6761e 100644 --- a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs +++ b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs @@ -130,7 +130,7 @@ public async Task SQLQueryInterfaceAsync() .AddJoin("emp", "org.employments") .AddJoin("pers", "emp.employee") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); } @@ -146,7 +146,7 @@ public async Task SQLQueryInterfaceAsync() .AddJoin("emp", "org.employments") .SetResultTransformer(new DistinctRootEntityResultTransformer()) .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); await (t.CommitAsync()); s.Close(); @@ -183,7 +183,7 @@ public async Task SQLQueryInterfaceCacheableAsync() .AddJoin("pers", "emp.employee") .SetCacheable(true) .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); } @@ -200,7 +200,7 @@ public async Task SQLQueryInterfaceCacheableAsync() .SetCacheable(true) .SetResultTransformer(new DistinctRootEntityResultTransformer()) .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); await (t.CommitAsync()); s.Close(); @@ -478,12 +478,12 @@ public async Task ResultSetMappingDefinitionAsync() IList l = await (s.CreateSQLQuery(OrgEmpRegionSQL) .SetResultSetMapping("org-emp-regionCode") .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); l = await (s.CreateSQLQuery(OrgEmpPersonSQL) .SetResultSetMapping("org-emp-person") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); s.Close(); @@ -522,12 +522,12 @@ public async Task ScalarValuesAsync() IEnumerator iter = (await (s.GetNamedQuery("orgNamesAndOrgs").ListAsync())).GetEnumerator(); iter.MoveNext(); object[] o = (object[]) iter.Current; - Assert.AreEqual(o[0], "IFA"); - Assert.AreEqual(((Organization) o[1]).Name, "IFA"); + Assert.AreEqual("IFA", o[0]); + Assert.AreEqual("IFA", ((Organization) o[1]).Name); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[0], "JBoss"); - Assert.AreEqual(((Organization) o[1]).Name, "JBoss"); + Assert.AreEqual("JBoss", o[0]); + Assert.AreEqual("JBoss", ((Organization) o[1]).Name); await (t.CommitAsync()); s.Close(); @@ -542,13 +542,13 @@ public async Task ScalarValuesAsync() Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); Assert.AreEqual("IFA", ((Organization) row[0]).Name); - Assert.AreEqual(row[1], "IFA"); + Assert.AreEqual("IFA", row[1]); iter.MoveNext(); row = (object[]) iter.Current; Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); - Assert.AreEqual(((Organization) row[0]).Name, "JBoss"); - Assert.AreEqual(row[1], "JBoss"); + Assert.AreEqual("JBoss", ((Organization) row[0]).Name); + Assert.AreEqual("JBoss", row[1]); Assert.IsFalse(iter.MoveNext()); await (t.CommitAsync()); @@ -560,11 +560,11 @@ public async Task ScalarValuesAsync() iter = (await (s.GetNamedQuery("orgIdsAndOrgNames").ListAsync())).GetEnumerator(); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "IFA"); + Assert.AreEqual("IFA", o[1]); Assert.AreEqual(o[0], idIfa); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "JBoss"); + Assert.AreEqual("JBoss", o[1]); Assert.AreEqual(o[0], idJBoss); await (t.CommitAsync()); @@ -713,7 +713,7 @@ public async Task AutoDetectAliasingAsync() IQuery queryWithCollection = s.GetNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.SetInt64("id", jboss.Id); list = await (queryWithCollection.ListAsync()); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); s.Clear(); @@ -804,7 +804,7 @@ public async Task MixAndMatchEntityScalarAsync() IList l = await (s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech") .SetResultSetMapping("speech") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.RollbackAsync()); s.Close(); @@ -883,7 +883,7 @@ public async Task CanSetResultTransformerOnFutureQueryAsync() .SetResultTransformer(transformer) .Future(); - Assert.AreEqual((await (l.GetEnumerableAsync())).Count(), 1); + Assert.AreEqual(1, (await (l.GetEnumerableAsync())).Count()); Assert.AreEqual("Ricardo", (await (l.GetEnumerableAsync())).ElementAt(0)[0]); Assert.IsTrue(transformer.TransformListCalled); Assert.IsTrue(transformer.TransformTupleCalled); @@ -928,7 +928,7 @@ public async Task CanExecuteFutureListAsync() .CreateSQLQuery("select Name from Person") .Future(); - Assert.AreEqual((await (l.GetEnumerableAsync())).Count(), 1); + Assert.AreEqual(1, (await (l.GetEnumerableAsync())).Count()); Assert.AreEqual("Ricardo", (await (l.GetEnumerableAsync())).ElementAt(0)); } } diff --git a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs index 63543fd6f07..2aa47a1b95d 100644 --- a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs @@ -55,24 +55,24 @@ public async Task SubselectFetchHqlAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -120,24 +120,24 @@ public async Task SubselectFetchNamedParamAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -185,24 +185,24 @@ public async Task SubselectFetchPosParamAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -251,8 +251,8 @@ public async Task SubselectFetchWithLimitAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(0, p.MoreChildren.Count); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); @@ -261,8 +261,8 @@ public async Task SubselectFetchWithLimitAsync() r = (Parent) await (s.GetAsync(typeof(Parent), r.Name)); Assert.IsTrue(NHibernateUtil.IsInitialized(r.Children)); // The test for True is the test of H3.2 Assert.IsFalse(NHibernateUtil.IsInitialized(r.MoreChildren)); - Assert.AreEqual(r.Children.Count, 1); - Assert.AreEqual(r.MoreChildren.Count, 0); + Assert.AreEqual(1, r.Children.Count); + Assert.AreEqual(0, r.MoreChildren.Count); await (s.DeleteAsync(p)); await (s.DeleteAsync(q)); @@ -344,24 +344,24 @@ public async Task SubselectFetchCriteriaAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); diff --git a/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs b/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs index 0c2466f902f..e6af17d146c 100644 --- a/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs +++ b/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs @@ -83,7 +83,7 @@ public async Task SaveAsync() "Default value should have been mapped to null"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_TWO")) == DBNull.Value, "Default value should have been mapped to null"); - Assert.AreEqual(Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), 5, + Assert.AreEqual(5, Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), "Non-Default value should not be changed"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_FOUR")) == DBNull.Value, "Default value should have been mapped to null"); @@ -105,17 +105,17 @@ public async Task LoadingAsync() Widget obj = (Widget) await (s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-normal").UniqueResultAsync()); - Assert.AreEqual(obj.ValueOne, 7, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 8, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, 9, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, 10, "Non-Default value incorrectly loaded"); + Assert.AreEqual(7, obj.ValueOne, "Non-Default value incorrectly loaded"); + Assert.AreEqual(8, obj.ValueTwo, "Non-Default value incorrectly loaded"); + Assert.AreEqual(9, obj.ValueThree, "Non-Default value incorrectly loaded"); + Assert.AreEqual(10, obj.ValueFour, "Non-Default value incorrectly loaded"); obj = (Widget) await (s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-default").UniqueResultAsync()); - Assert.AreEqual(obj.ValueOne, 1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 2, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, -1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, -5, "Default value incorrectly loaded"); + Assert.AreEqual(1, obj.ValueOne, "Default value incorrectly loaded"); + Assert.AreEqual(2, obj.ValueTwo, "Default value incorrectly loaded"); + Assert.AreEqual(-1, obj.ValueThree, "Default value incorrectly loaded"); + Assert.AreEqual(-5, obj.ValueFour, "Default value incorrectly loaded"); await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs b/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs index 21d783bac12..05def0554b6 100644 --- a/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs +++ b/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs @@ -66,7 +66,7 @@ public async Task UnionSubclassCollectionAsync() using (ITransaction t = s.BeginTransaction()) { Human gavin = (Human)await (s.CreateCriteria(typeof(Human)).UniqueResultAsync()); - Assert.AreEqual(gavin.Info.Count, 2); + Assert.AreEqual(2, gavin.Info.Count); await (s.DeleteAsync(gavin)); await (s.DeleteAsync(gavin.Location)); await (t.CommitAsync()); diff --git a/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs b/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs index 78a298f9d0c..b47e8e6f856 100644 --- a/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs +++ b/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs @@ -48,7 +48,7 @@ public async System.Threading.Tasks.Task VersionShortCircuitFlushAsync() await (t.CommitAsync()); s.Close(); - Assert.AreEqual(passp.Version, 2); + Assert.AreEqual(2, passp.Version); s = OpenSession(); t = s.BeginTransaction(); diff --git a/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs b/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs index 86a91e709d8..e2192233234 100644 --- a/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs +++ b/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs @@ -187,8 +187,8 @@ public void MultipleCollectionFetch() Assert.AreEqual(2, c.Orders.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[0]).LineItems)); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[1]).LineItems)); - Assert.AreEqual(((Order) c.Orders[0]).LineItems.Count, 2); - Assert.AreEqual(((Order) c.Orders[1]).LineItems.Count, 2); + Assert.AreEqual(2, ((Order) c.Orders[0]).LineItems.Count); + Assert.AreEqual(2, ((Order) c.Orders[1]).LineItems.Count); t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs index 63a22533aa1..2b27d8a2120 100644 --- a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs @@ -3216,7 +3216,7 @@ public void CanSetLockModeOnDetachedCriteria() var countExec = CriteriaTransformer.TransformToRowCount(ec); var countRes = countExec.UniqueResult(); - Assert.AreEqual(countRes, 1); + Assert.AreEqual(1, countRes); } } } diff --git a/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs b/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs index 19ad76bc17b..c32811972ec 100644 --- a/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs +++ b/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs @@ -81,7 +81,7 @@ private void AssertDictionariesAreEqual(IDictionary expected, IDictionary actual foreach (object key in expected.Keys) { if (!actual.Contains(key)) - Assert.AreEqual(key, null, _fieldPath.Peek() + "[" + key.ToString() + "]"); + Assert.AreEqual(null, key, _fieldPath.Peek() + "[" + key.ToString() + "]"); AssertObjectsAreEqual(expected[key], actual[key], "[" + key.ToString() + "]"); } diff --git a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs index a23d9f1d833..bcd00d7c9e5 100644 --- a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs @@ -336,7 +336,7 @@ public void SelectModeFetchLazyPropertiesForEntityJoin() Assert.That(NHibernateUtil.IsInitialized(rootChild), Is.True); Assert.That(NHibernateUtil.IsInitialized(parentJoin), Is.True); - Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.Not.Null.Or.Empty); + Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.True); Assert.That(parentJoin.LazyProp, Is.Not.Null.Or.Empty); Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected"); diff --git a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs index 4867332b8c4..eab82736533 100644 --- a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs +++ b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs @@ -63,9 +63,9 @@ public void QueryTestWithStrongTypeReturnValue() .Add(Projections.Min("Pay"))); c.SetResultTransformer(trans); ProjectionReport report = c.UniqueResult(); - Assert.AreEqual(report.AvgPay, 2.5); - Assert.AreEqual(report.MaxPay, 4); - Assert.AreEqual(report.MinPay, 1); + Assert.AreEqual(2.5, report.AvgPay); + Assert.AreEqual(4, report.MaxPay); + Assert.AreEqual(1, report.MinPay); } } @@ -86,10 +86,10 @@ public void QueryTest1() Assert.IsTrue(result[0] is object[], "expected object[] as result, but found " + result[0].GetType().Name); object[] results = (object[])result[0]; - Assert.AreEqual(results.Length, 3); - Assert.AreEqual(results[0], 2.5); - Assert.AreEqual(results[1], 4); - Assert.AreEqual(results[2], 1); + Assert.AreEqual(3, results.Length); + Assert.AreEqual(2.5, results[0]); + Assert.AreEqual(4, results[1]); + Assert.AreEqual(1, results[2]); } } @@ -108,7 +108,7 @@ public void SelectSqlProjectionTest() IList result = c.List(); // c.UniqueResult(); Assert.IsTrue(result.Count == 1); object results = result[0]; - Assert.AreEqual(results, 2.5); + Assert.AreEqual(2.5, results); } } } diff --git a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs index edbff2a5a25..67f96306bc1 100644 --- a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs +++ b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs @@ -96,7 +96,7 @@ public void CombinedClassAndCollectionFiltersEnabled() salespersons = session.CreateQuery("select s from Salesperson as s left join fetch s.Orders").List(); Assert.AreEqual(1, salespersons.Count, "Incorrect salesperson count"); sp = (Salesperson) salespersons[0]; - Assert.AreEqual(sp.Orders.Count, 1, "Incorrect order count"); + Assert.AreEqual(1, sp.Orders.Count, "Incorrect order count"); } } diff --git a/src/NHibernate.Test/FilterTest/FilterConfig.cs b/src/NHibernate.Test/FilterTest/FilterConfig.cs index 26c5d590aeb..d7e67d8952a 100644 --- a/src/NHibernate.Test/FilterTest/FilterConfig.cs +++ b/src/NHibernate.Test/FilterTest/FilterConfig.cs @@ -15,13 +15,13 @@ public void FilterDefinitionsLoadedCorrectly() { Configuration cfg = new Configuration(); cfg.AddResource(mappingCfg, this.GetType().Assembly); - Assert.AreEqual(cfg.FilterDefinitions.Count, 2); + Assert.AreEqual(2, cfg.FilterDefinitions.Count); Assert.IsTrue(cfg.FilterDefinitions.ContainsKey("LiveFilter")); FilterDefinition f = cfg.FilterDefinitions["LiveFilter"]; - Assert.AreEqual(f.ParameterTypes.Count, 1); + Assert.AreEqual(1, f.ParameterTypes.Count); BooleanType t = f.ParameterTypes["LiveParam"] as BooleanType; @@ -40,7 +40,7 @@ public void FiltersLoaded() IFilter filter = session.EnableFilter("LiveFilter"); - Assert.AreEqual(filter.FilterDefinition.FilterName, "LiveFilter"); + Assert.AreEqual("LiveFilter", filter.FilterDefinition.FilterName); filter.SetParameter("LiveParam", true); diff --git a/src/NHibernate.Test/Legacy/FooBarTest.cs b/src/NHibernate.Test/Legacy/FooBarTest.cs index 9704b5dc737..17bf3d8a317 100644 --- a/src/NHibernate.Test/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Legacy/FooBarTest.cs @@ -1066,8 +1066,8 @@ public void PropertyRef() using (ISession s = OpenSession()) { Holder h = (Holder) s.Load(typeof(Holder), hid); - Assert.AreEqual(h.Name, "foo"); - Assert.AreEqual(h.OtherHolder.Name, "bar"); + Assert.AreEqual("foo", h.Name); + Assert.AreEqual("bar", h.OtherHolder.Name); object[] res = (object[]) s.CreateQuery("from Holder h join h.OtherHolder oh where h.OtherHolder.Name = 'bar'").List()[0]; Assert.AreSame(h, res[0]); @@ -1418,7 +1418,7 @@ public void Sortables() // DictionaryEntry key - not the index. foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } @@ -1434,7 +1434,7 @@ public void Sortables() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } s.Flush(); @@ -1449,7 +1449,7 @@ public void Sortables() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } s.Delete(b); diff --git a/src/NHibernate.Test/Legacy/MasterDetailTest.cs b/src/NHibernate.Test/Legacy/MasterDetailTest.cs index d07d30af15a..94d0253eaf9 100644 --- a/src/NHibernate.Test/Legacy/MasterDetailTest.cs +++ b/src/NHibernate.Test/Legacy/MasterDetailTest.cs @@ -183,7 +183,7 @@ public void CopyCascade() // Save parent and cascade update detached child Category persistentParent = s.Merge(parent); Assert.IsTrue(persistentParent.Subcategories.Count == 1); - Assert.AreEqual(((Category) persistentParent.Subcategories[0]).Name, "child2"); + Assert.AreEqual("child2", ((Category) persistentParent.Subcategories[0]).Name); s.Flush(); s.Close(); diff --git a/src/NHibernate.Test/Legacy/SQLLoaderTest.cs b/src/NHibernate.Test/Legacy/SQLLoaderTest.cs index 5818a4f9909..75b4e71d289 100644 --- a/src/NHibernate.Test/Legacy/SQLLoaderTest.cs +++ b/src/NHibernate.Test/Legacy/SQLLoaderTest.cs @@ -520,7 +520,7 @@ private void ComponentTest(string sql) IQuery q = session.CreateSQLQuery(sql).AddEntity("comp", typeof(Componentizable)); IList list = q.List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); Componentizable co = (Componentizable) list[0]; diff --git a/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs b/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs index e576587cc01..b55a87f2d15 100644 --- a/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs @@ -13,7 +13,7 @@ public void CanGetAverageOfIntegersAsDouble() //NH-2429 var average = db.Products.Average(x => x.UnitsOnOrder); - Assert.AreEqual(average, 10.129870d, 0.000001d); + Assert.AreEqual(10.129870d, average, 0.000001d); } } } diff --git a/src/NHibernate.Test/Linq/PagingTests.cs b/src/NHibernate.Test/Linq/PagingTests.cs index b92abec5404..b5cbc78fab2 100644 --- a/src/NHibernate.Test/Linq/PagingTests.cs +++ b/src/NHibernate.Test/Linq/PagingTests.cs @@ -229,7 +229,7 @@ public void Customers11to20() var query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); } @@ -239,19 +239,19 @@ public void Customers11to20And21to30ShouldNoCacheQuery() var query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(20).Take(10).ToList(); - Assert.AreNotEqual(query[0], "BSBEV"); + Assert.AreNotEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(20).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(20, query.Count); } @@ -276,7 +276,7 @@ public void CustomersChainedSkip() { var q = (from c in db.Customers select c.CustomerId).Skip(10).Skip(5); var query = q.ToList(); - Assert.AreEqual(query[0], "CONSH"); + Assert.AreEqual("CONSH", query[0]); Assert.AreEqual(76, query.Count); } diff --git a/src/NHibernate.Test/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Linq/PreEvaluationTests.cs index 4e12c4b9d82..9284938842d 100644 --- a/src/NHibernate.Test/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Linq/PreEvaluationTests.cs @@ -323,7 +323,7 @@ public void CanSelectRandomDouble() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1)); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(1)); if (!LegacyPreEvaluation && IsFunctionSupported("random")) { @@ -380,7 +380,7 @@ public void CanSelectRandomInt() var randomValues = x.Select(o => o.r).Distinct().ToArray(); Assert.That( randomValues, - Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf()); + Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(int.MaxValue).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { @@ -436,7 +436,7 @@ public void CanSelectRandomIntWithMax() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf()); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(10).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { @@ -492,7 +492,7 @@ public void CanSelectRandomIntWithMinMax() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf()); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.All.LessThan(11).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs index 39e9075ed3a..b408efda7e2 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs @@ -33,7 +33,7 @@ public void AbstractClass() ca.Property(x => x.Something, map => map.Length(150)); }); var hbmMapping = mapper.CompileMappingFor(new[] { typeof(MyClass) }); - Assert.AreEqual(hbmMapping.RootClasses[0].@abstract, true); + Assert.AreEqual(true, hbmMapping.RootClasses[0].@abstract); } [Test] diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs index 2436fcb9890..e710636cab0 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs @@ -41,7 +41,7 @@ public void CanSpecifyUnsavedValue() var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); - Assert.AreEqual(mapping.RootClasses[0].CompositeId.unsavedvalue, HbmUnsavedValueType.Any); + Assert.AreEqual(HbmUnsavedValueType.Any, mapping.RootClasses[0].CompositeId.unsavedvalue); } [Test] diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs index 6a49c66f20b..82031d04c08 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs @@ -26,7 +26,7 @@ public void OptimisticLockModeTest() }); var mappings = mapper.CompileMappingForAllExplicitlyAddedEntities(); - Assert.AreEqual(mappings.RootClasses[0].optimisticlock, HbmOptimisticLockMode.Dirty); + Assert.AreEqual(HbmOptimisticLockMode.Dirty, mappings.RootClasses[0].optimisticlock); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs b/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs index 4a1a1b405ce..cf2eefe2018 100644 --- a/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs +++ b/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs @@ -20,7 +20,7 @@ public void CanSetPolymorphism() var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); var entity = mapping.RootClasses[0]; - Assert.AreEqual(entity.polymorphism, HbmPolymorphismType.Explicit); + Assert.AreEqual(HbmPolymorphismType.Explicit, entity.polymorphism); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs b/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs index 81ed2e127b6..e9090db461d 100644 --- a/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs +++ b/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs @@ -343,7 +343,7 @@ public void MergeSplitDefinitions() source.AddAsPropertySplit(new SplitDefinition(typeof (MyClass), "foo", property)); destination.Merge(source); - Assert.That(destination.SplitDefinitions, Has.Count.EqualTo(1)); + Assert.That(destination.SplitDefinitions.Count(), Is.EqualTo(1)); } [Test] @@ -354,7 +354,7 @@ public void MergePersistentMembers() source.AddAsPersistentMember(property); destination.Merge(source); - Assert.That(destination.PersistentMembers, Has.Count.EqualTo(1)); + Assert.That(destination.PersistentMembers.Count(), Is.EqualTo(1)); } [Test] @@ -365,7 +365,7 @@ public void MergeProperties() source.AddAsProperty(property); destination.Merge(source); - Assert.That(destination.Properties, Has.Count.EqualTo(1)); + Assert.That(destination.Properties.Count(), Is.EqualTo(1)); } [Test] @@ -376,7 +376,7 @@ public void MergeDictionaries() source.AddAsMap(property); destination.Merge(source); - Assert.That(destination.Dictionaries, Has.Count.EqualTo(1)); + Assert.That(destination.Dictionaries.Count(), Is.EqualTo(1)); } [Test] @@ -387,7 +387,7 @@ public void MergeArrays() source.AddAsArray(property); destination.Merge(source); - Assert.That(destination.Arrays, Has.Count.EqualTo(1)); + Assert.That(destination.Arrays.Count(), Is.EqualTo(1)); } [Test] @@ -398,7 +398,7 @@ public void MergeLists() source.AddAsList(property); destination.Merge(source); - Assert.That(destination.Lists, Has.Count.EqualTo(1)); + Assert.That(destination.Lists.Count(), Is.EqualTo(1)); } [Test] @@ -409,7 +409,7 @@ public void MergeIdBags() source.AddAsIdBag(property); destination.Merge(source); - Assert.That(destination.IdBags, Has.Count.EqualTo(1)); + Assert.That(destination.IdBags.Count(), Is.EqualTo(1)); } [Test] @@ -420,7 +420,7 @@ public void MergeBags() source.AddAsBag(property); destination.Merge(source); - Assert.That(destination.Bags, Has.Count.EqualTo(1)); + Assert.That(destination.Bags.Count(), Is.EqualTo(1)); } [Test] @@ -431,7 +431,7 @@ public void MergeSets() source.AddAsSet(property); destination.Merge(source); - Assert.That(destination.Sets, Has.Count.EqualTo(1)); + Assert.That(destination.Sets.Count(), Is.EqualTo(1)); } [Test] @@ -442,7 +442,7 @@ public void MergeNaturalIds() source.AddAsNaturalId(property); destination.Merge(source); - Assert.That(destination.NaturalIds, Has.Count.EqualTo(1)); + Assert.That(destination.NaturalIds.Count(), Is.EqualTo(1)); } [Test] @@ -453,7 +453,7 @@ public void MergeVersionProperties() source.AddAsVersionProperty(property); destination.Merge(source); - Assert.That(destination.VersionProperties, Has.Count.EqualTo(1)); + Assert.That(destination.VersionProperties.Count(), Is.EqualTo(1)); } [Test] @@ -464,7 +464,7 @@ public void MergePoids() source.AddAsPoid(property); destination.Merge(source); - Assert.That(destination.Poids, Has.Count.EqualTo(1)); + Assert.That(destination.Poids.Count(), Is.EqualTo(1)); } [Test] @@ -475,7 +475,7 @@ public void MergeAny() source.AddAsAny(property); destination.Merge(source); - Assert.That(destination.Any, Has.Count.EqualTo(1)); + Assert.That(destination.Any.Count(), Is.EqualTo(1)); } [Test] @@ -486,7 +486,7 @@ public void MergeOneToManyRelations() source.AddAsOneToManyRelation(property); destination.Merge(source); - Assert.That(destination.OneToManyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.OneToManyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -497,7 +497,7 @@ public void MergeManyToAnyRelations() source.AddAsManyToAnyRelation(property); destination.Merge(source); - Assert.That(destination.ManyToAnyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ManyToAnyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -508,7 +508,7 @@ public void MergeManyToManyRelations() source.AddAsManyToManyItemRelation(property); destination.Merge(source); - Assert.That(destination.ItemManyToManyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ItemManyToManyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -519,7 +519,7 @@ public void MergeManyToOneRelations() source.AddAsManyToOneRelation(property); destination.Merge(source); - Assert.That(destination.ManyToOneRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ManyToOneRelations.Count(), Is.EqualTo(1)); } [Test] @@ -530,7 +530,7 @@ public void MergeOneToOneRelations() source.AddAsOneToOneRelation(property); destination.Merge(source); - Assert.That(destination.OneToOneRelations, Has.Count.EqualTo(1)); + Assert.That(destination.OneToOneRelations.Count(), Is.EqualTo(1)); } [Test] @@ -541,7 +541,7 @@ public void MergeTablePerConcreteClassEntities() source.AddAsTablePerConcreteClassEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerConcreteClassEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerConcreteClassEntities.Count(), Is.EqualTo(1)); } [Test] @@ -552,7 +552,7 @@ public void MergeTablePerClassHierarchyEntities() source.AddAsTablePerClassHierarchyEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerClassHierarchyEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerClassHierarchyEntities.Count(), Is.EqualTo(1)); } [Test] @@ -563,7 +563,7 @@ public void MergeTablePerClassEntities() source.AddAsTablePerClassEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerClassEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerClassEntities.Count(), Is.EqualTo(1)); } [Test] @@ -574,7 +574,7 @@ public void MergeComponents() source.AddAsComponent(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.Components, Has.Count.EqualTo(1)); + Assert.That(destination.Components.Count(), Is.EqualTo(1)); } [Test] @@ -585,7 +585,7 @@ public void MergeRootEntities() source.AddAsRootEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.RootEntities, Has.Count.EqualTo(1)); + Assert.That(destination.RootEntities.Count(), Is.EqualTo(1)); } [Test] @@ -596,7 +596,7 @@ public void MergeDynamicComponents() source.AddAsDynamicComponent(property, typeof(MyClass)); destination.Merge(source); - Assert.That(destination.DynamicComponents, Has.Count.EqualTo(1)); + Assert.That(destination.DynamicComponents.Count(), Is.EqualTo(1)); Assert.That(destination.GetDynamicComponentTemplate(property), Is.EqualTo(typeof(MyClass))); } @@ -608,7 +608,7 @@ public void MergeComposedId() source.AddAsPartOfComposedId(property); destination.Merge(source); - Assert.That(destination.ComposedIds, Has.Count.EqualTo(1)); + Assert.That(destination.ComposedIds.Count(), Is.EqualTo(1)); } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs index 4b57f08e186..eb3afa36f6a 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -74,7 +75,7 @@ public void CanAddChildAfterFlush() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -92,7 +93,7 @@ public void CanAddChildAfterFlushWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -120,7 +121,7 @@ public void CanMergeWithTransientChild() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -141,7 +142,7 @@ public void CanMergeWithTransientChildWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -167,7 +168,7 @@ public void CanChangeOwnershipOnFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -180,7 +181,7 @@ public void CanChangeOwnershipOnFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -203,7 +204,7 @@ public void CanChangeOwnershipOnFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -216,7 +217,7 @@ public void CanChangeOwnershipOnFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -242,7 +243,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -255,7 +256,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -278,7 +279,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -291,7 +292,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -317,7 +318,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -330,7 +331,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -353,7 +354,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -366,7 +367,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -392,7 +393,7 @@ public void CanChangeOwnershipOnNonFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -405,7 +406,7 @@ public void CanChangeOwnershipOnNonFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -428,7 +429,7 @@ public void CanChangeOwnershipOnNonFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -441,7 +442,7 @@ public void CanChangeOwnershipOnNonFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs index ae2d5b7f395..5327df58c05 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs @@ -226,7 +226,7 @@ public void QueryMapElements() var a = query.UniqueResult(); - Assert.AreEqual(a.C[1], "Text1"); + Assert.AreEqual("Text1", a.C[1]); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs index 0bad20e6fc7..5a321fe4ce0 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs @@ -94,9 +94,9 @@ public void CanOrderBySubqueryProjection() // Oracle order NULL Last (ASC) nullRelationOffSet = 0; } - Assert.AreEqual(list[nullRelationOffSet].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet + 1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet + 2].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet + 1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet + 2].Name); } } } @@ -122,9 +122,9 @@ public void CanOrderBySubqueryProjectionDesc() // Oracle order NULL First (DESC) nullRelationOffSet = 2; } - Assert.AreEqual(list[nullRelationOffSet+2].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet+1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet+2].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet+1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet].Name); } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs index aa30ea8509b..590e5d740d7 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs @@ -28,7 +28,7 @@ public void Bug() ICriteria icriteria = criteria.GetExecutableCriteria(session); icriteria.SetFirstResult(0); icriteria.SetMaxResults(2); - Assert.That(2, Is.EqualTo(icriteria.List().Count)); + Assert.That(icriteria.List().Count, Is.EqualTo(2)); } using (ISession session = OpenSession()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs index 5e0a028dc7a..9f5ad5e4bd5 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs @@ -52,7 +52,7 @@ public void TestAction(System.Action action) action.Invoke(criteria); IList l = criteria.GetExecutableCriteria(session).List(); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs index 1673fde4fb4..aa1fa121ea9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs @@ -61,7 +61,7 @@ public void TestAction(System.Action action) action.Invoke(criteria); IList l = criteria.GetExecutableCriteria(session).List(); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs index 2d832cb4149..f6fe534150f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs @@ -30,13 +30,9 @@ from Entity Regex whitespaces = new Regex(@"\s+", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); - Assert.AreEqual( - string.Compare( - whitespaces.Replace(sql, " ").Trim(), - whitespaces.Replace(renderedSql, " ").Trim(), - true - ), - 0 + Assert.That( + whitespaces.Replace(renderedSql, " ").Trim(), + Is.EqualTo(whitespaces.Replace(sql, " ").Trim()).IgnoreCase ); } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs index eb9a41f560b..e4a534f7f0e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs @@ -33,7 +33,7 @@ public void NativeQueryWithTwoComments() IQuery qry = session.CreateSQLQuery("select /* first comment */ o.* /* second comment*/ from domainclass o") .AddEntity("o", typeof (DomainClass)); var res = qry.List(); - Assert.AreEqual(res[0].Id, 1); + Assert.AreEqual(1, res[0].Id); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs index 6871ca6e2dd..ce746a5b383 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs @@ -27,7 +27,7 @@ public void ConstrainedLazyLoadedOneToOneUsingCastleProxy() Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.False); - Assert.That("Person1", Is.EqualTo(employee.Person.Name)); + Assert.That(employee.Person.Name, Is.EqualTo("Person1")); Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.True); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs index fefdf3254d3..5c303be7b17 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs @@ -76,7 +76,7 @@ public void CanUseFieldInterceptingProxyAsHQLArgument() .SetEntity("p", person) .List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); } } finally diff --git a/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs index 706eb379177..bc0f382f6a2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs @@ -41,7 +41,7 @@ private static void RunTest(TestSqlClientDriver driver) unusedParam.ParameterName = driver.FormatNameForParameter("unused"); command.Parameters.Add(unusedParam); - Assert.AreEqual(command.Parameters.Count, 2); + Assert.AreEqual(2, command.Parameters.Count); SqlString sqlString = new SqlStringBuilder() .AddParameter() @@ -49,7 +49,7 @@ private static void RunTest(TestSqlClientDriver driver) driver.RemoveUnusedCommandParameters(command, sqlString); - Assert.AreEqual(command.Parameters.Count, 1); + Assert.AreEqual(1, command.Parameters.Count); Assert.AreEqual(command.Parameters[0], usedParam); } diff --git a/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs b/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs index 4bbcca81380..ac86449cde3 100644 --- a/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs @@ -61,7 +61,7 @@ public void MappingOuterJoin() Assert.IsNull(p2.Address); Assert.IsNotNull(p.Address); var l = s.CreateQuery("from Person").List(); //pull address references for cache - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsTrue(l.Contains(p) && l.Contains(p2)); } } @@ -75,7 +75,7 @@ public void AddressBySequentialSelect() using (s.BeginTransaction()) { var l = s.CreateQuery("from Person p order by p.Name").List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsNull(l[0].Address); Assert.IsNotNull(l[1].Address); } @@ -90,7 +90,7 @@ public void AddressOuterJoin() using (s.BeginTransaction()) { var l = s.CreateQuery("from Person p left join fetch p.Address a order by a.Country").List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); if (l[0].Name.Equals("Max")) { Assert.IsNull(l[0].Address); @@ -135,11 +135,11 @@ public void AccountsOuterJoinVerifyInitialization() var l = s.CreateQuery("from Person p left join fetch p.Accounts a order by p.Name").List(); var p0 = l[0]; Assert.IsTrue(NHibernateUtil.IsInitialized(p0.Accounts)); - Assert.AreEqual(p0.Accounts.Count, 1); + Assert.AreEqual(1, p0.Accounts.Count); Assert.AreSame(p0.Accounts.First().User, p0); var p1 = l[1]; Assert.IsTrue(NHibernateUtil.IsInitialized(p1.Accounts)); - Assert.AreEqual(p1.Accounts.Count, 0); + Assert.AreEqual(0, p1.Accounts.Count); } } } diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 5a3b08cdfc5..2ae6cf60202 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -70,6 +70,7 @@ + diff --git a/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs index 3275ed54041..df244dff0eb 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs @@ -434,7 +434,8 @@ public void ParameterPropertyShouldReturnNewInstances() Assert.IsNull(parameters2[0].ParameterPosition); // more simple version of the test - Assert.That(Parameter.Placeholder, Is.Not.SameAs(Parameter.Placeholder)); + var placeholder = Parameter.Placeholder; + Assert.That(placeholder, Is.Not.SameAs(Parameter.Placeholder)); } [Test] diff --git a/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs b/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs index 8ee760763c3..79a157d4086 100644 --- a/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs +++ b/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs @@ -48,10 +48,10 @@ public void HandSQL() s = OpenSession(); t = s.BeginTransaction(); jboss = (Organization)s.Get(typeof(Organization), orgId); - Assert.AreEqual(jboss.Employments.Count, 2); + Assert.AreEqual(2, jboss.Employments.Count); emp = (Employment)GetFirstItem(jboss.Employments); gavin = emp.Employee; - Assert.AreEqual(gavin.Name, "GAVIN"); + Assert.AreEqual("GAVIN", gavin.Name); Assert.AreEqual(s.GetCurrentLockMode(gavin), LockMode.Upgrade); emp.EndDate = DateTime.Today; Employment emp3 = new Employment(gavin, jboss, "US"); @@ -64,7 +64,7 @@ public void HandSQL() IEnumerator iter = s.GetNamedQuery("allOrganizationsWithEmployees").List().GetEnumerator(); Assert.IsTrue(iter.MoveNext()); Organization o = (Organization)iter.Current; - Assert.AreEqual(o.Employments.Count, 3); + Assert.AreEqual(3, o.Employments.Count); foreach (Employment e in o.Employments) { diff --git a/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs b/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs index 73bb920d571..e965bf6362f 100644 --- a/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs +++ b/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs @@ -15,8 +15,8 @@ public void ScalarStoredProcedure() namedQuery.SetInt64("number", 43L); IList list = namedQuery.List(); object[] o = (object[])list[0]; - Assert.AreEqual(o[0], "getAll"); - Assert.AreEqual(o[1], 43L); + Assert.AreEqual("getAll", o[0]); + Assert.AreEqual(43L, o[1]); s.Close(); } @@ -30,16 +30,16 @@ public void ParameterHandling() namedQuery.SetInt64(1, 20L); IList list = namedQuery.List(); object[] o = (Object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); namedQuery = s.GetNamedQuery("paramhandling_mixed"); namedQuery.SetInt64(0, 10L); namedQuery.SetInt64("second", 20L); list = namedQuery.List(); o = (object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); s.Close(); } diff --git a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs index 38c395298df..26cadf8f47f 100644 --- a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs +++ b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs @@ -119,7 +119,7 @@ public void SQLQueryInterface() .AddJoin("emp", "org.employments") .AddJoin("pers", "emp.employee") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); } @@ -135,7 +135,7 @@ public void SQLQueryInterface() .AddJoin("emp", "org.employments") .SetResultTransformer(new DistinctRootEntityResultTransformer()) .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); t.Commit(); s.Close(); @@ -172,7 +172,7 @@ public void SQLQueryInterfaceCacheable() .AddJoin("pers", "emp.employee") .SetCacheable(true) .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); } @@ -189,7 +189,7 @@ public void SQLQueryInterfaceCacheable() .SetCacheable(true) .SetResultTransformer(new DistinctRootEntityResultTransformer()) .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); t.Commit(); s.Close(); @@ -460,12 +460,12 @@ public void ResultSetMappingDefinition() IList l = s.CreateSQLQuery(OrgEmpRegionSQL) .SetResultSetMapping("org-emp-regionCode") .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); l = s.CreateSQLQuery(OrgEmpPersonSQL) .SetResultSetMapping("org-emp-person") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); s.Close(); @@ -504,12 +504,12 @@ public void ScalarValues() IEnumerator iter = s.GetNamedQuery("orgNamesAndOrgs").List().GetEnumerator(); iter.MoveNext(); object[] o = (object[]) iter.Current; - Assert.AreEqual(o[0], "IFA"); - Assert.AreEqual(((Organization) o[1]).Name, "IFA"); + Assert.AreEqual("IFA", o[0]); + Assert.AreEqual("IFA", ((Organization) o[1]).Name); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[0], "JBoss"); - Assert.AreEqual(((Organization) o[1]).Name, "JBoss"); + Assert.AreEqual("JBoss", o[0]); + Assert.AreEqual("JBoss", ((Organization) o[1]).Name); t.Commit(); s.Close(); @@ -524,13 +524,13 @@ public void ScalarValues() Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); Assert.AreEqual("IFA", ((Organization) row[0]).Name); - Assert.AreEqual(row[1], "IFA"); + Assert.AreEqual("IFA", row[1]); iter.MoveNext(); row = (object[]) iter.Current; Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); - Assert.AreEqual(((Organization) row[0]).Name, "JBoss"); - Assert.AreEqual(row[1], "JBoss"); + Assert.AreEqual("JBoss", ((Organization) row[0]).Name); + Assert.AreEqual("JBoss", row[1]); Assert.IsFalse(iter.MoveNext()); t.Commit(); @@ -542,11 +542,11 @@ public void ScalarValues() iter = s.GetNamedQuery("orgIdsAndOrgNames").List().GetEnumerator(); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "IFA"); + Assert.AreEqual("IFA", o[1]); Assert.AreEqual(o[0], idIfa); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "JBoss"); + Assert.AreEqual("JBoss", o[1]); Assert.AreEqual(o[0], idJBoss); t.Commit(); @@ -769,7 +769,7 @@ public void AutoDetectAliasing() IQuery queryWithCollection = s.GetNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.SetInt64("id", jboss.Id); list = queryWithCollection.List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); s.Clear(); @@ -860,7 +860,7 @@ public void MixAndMatchEntityScalar() IList l = s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech") .SetResultSetMapping("speech") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Rollback(); s.Close(); @@ -939,7 +939,7 @@ public void CanSetResultTransformerOnFutureQuery() .SetResultTransformer(transformer) .Future(); - Assert.AreEqual(l.GetEnumerable().Count(), 1); + Assert.AreEqual(1, l.GetEnumerable().Count()); Assert.AreEqual("Ricardo", l.GetEnumerable().ElementAt(0)[0]); Assert.IsTrue(transformer.TransformListCalled); Assert.IsTrue(transformer.TransformTupleCalled); @@ -984,7 +984,7 @@ public void CanExecuteFutureList() .CreateSQLQuery("select Name from Person") .Future(); - Assert.AreEqual(l.GetEnumerable().Count(), 1); + Assert.AreEqual(1, l.GetEnumerable().Count()); Assert.AreEqual("Ricardo", l.GetEnumerable().ElementAt(0)); } } diff --git a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs index 9fd00d6e6c6..3b60b3367a1 100644 --- a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs @@ -44,24 +44,24 @@ public void SubselectFetchHql() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -109,24 +109,24 @@ public void SubselectFetchNamedParam() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -174,24 +174,24 @@ public void SubselectFetchPosParam() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -240,8 +240,8 @@ public void SubselectFetchWithLimit() Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(0, p.MoreChildren.Count); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); @@ -250,8 +250,8 @@ public void SubselectFetchWithLimit() r = (Parent) s.Get(typeof(Parent), r.Name); Assert.IsTrue(NHibernateUtil.IsInitialized(r.Children)); // The test for True is the test of H3.2 Assert.IsFalse(NHibernateUtil.IsInitialized(r.MoreChildren)); - Assert.AreEqual(r.Children.Count, 1); - Assert.AreEqual(r.MoreChildren.Count, 0); + Assert.AreEqual(1, r.Children.Count); + Assert.AreEqual(0, r.MoreChildren.Count); s.Delete(p); s.Delete(q); @@ -333,24 +333,24 @@ public void SubselectFetchCriteria() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); diff --git a/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs b/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs index c84a4e83415..00176694879 100644 --- a/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs +++ b/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs @@ -71,7 +71,7 @@ public void Save() "Default value should have been mapped to null"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_TWO")) == DBNull.Value, "Default value should have been mapped to null"); - Assert.AreEqual(Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), 5, + Assert.AreEqual(5, Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), "Non-Default value should not be changed"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_FOUR")) == DBNull.Value, "Default value should have been mapped to null"); @@ -93,17 +93,17 @@ public void Loading() Widget obj = (Widget) s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-normal").UniqueResult(); - Assert.AreEqual(obj.ValueOne, 7, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 8, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, 9, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, 10, "Non-Default value incorrectly loaded"); + Assert.AreEqual(7, obj.ValueOne, "Non-Default value incorrectly loaded"); + Assert.AreEqual(8, obj.ValueTwo, "Non-Default value incorrectly loaded"); + Assert.AreEqual(9, obj.ValueThree, "Non-Default value incorrectly loaded"); + Assert.AreEqual(10, obj.ValueFour, "Non-Default value incorrectly loaded"); obj = (Widget) s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-default").UniqueResult(); - Assert.AreEqual(obj.ValueOne, 1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 2, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, -1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, -5, "Default value incorrectly loaded"); + Assert.AreEqual(1, obj.ValueOne, "Default value incorrectly loaded"); + Assert.AreEqual(2, obj.ValueTwo, "Default value incorrectly loaded"); + Assert.AreEqual(-1, obj.ValueThree, "Default value incorrectly loaded"); + Assert.AreEqual(-5, obj.ValueFour, "Default value incorrectly loaded"); t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs b/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs index 8a72e49d29b..e58dad4d1cb 100644 --- a/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs +++ b/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs @@ -55,7 +55,7 @@ public void UnionSubclassCollection() using (ITransaction t = s.BeginTransaction()) { Human gavin = (Human)s.CreateCriteria(typeof(Human)).UniqueResult(); - Assert.AreEqual(gavin.Info.Count, 2); + Assert.AreEqual(2, gavin.Info.Count); s.Delete(gavin); s.Delete(gavin.Location); t.Commit(); diff --git a/src/NHibernate.Test/VersionTest/VersionFixture.cs b/src/NHibernate.Test/VersionTest/VersionFixture.cs index 04f58281a98..2c7026ad9ca 100644 --- a/src/NHibernate.Test/VersionTest/VersionFixture.cs +++ b/src/NHibernate.Test/VersionTest/VersionFixture.cs @@ -38,7 +38,7 @@ public void VersionShortCircuitFlush() t.Commit(); s.Close(); - Assert.AreEqual(passp.Version, 2); + Assert.AreEqual(2, passp.Version); s = OpenSession(); t = s.BeginTransaction(); From 0c3c705cf46a43e459e539e612c3677bae64ef57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:57:41 +0100 Subject: [PATCH 073/128] Fix concurrency issues on TransactionScope timeout (#3483) --- .editorconfig | 1 + build-common/teamcity-hibernate.cfg.xml | 2 + default.build | 20 +++ doc/reference/modules/configuration.xml | 31 +++- psake.ps1 | 2 + .../SapSQLAnywhere.cfg.xml | 2 + .../SystemTransactionFixture.cs | 154 ++++++++++++++++++ src/NHibernate.Test/DebugSessionFactory.cs | 47 ++++-- .../SystemTransactionFixture.cs | 154 ++++++++++++++++++ src/NHibernate.Test/TestCase.cs | 15 +- src/NHibernate.Test/TestDialect.cs | 5 + .../TestDialects/MySQL5TestDialect.cs | 5 + .../SapSQLAnywhere17TestDialect.cs | 2 +- .../AdoNetWithSystemTransactionFactory.cs | 1 + src/NHibernate/Cfg/Environment.cs | 21 ++- src/NHibernate/Engine/ISessionImplementor.cs | 3 + src/NHibernate/ISession.cs | 7 +- src/NHibernate/Impl/AbstractSessionImpl.cs | 33 +++- src/NHibernate/Impl/SessionImpl.cs | 22 +-- .../AdoNetWithSystemTransactionFactory.cs | 127 ++++++++++++--- src/NHibernate/nhibernate-configuration.xsd | 24 ++- teamcity.build | 2 + 22 files changed, 610 insertions(+), 70 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9315aa4e45e..da812d88d1b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,6 +2,7 @@ root=true [*] insert_final_newline = true +charset = utf-8 [*.cs] indent_style = tab diff --git a/build-common/teamcity-hibernate.cfg.xml b/build-common/teamcity-hibernate.cfg.xml index e8cb7f7e6dd..9cdad8f1e78 100644 --- a/build-common/teamcity-hibernate.cfg.xml +++ b/build-common/teamcity-hibernate.cfg.xml @@ -26,5 +26,7 @@ + + diff --git a/default.build b/default.build index c8020603e1c..2ee19e5a694 100644 --- a/default.build +++ b/default.build @@ -139,6 +139,26 @@ + + + + + + + + + + + + + + + + diff --git a/doc/reference/modules/configuration.xml b/doc/reference/modules/configuration.xml index dd0c4bd6a63..290e4e64bc0 100644 --- a/doc/reference/modules/configuration.xml +++ b/doc/reference/modules/configuration.xml @@ -1050,8 +1050,8 @@ var session = sessions.OpenSession(conn); after scope disposal. This occurs when the transaction is distributed. This notably concerns ISessionImplementor.AfterTransactionCompletion(bool, ITransaction). NHibernate protects the session from being concurrently used by the code following the scope disposal - with a lock. To prevent any application freeze, this lock has a default timeout of five seconds. If the - application appears to require longer (!) running transaction completion events, this setting allows to + with a lock. To prevent any application freeze, this lock has a default timeout of one second. If the + application appears to require longer running transaction completion events, this setting allows to raise this timeout. -1 disables the timeout. @@ -1060,6 +1060,33 @@ var session = sessions.OpenSession(conn);
+ + + transaction.ignore_session_synchronization_failures + + + Whether session synchronisation failures occuring during finalizations of system transaction should be + ignored or not. false by default. + + When a system transaction terminates abnormaly, especially through timeouts, it may have its + completion events running on concurrent threads while the session is still performing some processing. + To prevent threading concurrency failures, NHibernate then wait for the session to end its processing, + up to transaction.system_completion_lock_timeout. If the session processing is still ongoing + afterwards, it will by default log an error, perform transaction finalization processing concurrently, + then throw a synchronization error. This setting allows to disable that later throw. + + + Disabling the throw can be useful if the used data provider has its own locking mechanism applied + during transaction completion, preventing the session to end its processing. It may then be safe to + ignore this synchronization failure. In case of threading concurrency failure, you may then need to + raise transaction.system_completion_lock_timeout. + + + eg. + true | false + + + transaction.auto_join diff --git a/psake.ps1 b/psake.ps1 index 16f7a267f14..877321e24e3 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -29,6 +29,8 @@ Task Set-Configuration { 'connection.connection_string' = 'Server=(local)\SQL2017;Uid=sa;Pwd=Password12!;Database=nhibernateOdbc;Driver={SQL Server Native Client 11.0};Mars_Connection=yes;'; 'connection.driver_class' = 'NHibernate.Driver.OdbcDriver'; 'odbc.explicit_datetime_scale' = '3'; + 'transaction.ignore_session_synchronization_failures' = 'true'; + 'transaction.system_completion_lock_timeout' = '200'; <# We need to use a dialect that avoids mapping DbType.Time to TIME on MSSQL. On modern SQL Server this becomes TIME(7). Later, such values cannot be read back over ODBC. The error we get is "System.ArgumentException : Unknown SQL type - SS_TIME_EX.". I don't know for certain diff --git a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml index 9512fef12d6..57e02f1a82e 100644 --- a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml +++ b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml @@ -17,5 +17,7 @@ for your own use before compiling tests in Visual Studio.
NHibernate.Dialect.SybaseSQLAnywhere12Dialect true=1;false=0 + true + 200 diff --git a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs index 056ae272b0a..a87793c3d9b 100644 --- a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs @@ -9,6 +9,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -30,6 +31,13 @@ public class SystemTransactionFixtureAsync : SystemTransactionFixtureBase protected override bool UseConnectionOnSystemTransactionPrepare => true; protected override bool AutoJoinTransaction => true; + protected override void OnTearDown() + { + base.OnTearDown(); + // The SupportsTransactionTimeout test may change this, restore it to its default value. + FailOnNotClosedSession = true; + } + [Test] public async Task WillNotCrashOnPrepareFailureAsync() { @@ -524,6 +532,152 @@ public async Task EnforceConnectionUsageRulesOnTransactionCompletionAsync() // Currently always forbidden, whatever UseConnectionOnSystemTransactionEvents. Assert.That(interceptor.AfterException, Is.TypeOf()); } + + // This test check a concurrency issue hard to reproduce. If it is flaky, it has to be considered failing. + // In such case, raise triesCount to investigate it locally with more chances of triggering the trouble. + [Test] + public async Task SupportsTransactionTimeoutAsync() + { + Assume.That(TestDialect.SupportsTransactionScopeTimeouts, Is.True, "The tested dialect is not supported for transaction scope timeouts."); + // Other special cases: ODBC and SAP SQL Anywhere succeed this test only with transaction.ignore_session_synchronization_failures + // enabled. + // They freeze the session during the transaction cancellation. To avoid the test to be very long, the synchronization + // lock timeout should be lowered too. + + // A concurrency issue exists with the legacy setting allowing to use the session from transaction completion, which + // may cause session leaks. Ignore them. + FailOnNotClosedSession = !UseConnectionOnSystemTransactionPrepare; + + // Test case adapted from https://github.com/kaksmet/NHibBugRepro + + // Create some test data. + const int entitiesCount = 5000; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < entitiesCount; i++) + { + var person = new Person + { + NotNullData = Guid.NewGuid().ToString() + }; + + await (s.SaveAsync(person)); + } + + await (t.CommitAsync()); + } + + // Setup unhandled exception catcher. + _unhandledExceptions = new ConcurrentBag(); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + try + { + // Generate transaction timeouts. + const int triesCount = 100; + var txOptions = new TransactionOptions { Timeout = TimeSpan.FromMilliseconds(1) }; + var timeoutsCount = 0; + for (var i = 0; i < triesCount; i++) + { + try + { + using var txScope = new TransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled); + using var session = OpenSession(); + var data = await (session.CreateCriteria().ListAsync()); + Assert.That(data, Has.Count.EqualTo(entitiesCount), "Unexpected count of loaded entities."); + await (Task.Delay(2)); + var count = await (session.Query().CountAsync()); + Assert.That(count, Is.EqualTo(entitiesCount), "Unexpected entities count."); + txScope.Complete(); + } + catch + { + // Assume that is a transaction timeout. It may cause various failures, of which some are hard to identify. + timeoutsCount++; + } + // If in need of checking some specific failures, the following code may be used instead: + /* + catch (Exception ex) + { + var currentEx = ex; + // Depending on where the transaction aborption has broken NHibernate processing, we may + // get various exceptions, like directly a TransactionAbortedException with an inner + // TimeoutException, or a HibernateException encapsulating a TransactionException with a + // timeout, ... + bool isTransactionException, isTimeout; + do + { + isTransactionException = currentEx is System.Transactions.TransactionException; + isTimeout = isTransactionException && currentEx is TransactionAbortedException; + currentEx = currentEx.InnerException; + } + while (!isTransactionException && currentEx != null); + while (!isTimeout && currentEx != null) + { + isTimeout = currentEx is TimeoutException; + currentEx = currentEx?.InnerException; + } + + if (!isTimeout) + { + // We may also get a GenericADOException with an InvalidOperationException stating the + // transaction associated to the connection is no more active but not yet suppressed, + // and that for executing some SQL, we need to suppress it. That is a weak way of + // identifying the case, especially with the many localizations of the message. + currentEx = ex; + do + { + isTimeout = currentEx is InvalidOperationException && currentEx.Message.Contains("SQL"); + currentEx = currentEx?.InnerException; + } + while (!isTimeout && currentEx != null); + } + + if (isTimeout) + timeoutsCount++; + else + throw; + } + */ + } + + Assert.That( + _unhandledExceptions.Count, + Is.EqualTo(0), + "Unhandled exceptions have occurred: {0}", + string.Join(@" + +", _unhandledExceptions)); + + // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly + // more than 10% of the attempts. + Warn.Unless(timeoutsCount, Is.GreaterThan(5), "The test should have generated more timeouts."); + } + finally + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + } + } + + private ConcurrentBag _unhandledExceptions; + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception exception) + { + // Ascertain NHibernate is involved. Some unhandled exceptions occur due to the + // TransactionScope timeout operating on an unexpected thread for the data provider. + var isNHibernateInvolved = false; + while (exception != null && !isNHibernateInvolved) + { + isNHibernateInvolved = exception.StackTrace != null && exception.StackTrace.ToLowerInvariant().Contains("nhibernate"); + exception = exception.InnerException; + } + if (!isNHibernateInvolved) + return; + } + _unhandledExceptions.Add(e.ExceptionObject); + } } [TestFixture] diff --git a/src/NHibernate.Test/DebugSessionFactory.cs b/src/NHibernate.Test/DebugSessionFactory.cs index 7eb551bb83f..8c5d892b1d4 100644 --- a/src/NHibernate.Test/DebugSessionFactory.cs +++ b/src/NHibernate.Test/DebugSessionFactory.cs @@ -43,14 +43,13 @@ public partial class DebugSessionFactory : ISessionFactoryImplementor /// it debug or not. /// public DebugConnectionProvider DebugConnectionProvider - => _debugConnectionProvider ?? - (_debugConnectionProvider = ActualFactory.ConnectionProvider as DebugConnectionProvider); + => _debugConnectionProvider ??= ActualFactory.ConnectionProvider as DebugConnectionProvider; public ISessionFactoryImplementor ActualFactory { get; } public EventListeners EventListeners => ((SessionFactoryImpl)ActualFactory).EventListeners; [NonSerialized] - private readonly ConcurrentBag _openedSessions = new ConcurrentBag(); + private readonly ConcurrentQueue _openedSessions = new(); private static readonly ILog _log = LogManager.GetLogger(typeof(DebugSessionFactory).Assembly, typeof(TestCase)); public DebugSessionFactory(ISessionFactory actualFactory) @@ -63,29 +62,43 @@ public DebugSessionFactory(ISessionFactory actualFactory) public bool CheckSessionsWereClosed() { var allClosed = true; + var number = 1; foreach (var session in _openedSessions) { - // Do not inverse, we want to close all of them. - allClosed = CheckSessionWasClosed(session) && allClosed; + var wasClosed = CheckSessionWasClosed(session); + // No early exit out of the loop: we want to close all forgotten sessions. + if (!wasClosed) + { + _log.ErrorFormat("Test case didn't close session {0}, n°{1} of {2}, closing.", + session.SessionId, number, _openedSessions.Count); + } + allClosed = wasClosed && allClosed; + // Catches only session opened from another one while sharing the connection. Those // opened without sharing the connection stay un-monitored. foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList()) { - allClosed = CheckSessionWasClosed(dependentSession) && allClosed; + wasClosed = CheckSessionWasClosed(dependentSession); + if (!wasClosed) + { + _log.ErrorFormat("Test case didn't close dependent session {0} of the session {3}, n°{1} of {2}, closing.", + dependentSession.SessionId, number, _openedSessions.Count, session.SessionId); + } + allClosed = wasClosed && allClosed; } + number++; } return allClosed; } - private bool CheckSessionWasClosed(ISessionImplementor session) + private static bool CheckSessionWasClosed(ISessionImplementor session) { session.TransactionContext?.Wait(); if (!session.IsOpen) return true; - _log.Error($"Test case didn't close session {session.SessionId}, closing"); (session as ISession)?.Close(); (session as IStatelessSession)?.Close(); return false; @@ -101,7 +114,7 @@ ISession ISessionFactory.OpenSession(DbConnection connection) #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(connection); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -110,7 +123,7 @@ ISession ISessionFactory.OpenSession(IInterceptor sessionLocalInterceptor) #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(sessionLocalInterceptor); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -119,14 +132,14 @@ ISession ISessionFactory.OpenSession(DbConnection conn, IInterceptor sessionLoca #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(conn, sessionLocalInterceptor); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } ISession ISessionFactory.OpenSession() { var s = ActualFactory.OpenSession(); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -138,14 +151,14 @@ IStatelessSessionBuilder ISessionFactory.WithStatelessOptions() IStatelessSession ISessionFactory.OpenStatelessSession() { var s = ActualFactory.OpenStatelessSession(); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } IStatelessSession ISessionFactory.OpenStatelessSession(DbConnection connection) { var s = ActualFactory.OpenStatelessSession(connection); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -158,7 +171,7 @@ ISession ISessionFactoryImplementor.OpenSession( #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(connection, flushBeforeCompletionEnabled, autoCloseSessionEnabled, connectionReleaseMode); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -429,7 +442,7 @@ public SessionBuilder(ISessionBuilder actualBuilder, DebugSessionFactory debugFa ISession ISessionBuilder.OpenSession() { var s = _actualBuilder.OpenSession(); - _debugFactory._openedSessions.Add(s.GetSessionImplementation()); + _debugFactory._openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -504,7 +517,7 @@ public StatelessSessionBuilder(IStatelessSessionBuilder actualBuilder, DebugSess IStatelessSession IStatelessSessionBuilder.OpenStatelessSession() { var s = _actualBuilder.OpenStatelessSession(); - _debugFactory._openedSessions.Add(s.GetSessionImplementation()); + _debugFactory._openedSessions.Enqueue(s.GetSessionImplementation()); return s; } diff --git a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs index e5fb6fd46c0..8503de97948 100644 --- a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -18,6 +19,13 @@ public class SystemTransactionFixture : SystemTransactionFixtureBase protected override bool UseConnectionOnSystemTransactionPrepare => true; protected override bool AutoJoinTransaction => true; + protected override void OnTearDown() + { + base.OnTearDown(); + // The SupportsTransactionTimeout test may change this, restore it to its default value. + FailOnNotClosedSession = true; + } + [Test] public void WillNotCrashOnPrepareFailure() { @@ -643,6 +651,152 @@ public void CanUseSessionWithManyDependentTransaction(bool explicitFlush) } } + // This test check a concurrency issue hard to reproduce. If it is flaky, it has to be considered failing. + // In such case, raise triesCount to investigate it locally with more chances of triggering the trouble. + [Test] + public void SupportsTransactionTimeout() + { + Assume.That(TestDialect.SupportsTransactionScopeTimeouts, Is.True, "The tested dialect is not supported for transaction scope timeouts."); + // Other special cases: ODBC and SAP SQL Anywhere succeed this test only with transaction.ignore_session_synchronization_failures + // enabled. + // They freeze the session during the transaction cancellation. To avoid the test to be very long, the synchronization + // lock timeout should be lowered too. + + // A concurrency issue exists with the legacy setting allowing to use the session from transaction completion, which + // may cause session leaks. Ignore them. + FailOnNotClosedSession = !UseConnectionOnSystemTransactionPrepare; + + // Test case adapted from https://github.com/kaksmet/NHibBugRepro + + // Create some test data. + const int entitiesCount = 5000; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < entitiesCount; i++) + { + var person = new Person + { + NotNullData = Guid.NewGuid().ToString() + }; + + s.Save(person); + } + + t.Commit(); + } + + // Setup unhandled exception catcher. + _unhandledExceptions = new ConcurrentBag(); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + try + { + // Generate transaction timeouts. + const int triesCount = 100; + var txOptions = new TransactionOptions { Timeout = TimeSpan.FromMilliseconds(1) }; + var timeoutsCount = 0; + for (var i = 0; i < triesCount; i++) + { + try + { + using var txScope = new TransactionScope(TransactionScopeOption.Required, txOptions); + using var session = OpenSession(); + var data = session.CreateCriteria().List(); + Assert.That(data, Has.Count.EqualTo(entitiesCount), "Unexpected count of loaded entities."); + Thread.Sleep(2); + var count = session.Query().Count(); + Assert.That(count, Is.EqualTo(entitiesCount), "Unexpected entities count."); + txScope.Complete(); + } + catch + { + // Assume that is a transaction timeout. It may cause various failures, of which some are hard to identify. + timeoutsCount++; + } + // If in need of checking some specific failures, the following code may be used instead: + /* + catch (Exception ex) + { + var currentEx = ex; + // Depending on where the transaction aborption has broken NHibernate processing, we may + // get various exceptions, like directly a TransactionAbortedException with an inner + // TimeoutException, or a HibernateException encapsulating a TransactionException with a + // timeout, ... + bool isTransactionException, isTimeout; + do + { + isTransactionException = currentEx is System.Transactions.TransactionException; + isTimeout = isTransactionException && currentEx is TransactionAbortedException; + currentEx = currentEx.InnerException; + } + while (!isTransactionException && currentEx != null); + while (!isTimeout && currentEx != null) + { + isTimeout = currentEx is TimeoutException; + currentEx = currentEx?.InnerException; + } + + if (!isTimeout) + { + // We may also get a GenericADOException with an InvalidOperationException stating the + // transaction associated to the connection is no more active but not yet suppressed, + // and that for executing some SQL, we need to suppress it. That is a weak way of + // identifying the case, especially with the many localizations of the message. + currentEx = ex; + do + { + isTimeout = currentEx is InvalidOperationException && currentEx.Message.Contains("SQL"); + currentEx = currentEx?.InnerException; + } + while (!isTimeout && currentEx != null); + } + + if (isTimeout) + timeoutsCount++; + else + throw; + } + */ + } + + Assert.That( + _unhandledExceptions.Count, + Is.EqualTo(0), + "Unhandled exceptions have occurred: {0}", + string.Join(@" + +", _unhandledExceptions)); + + // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly + // more than 10% of the attempts. + Warn.Unless(timeoutsCount, Is.GreaterThan(5), "The test should have generated more timeouts."); + } + finally + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + } + } + + private ConcurrentBag _unhandledExceptions; + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception exception) + { + // Ascertain NHibernate is involved. Some unhandled exceptions occur due to the + // TransactionScope timeout operating on an unexpected thread for the data provider. + var isNHibernateInvolved = false; + while (exception != null && !isNHibernateInvolved) + { + isNHibernateInvolved = exception.StackTrace != null && exception.StackTrace.ToLowerInvariant().Contains("nhibernate"); + exception = exception.InnerException; + } + if (!isNHibernateInvolved) + return; + } + _unhandledExceptions.Add(e.ExceptionObject); + } + [Theory, Explicit("Bench")] public void BenchTransactionAccess(bool inTransaction) { diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index c58d819ed64..137818e1e90 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -54,6 +54,8 @@ protected TestDialect TestDialect get { return _testDialect ?? (_testDialect = TestDialect.GetTestDialect(Dialect)); } } + protected bool FailOnNotClosedSession { get; set; } = true; + /// /// Mapping files used in the TestCase /// @@ -157,6 +159,9 @@ public void TearDown() { var testResult = TestContext.CurrentContext.Result; var fail = false; + var wereClosed = true; + // In case the test Teardown needs to switch it off for other tests, back it up. + var failOnNotClosedSession = FailOnNotClosedSession; var testOwnTearDownDone = false; string badCleanupMessage = null; try @@ -170,12 +175,12 @@ public void TearDown() { try { - var wereClosed = _sessionFactory.CheckSessionsWereClosed(); + wereClosed = _sessionFactory.CheckSessionsWereClosed(); var wasCleaned = CheckDatabaseWasCleaned(); var wereConnectionsClosed = CheckConnectionsWereClosed(); - fail = !wereClosed || !wasCleaned || !wereConnectionsClosed; + fail = !wereClosed && failOnNotClosedSession || !wasCleaned || !wereConnectionsClosed; - if (fail) + if (fail || !wereClosed) { badCleanupMessage = "Test didn't clean up after itself. session closed: " + wereClosed + "; database cleaned: " + wasCleaned @@ -213,6 +218,10 @@ public void TearDown() { Assert.Fail(badCleanupMessage); } + else if (!wereClosed) + { + Assert.Warn(badCleanupMessage); + } } private string GetCombinedFailureMessage(TestContext.ResultAdapter result, string tearDownFailure, string tearDownStackTrace) diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index e7bc20d304f..69ab31fcb37 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -177,6 +177,11 @@ public bool SupportsSqlType(SqlType sqlType) /// public virtual bool SupportsDependentTransaction => true; + /// + /// Transaction scope timeouts occur on a dedicated thread which wrecks some data providers. + /// + public virtual bool SupportsTransactionScopeTimeouts => true; + /// /// Some databases (provider?) fails to compute adequate column types for queries which columns /// computing include a parameter value. diff --git a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs index ea68e6f19b7..d37bef44dd5 100644 --- a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs @@ -21,5 +21,10 @@ public MySQL5TestDialect(Dialect.Dialect dialect) /// See https://dev.mysql.com/doc/refman/8.0/en/correlated-subqueries.html /// public override bool SupportsCorrelatedColumnsInSubselectJoin => false; + + /// + /// MySQL data provider may be wrecked by transaction scope timeouts to the point of causing even the teardown to fail. + /// + public override bool SupportsTransactionScopeTimeouts => false; } } diff --git a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs index 35a35092ce3..3955f92aef7 100644 --- a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs @@ -1,4 +1,4 @@ -namespace NHibernate.Test.TestDialects +namespace NHibernate.Test.TestDialects { public class SapSQLAnywhere17TestDialect : TestDialect { diff --git a/src/NHibernate/Async/Transaction/AdoNetWithSystemTransactionFactory.cs b/src/NHibernate/Async/Transaction/AdoNetWithSystemTransactionFactory.cs index 91558147f86..3e9de8e7836 100644 --- a/src/NHibernate/Async/Transaction/AdoNetWithSystemTransactionFactory.cs +++ b/src/NHibernate/Async/Transaction/AdoNetWithSystemTransactionFactory.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Transactions; diff --git a/src/NHibernate/Cfg/Environment.cs b/src/NHibernate/Cfg/Environment.cs index cc107802524..c052cd64267 100644 --- a/src/NHibernate/Cfg/Environment.cs +++ b/src/NHibernate/Cfg/Environment.cs @@ -142,12 +142,29 @@ public static string Version /// after scope disposal. This occurs when the transaction is distributed. /// This notably concerns . /// NHibernate protects the session from being concurrently used by the code following the scope disposal - /// with a lock. To prevent any application freeze, this lock has a default timeout of five seconds. If the - /// application appears to require longer (!) running transaction completion events, this setting allows to + /// with a lock. To prevent any application freeze, this lock has a default timeout of one second. If the + /// application appears to require longer running transaction completion events, this setting allows to /// raise this timeout. -1 disables the timeout. /// public const string SystemTransactionCompletionLockTimeout = "transaction.system_completion_lock_timeout"; /// + /// Whether session synchronisation failures occuring during finalizations of system transaction should be + /// ignored or not. by default. + /// + /// + /// When a system transaction terminates abnormaly, especially through timeouts, it may have its + /// completion events running on concurrent threads while the session is still performing some processing. + /// To prevent threading concurrency failures, NHibernate then wait for the session to end its processing, + /// up to . If the session processing is still ongoing + /// afterwards, it will by default log an error, perform transaction finalization processing concurrently, + /// then throw a synchronization error. This setting allows to disable that later throw. + /// Disabling the throw can be useful if the used data provider has its own locking mechanism applied + /// during transaction completion, preventing the session to end its processing. It may then be safe to + /// ignore this synchronization failure. In case of threading concurrency failure, you may then need to + /// raise . + /// + public const string IgnoreSessionSynchronizationFailuresOnSystemTransaction = "transaction.ignore_session_synchronization_failures"; + /// /// When a system transaction is being prepared, is using connection during this process enabled? /// Default is , for supporting with transaction factories /// supporting system transactions. But this requires enlisting additional connections, retaining disposed diff --git a/src/NHibernate/Engine/ISessionImplementor.cs b/src/NHibernate/Engine/ISessionImplementor.cs index 9a0cb58b77a..d7af7a73fbd 100644 --- a/src/NHibernate/Engine/ISessionImplementor.cs +++ b/src/NHibernate/Engine/ISessionImplementor.cs @@ -66,6 +66,9 @@ internal static IDisposable BeginProcess(this ISessionImplementor session) : SessionIdLoggingContext.CreateOrNull(session.SessionId); } + internal static bool IsProcessing(this ISessionImplementor session) + => session is AbstractSessionImpl impl && impl.IsProcessing; + //6.0 TODO: Expose as ISessionImplementor.FutureBatch and replace method usages with property internal static IQueryBatch GetFutureBatch(this ISessionImplementor session) { diff --git a/src/NHibernate/ISession.cs b/src/NHibernate/ISession.cs index 237dc9823c0..92b276a88ab 100644 --- a/src/NHibernate/ISession.cs +++ b/src/NHibernate/ISession.cs @@ -243,8 +243,11 @@ public partial interface ISession : IDisposable /// End the ISession by disconnecting from the ADO.NET connection and cleaning up. /// /// - /// It is not strictly necessary to Close() the ISession but you must - /// at least Disconnect() it. + /// It is not strictly necessary to Close() the ISession but you must + /// at least Disconnect() or Dispose it. + /// Do not call this method inside a transaction scope, use Dispose instead, + /// since Close() is not aware of system transactions: if the transaction completion + /// requires the session, it will fail. /// /// The connection provided by the application or DbConnection Close(); diff --git a/src/NHibernate/Impl/AbstractSessionImpl.cs b/src/NHibernate/Impl/AbstractSessionImpl.cs index 4fe9c9ae598..bd51bb51697 100644 --- a/src/NHibernate/Impl/AbstractSessionImpl.cs +++ b/src/NHibernate/Impl/AbstractSessionImpl.cs @@ -394,6 +394,11 @@ public bool IsClosed get { return closed; } } + /// + /// Indicates if the session is currently processing some operations. + /// + public bool IsProcessing => _processHelper.Processing; + /// /// If not nested in another call to BeginProcess on this session, check and update the /// session status and set its session id in context. @@ -407,6 +412,21 @@ public IDisposable BeginProcess() return _processHelper.BeginProcess(this); } + /// + /// If not nested in another call to BeginProcess on this session, optionnaly check + /// and update the session status, then set its session id in context and flag it as processing. + /// + /// to initiate a processing without + /// checking and updating the session. + /// + /// If not already processing, an object to dispose for signaling the end of the process. + /// Otherwise, . + /// + protected IDisposable BeginProcess(bool noCheckAndUpdate) + { + return _processHelper.BeginProcess(this, noCheckAndUpdate); + } + /// /// If not nested in a call to BeginProcess on this session, set its session id in context. /// @@ -429,7 +449,7 @@ private sealed class ProcessHelper : IDisposable private IDisposable _context; [NonSerialized] - private bool _processing; + private volatile bool _processing; public ProcessHelper() { @@ -437,7 +457,7 @@ public ProcessHelper() public bool Processing { get => _processing; } - public IDisposable BeginProcess(AbstractSessionImpl session) + public IDisposable BeginProcess(AbstractSessionImpl session, bool noCheckAndUpdate = false) { if (_processing) return null; @@ -445,7 +465,14 @@ public IDisposable BeginProcess(AbstractSessionImpl session) try { _context = SessionIdLoggingContext.CreateOrNull(session.SessionId); - session.CheckAndUpdateSessionStatus(); + if (noCheckAndUpdate) + { + session.TransactionContext?.Wait(); + } + else + { + session.CheckAndUpdateSessionStatus(); + } _processing = true; } catch diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index 9a7120ae8b7..46d6f20c883 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -264,16 +264,10 @@ public bool ShouldAutoClose get { return IsAutoCloseSessionEnabled && !IsClosed; } } - /// - /// Close the session and release all resources - /// - /// Do not call this method inside a transaction scope, use Dispose instead, since - /// Close() is not aware of distributed transactions - /// - /// + /// public DbConnection Close() { - using (BeginContext()) + using (BeginProcess(true)) { log.Debug("closing session"); if (IsClosed) @@ -1488,18 +1482,18 @@ public void Reconnect(DbConnection conn) /// public void Dispose() { - using (BeginContext()) + // Ensure we are not disposing concurrently to transaction completion, which would + // remove the transaction context. + using (BeginProcess(true)) { log.Debug("[session-id={0}] running ISession.Dispose()", SessionId); - // Ensure we are not disposing concurrently to transaction completion, which would - // remove the context. (Do not store it into a local variable before the Wait.) - TransactionContext?.Wait(); - // If the synchronization above is bugged and lets a race condition remaining, we may + // If the BeginProcess synchronization is bugged and lets a race condition remaining, we may // blow here with a null ref exception after the null check. We could introduce // a local variable for avoiding it, but that would turn a failure causing an exception // into a failure causing a session and connection leak. So do not do it, better blow away // with a null ref rather than silently leaking a session. And then fix the synchronization. - if (TransactionContext != null && TransactionContext.CanFlushOnSystemTransactionCompleted) + if (TransactionContext != null && TransactionContext.CanFlushOnSystemTransactionCompleted && + TransactionContext.IsInActiveTransaction) { TransactionContext.ShouldCloseSessionOnSystemTransactionCompleted = true; return; diff --git a/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs b/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs index 7f74bc7218c..2c6973137c2 100644 --- a/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs +++ b/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Transactions; @@ -23,6 +24,10 @@ public partial class AdoNetWithSystemTransactionFactory : AdoNetTransactionFacto /// protected int SystemTransactionCompletionLockTimeout { get; private set; } /// + /// See . + /// + protected bool IgnoreSessionSynchronizationFailuresOnSystemTransaction { get; private set; } + /// /// See . /// protected bool UseConnectionOnSystemTransactionPrepare { get; private set; } @@ -32,10 +37,12 @@ public override void Configure(IDictionary props) { base.Configure(props); SystemTransactionCompletionLockTimeout = - PropertiesHelper.GetInt32(Cfg.Environment.SystemTransactionCompletionLockTimeout, props, 5000); + PropertiesHelper.GetInt32(Cfg.Environment.SystemTransactionCompletionLockTimeout, props, 1000); if (SystemTransactionCompletionLockTimeout < -1) throw new HibernateException( $"Invalid {Cfg.Environment.SystemTransactionCompletionLockTimeout} value: {SystemTransactionCompletionLockTimeout}. It can not be less than -1."); + IgnoreSessionSynchronizationFailuresOnSystemTransaction = + PropertiesHelper.GetBoolean(Cfg.Environment.IgnoreSessionSynchronizationFailuresOnSystemTransaction, props, false); UseConnectionOnSystemTransactionPrepare = PropertiesHelper.GetBoolean(Cfg.Environment.UseConnectionOnSystemTransactionPrepare, props, true); } @@ -129,7 +136,7 @@ protected virtual ITransactionContext CreateAndEnlistMainContext( { var transactionContext = new SystemTransactionContext( session, transaction, SystemTransactionCompletionLockTimeout, - UseConnectionOnSystemTransactionPrepare); + UseConnectionOnSystemTransactionPrepare, IgnoreSessionSynchronizationFailuresOnSystemTransaction); transactionContext.EnlistedTransaction.EnlistVolatile( transactionContext, UseConnectionOnSystemTransactionPrepare @@ -188,6 +195,7 @@ public class SystemTransactionContext : ITransactionContext, IEnlistmentNotifica private readonly ISessionImplementor _session; private readonly bool _useConnectionOnSystemTransactionPrepare; + private readonly bool _ignoreSessionSynchronizationFailures; private readonly System.Transactions.Transaction _originalTransaction; private readonly ManualResetEventSlim _lock = new ManualResetEventSlim(true); private volatile bool _needCompletionLocking = true; @@ -203,6 +211,8 @@ public class SystemTransactionContext : ITransactionContext, IEnlistmentNotifica /// The transaction into which the context will be enlisted. /// See . /// See . + // Since 5.6 + [Obsolete("Use overload with an additionnal boolean parameter")] public SystemTransactionContext( ISessionImplementor session, System.Transactions.Transaction transaction, @@ -216,6 +226,29 @@ public SystemTransactionContext( _useConnectionOnSystemTransactionPrepare = useConnectionOnSystemTransactionPrepare; } + /// + /// Default constructor. + /// + /// The session to enlist with the transaction. + /// The transaction into which the context will be enlisted. + /// See . + /// See . + /// See . + public SystemTransactionContext( + ISessionImplementor session, + System.Transactions.Transaction transaction, + int systemTransactionCompletionLockTimeout, + bool useConnectionOnSystemTransactionPrepare, + bool ignoreSessionSynchronizationFailures) + { + _session = session ?? throw new ArgumentNullException(nameof(session)); + _originalTransaction = transaction ?? throw new ArgumentNullException(nameof(transaction)); + EnlistedTransaction = transaction.Clone(); + _systemTransactionCompletionLockTimeout = systemTransactionCompletionLockTimeout; + _useConnectionOnSystemTransactionPrepare = useConnectionOnSystemTransactionPrepare; + _ignoreSessionSynchronizationFailures = ignoreSessionSynchronizationFailures; + } + /// public virtual void Wait() { @@ -242,9 +275,9 @@ public virtual void Wait() // Remove the block then throw. Unlock(); throw new HibernateException( - $"Synchronization timeout for transaction completion. Either raise" + - $"{Cfg.Environment.SystemTransactionCompletionLockTimeout}, or check all scopes are properly" + - $"disposed and/or all direct System.Transaction.Current changes are properly managed."); + "A synchronization timeout occurred at transaction completion. Either raise " + + $"{Cfg.Environment.SystemTransactionCompletionLockTimeout}, or check all scopes are properly " + + "disposed and/or all direct System.Transaction.Current changes are properly managed."); } catch (HibernateException) { @@ -266,8 +299,8 @@ protected virtual void Lock() { if (!_needCompletionLocking || _isDisposed) return; - _needCompletionLocking = false; _lock.Reset(); + _needCompletionLocking = false; } /// @@ -418,23 +451,20 @@ void IEnlistmentNotification.InDoubt(Enlistment enlistment) /// callback, if this is an in-doubt callback. protected virtual void ProcessSecondPhase(Enlistment enlistment, bool? success) { - using (_session.BeginContext()) - { - _logger.Debug( - success.HasValue - ? success.Value - ? "Committing system transaction" - : "Rolled back system transaction" - : "System transaction is in doubt"); + _logger.Debug( + success.HasValue + ? success.Value + ? "Committing system transaction" + : "Rolled back system transaction" + : "System transaction is in doubt"); - try - { - CompleteTransaction(success ?? false); - } - finally - { - enlistment.Done(); - } + try + { + CompleteTransaction(success ?? false); + } + finally + { + enlistment.Done(); } } @@ -454,10 +484,47 @@ protected virtual void CompleteTransaction(bool isCommitted) // do an early exit here in such case. if (!IsInActiveTransaction) return; + Lock(); + // In case of a rollback due to a timeout, we may have the session disposal running concurrently + // to the transaction completion in a way our current locking mechanism cannot fully protect: the + // session disposal "BeginProcess" can go through the Wait before it is locked but flag the + // session as processing after the transaction completion has read it as not processing. To dodge + // that very unlikely case, we could consider the session as still processing initially regardless + // of its actual status in case of rollback by changing below condition to + // "!isCommitted || _session.IsProcessing()". That would cause a Thread.Sleep in all rollback cases. + // That would reinforce the impracticality of that concurrency possibility, but with an ugly crutch. + var isSessionProcessing = _session.IsProcessing(); try { // Allow transaction completed actions to run while others stay blocked. _bypassLock.Value = true; + // Ensure no other session processing is still ongoing. In case of a transaction timeout, the transaction is + // cancelled on a new thread even for non-distributed scopes. So, the session could be doing some processing, + // and will not be interrupted until attempting some usage of the connection. See #3355. + // Thread safety of a concurrent session BeginProcess is ensured by the Wait performed by BeginProcess. + if (isSessionProcessing) + { + var timeOutGuard = new Stopwatch(); + timeOutGuard.Start(); + while (isSessionProcessing && timeOutGuard.ElapsedMilliseconds < _systemTransactionCompletionLockTimeout) + { + // Naïve yield. + Thread.Sleep(10); + isSessionProcessing = _session.IsProcessing(); + } + if (isSessionProcessing) + { + // Throwing would give up attempting to close the session if need be, which may still succeed. So, + // just log an error. + _logger.Warn( + "A synchronization timeout occurred at transaction completion: the session is still processing. " + + "Attempting to finalize the transaction concurrently, which may cause a thread concurrency failure. " + + "You may raise {0} if it is set too low. It may also be a limitation of the data provider, " + + "like locks applied on its side while processing transaction cancellations occurring on concurrent threads, " + + "thus preventing the session to finish its current processing during a transaction cancellation.", + Cfg.Environment.SystemTransactionCompletionLockTimeout); + } + } using (_session.BeginContext()) { // Flag active as false before running actions, otherwise the session may not cleanup as much @@ -477,7 +544,7 @@ protected virtual void CompleteTransaction(bool isCommitted) // within scopes, although mixing is not advised. if (!ShouldCloseSessionOnSystemTransactionCompleted) _session.ConnectionManager.EnlistIfRequired(null); - + _session.AfterTransactionCompletion(isCommitted, null); foreach (var dependentSession in _session.ConnectionManager.DependentSessions) dependentSession.AfterTransactionCompletion(isCommitted, null); @@ -497,6 +564,18 @@ protected virtual void CompleteTransaction(bool isCommitted) // Dispose releases blocked threads by the way. Dispose(); } + + if (isSessionProcessing && !_ignoreSessionSynchronizationFailures) + { + throw new HibernateException( + "A synchronization timeout occurred at transaction completion: the session was still processing. " + + $"You may raise {Cfg.Environment.SystemTransactionCompletionLockTimeout} if it is set too low. " + + "It may also be a limitation of the data provider, " + + "like locks applied on its side while processing transaction cancellations occurring on concurrent threads, " + + "thus preventing the session to finish its current processing during a transaction cancellation. " + + $"In such case, you may enable {Cfg.Environment.IgnoreSessionSynchronizationFailuresOnSystemTransaction}, " + + $"and possibly lower {Cfg.Environment.SystemTransactionCompletionLockTimeout}."); + } } private static void Cleanup(ISessionImplementor session) @@ -504,7 +583,7 @@ private static void Cleanup(ISessionImplementor session) foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList()) { var dependentContext = dependentSession.TransactionContext; - // Do not nullify TransactionContext here, could create a race condition with + // Do not nullify TransactionContext here, it could create a race condition with // would be await-er on session for disposal (test cases cleanup checks by example). if (dependentContext == null) continue; diff --git a/src/NHibernate/nhibernate-configuration.xsd b/src/NHibernate/nhibernate-configuration.xsd index 08d922ad963..12abc622a52 100644 --- a/src/NHibernate/nhibernate-configuration.xsd +++ b/src/NHibernate/nhibernate-configuration.xsd @@ -233,12 +233,32 @@ after scope disposal. This occurs when the transaction is distributed. This notably concerns ISessionImplementor.AfterTransactionCompletion(bool, ITransaction). NHibernate protects the session from being concurrently used by the code following the scope disposal - with a lock. To prevent any application freeze, this lock has a default timeout of five seconds. If the - application appears to require longer (!) running transaction completion events, this setting allows to + with a lock. To prevent any application freeze, this lock has a default timeout of one second. If the + application appears to require longer running transaction completion events, this setting allows to raise this timeout. -1 disables the timeout. + + + + Whether session synchronisation failures occuring during finalizations of system transaction should be + ignored or not. false by default. + + When a system transaction terminates abnormaly, especially through timeouts, it may have its + completion events running on concurrent threads while the session is still performing some processing. + To prevent threading concurrency failures, NHibernate then wait for the session to end its processing, + up to transaction.system_completion_lock_timeout. If the session processing is still ongoing + afterwards, it will by default log an error, perform transaction finalization processing concurrently, + then throw a synchronization error. This setting allows to disable that later throw. + + Disabling the throw can be useful if the used data provider has its own locking mechanism applied + during transaction completion, preventing the session to end its processing. It may then be safe to + ignore this synchronization failure. In case of threading concurrency failure, you may then need to + raise transaction.system_completion_lock_timeout. + + + diff --git a/teamcity.build b/teamcity.build index b8125f5dfe5..9319ed389fc 100644 --- a/teamcity.build +++ b/teamcity.build @@ -50,6 +50,8 @@ + + dev - 9.0 + 12.0 $(NhVersion).$(VersionPatch) $(VersionSuffix).$(BuildNumber) @@ -14,14 +14,16 @@ $(VersionPrefix).$(BuildNumber) $(VersionPrefix).0 - net48;net6.0 - net461;net48;netcoreapp2.0;netstandard2.0;netstandard2.1;net6.0 + net48;net8.0 + net461;net48;netcoreapp2.0;netstandard2.0;netstandard2.1;net6.0;net8.0 false true NETFX;$(DefineConstants) NETFX,$(DefineConstants) + $(NoWarn);NU1903 $(NoWarn);SYSLIB0011 + $(NoWarn);SYSLIB0011;SYSLIB0050;SYSLIB0051 NHibernate NHibernate.info diff --git a/global.json b/global.json index 6ecdd6167f9..391ba3c2a30 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.101", + "version": "8.0.100", "rollForward": "latestFeature" } } diff --git a/psake.ps1 b/psake.ps1 index 877321e24e3..0eb342b2875 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -132,7 +132,7 @@ Task Test -depends Build { 'NHibernate.Test', 'NHibernate.Test.VisualBasic' ) | ForEach-Object { - $assembly = [IO.Path]::Combine("src", $_, "bin", "Release", "net6.0", "$_.dll") + $assembly = [IO.Path]::Combine("src", $_, "bin", "Release", "net8.0", "$_.dll") Exec { dotnet $assembly --labels=before --nocolor "--result=$_-TestResult.xml" } diff --git a/src/AsyncGenerator.yml b/src/AsyncGenerator.yml index 1f763ac1df9..9c5f0a43404 100644 --- a/src/AsyncGenerator.yml +++ b/src/AsyncGenerator.yml @@ -187,7 +187,7 @@ scanForMissingAsyncMembers: - all: true - filePath: NHibernate.Test/NHibernate.Test.csproj - targetFramework: net6.0 + targetFramework: net8.0 concurrentRun: true applyChanges: true suppressDiagnosticFailures: diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index af019d9d1e5..e720221f895 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -8,14 +8,14 @@ On On - + Exe false - + @@ -30,7 +30,7 @@ - + diff --git a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs index f2683f7f26c..27a470f9d9b 100644 --- a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs @@ -30,6 +30,7 @@ namespace NHibernate.Test.CacheTest { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class SerializationFixtureAsync { @@ -312,11 +313,11 @@ private void CheckObjectTypeCacheEntry(AnyType.ObjectTypeCacheEntry original, An Assert.That(copy.EntityName, Is.EqualTo(original.EntityName)); } - private static async Task TestDataContractSerializerAsync(T obj) + private static async Task TestDataContractSerializerAsync(T obj, CancellationToken cancellationToken = default(CancellationToken)) { - var xml = await (DataContractSerializerToXmlAsync(obj)); + var xml = await (DataContractSerializerToXmlAsync(obj, cancellationToken)); obj = DataContractSerializerFromXml(xml); - Assert.That(xml, Is.EqualTo(await (DataContractSerializerToXmlAsync(obj)))); + Assert.That(xml, Is.EqualTo(await (DataContractSerializerToXmlAsync(obj, cancellationToken)))); return obj; } @@ -328,7 +329,7 @@ private static T TestBinaryFormatter(T obj) return obj; } - private static async Task DataContractSerializerToXmlAsync(T obj) + private static async Task DataContractSerializerToXmlAsync(T obj, CancellationToken cancellationToken = default(CancellationToken)) { using (var memoryStream = new MemoryStream()) using (var reader = new StreamReader(memoryStream)) @@ -336,7 +337,7 @@ private static async Task DataContractSerializerToXmlAsync(T obj) var serializer = new DataContractSerializer(typeof(T), KnownTypes); serializer.WriteObject(memoryStream, obj); memoryStream.Position = 0; - return await (reader.ReadToEndAsync()); + return await (reader.ReadToEndAsync(cancellationToken)); } } diff --git a/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs b/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs new file mode 100644 index 00000000000..8b5b55f7cb9 --- /dev/null +++ b/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs @@ -0,0 +1,15 @@ +#if !NET8_0_OR_GREATER +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace NHibernate.Test.CacheTest; + +internal static class TextReaderExtensions +{ + public static Task ReadToEndAsync(this TextReader reader, CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested + ? Task.FromCanceled(cancellationToken) + : reader.ReadToEndAsync(); +} +#endif diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 2ae6cf60202..ee64e604146 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -4,10 +4,11 @@ The Unit Tests for NHibernate. $(NhAppTargetFrameworks) true - $(NoWarn);3001;3002;3003;3005;SYSLIB0003;SYSLIB0012 + $(NoWarn);3001;3002;3003;3005;8981;SYSLIB0003;SYSLIB0012 true + true - + Exe false @@ -38,7 +39,7 @@ PreserveNewest - + @@ -63,7 +64,7 @@ - + @@ -86,10 +87,10 @@ - - + + - + diff --git a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj index 60d56bb7401..715af02ffb3 100644 --- a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj +++ b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj @@ -7,7 +7,7 @@ true $(NoWarn);3001;3002;3003;3005 - + Exe false @@ -18,7 +18,7 @@ - + diff --git a/src/NHibernate.sln b/src/NHibernate.sln index 2c7f1c7eb97..4eec9b87633 100644 --- a/src/NHibernate.sln +++ b/src/NHibernate.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\build-common\common.xml = ..\build-common\common.xml ..\appveyor.yml = ..\appveyor.yml ..\ReleaseProcedure.txt = ..\ReleaseProcedure.txt + ..\global.json = ..\global.json EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate", "NHibernate\NHibernate.csproj", "{5909BFE7-93CF-4E5F-BE22-6293368AF01D}" diff --git a/src/NHibernate/ADOException.cs b/src/NHibernate/ADOException.cs index f3c5108b5fd..c0aa5f01916 100644 --- a/src/NHibernate/ADOException.cs +++ b/src/NHibernate/ADOException.cs @@ -21,6 +21,7 @@ public class ADOException : HibernateException public ADOException() { } + /// /// Initializes a new instance of the class. /// @@ -50,17 +51,23 @@ public ADOException(string message, Exception innerException, string sql) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ADOException(SerializationInfo info, StreamingContext context) : base(info, context) { this.sql = (string) info.GetValue("sql", typeof(string)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("sql", sql); } +#pragma warning restore CS0809 public string SqlString { diff --git a/src/NHibernate/AdoNet/TooManyRowsAffectedException.cs b/src/NHibernate/AdoNet/TooManyRowsAffectedException.cs index bcf54ff1e63..e113040c659 100644 --- a/src/NHibernate/AdoNet/TooManyRowsAffectedException.cs +++ b/src/NHibernate/AdoNet/TooManyRowsAffectedException.cs @@ -18,13 +18,17 @@ public TooManyRowsAffectedException(String message, int expectedRowCount, int ac this.actualRowCount = actualRowCount; } - protected TooManyRowsAffectedException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected TooManyRowsAffectedException(SerializationInfo info, StreamingContext context) : base(info, context) { this.expectedRowCount = info.GetInt32("expectedRowCount"); this.actualRowCount = info.GetInt32("actualRowCount"); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -32,6 +36,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("expectedRowCount", expectedRowCount); info.AddValue("actualRowCount", actualRowCount); } +#pragma warning restore CS0809 public int ExpectedRowCount { diff --git a/src/NHibernate/AssertionFailure.cs b/src/NHibernate/AssertionFailure.cs index 52cbbdae11d..4c9bc955b51 100644 --- a/src/NHibernate/AssertionFailure.cs +++ b/src/NHibernate/AssertionFailure.cs @@ -52,6 +52,8 @@ public AssertionFailure(string message, Exception innerException) : base(message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected AssertionFailure(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Bytecode/HibernateByteCodeException.cs b/src/NHibernate/Bytecode/HibernateByteCodeException.cs index 803765f88a7..17126c8286e 100644 --- a/src/NHibernate/Bytecode/HibernateByteCodeException.cs +++ b/src/NHibernate/Bytecode/HibernateByteCodeException.cs @@ -10,6 +10,8 @@ public HibernateByteCodeException() {} public HibernateByteCodeException(string message) : base(message) {} public HibernateByteCodeException(string message, Exception inner) : base(message, inner) {} + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected HibernateByteCodeException(SerializationInfo info, StreamingContext context) : base(info, context) {} } -} \ No newline at end of file +} diff --git a/src/NHibernate/Bytecode/HibernateObjectsFactoryException.cs b/src/NHibernate/Bytecode/HibernateObjectsFactoryException.cs index f4551474bd0..95d4003c12f 100644 --- a/src/NHibernate/Bytecode/HibernateObjectsFactoryException.cs +++ b/src/NHibernate/Bytecode/HibernateObjectsFactoryException.cs @@ -13,6 +13,8 @@ public HibernateObjectsFactoryException() {} public HibernateObjectsFactoryException(string message) : base(message) {} public HibernateObjectsFactoryException(string message, Exception inner) : base(message, inner) {} + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected HibernateObjectsFactoryException(SerializationInfo info, StreamingContext context) : base(info, context) {} } } diff --git a/src/NHibernate/Bytecode/NotInstrumentedException.cs b/src/NHibernate/Bytecode/NotInstrumentedException.cs index 71a392b9b0a..c03a4a3044a 100644 --- a/src/NHibernate/Bytecode/NotInstrumentedException.cs +++ b/src/NHibernate/Bytecode/NotInstrumentedException.cs @@ -25,7 +25,8 @@ public NotInstrumentedException(string message) : base(message) } /// - protected NotInstrumentedException(SerializationInfo info, StreamingContext context) - : base(info, context) {} + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected NotInstrumentedException(SerializationInfo info, StreamingContext context) : base(info, context) {} } } diff --git a/src/NHibernate/Bytecode/UnableToLoadProxyFactoryFactoryException.cs b/src/NHibernate/Bytecode/UnableToLoadProxyFactoryFactoryException.cs index d37d031e370..10f81028196 100644 --- a/src/NHibernate/Bytecode/UnableToLoadProxyFactoryFactoryException.cs +++ b/src/NHibernate/Bytecode/UnableToLoadProxyFactoryFactoryException.cs @@ -13,8 +13,9 @@ public UnableToLoadProxyFactoryFactoryException(string typeName, Exception inner TypeName = typeName; } - protected UnableToLoadProxyFactoryFactoryException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected UnableToLoadProxyFactoryFactoryException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) { @@ -25,12 +26,16 @@ protected UnableToLoadProxyFactoryFactoryException(SerializationInfo info, Strea } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("TypeName", TypeName); } +#pragma warning restore CS0809 public string TypeName { get; } public override string Message diff --git a/src/NHibernate/Cache/CacheException.cs b/src/NHibernate/Cache/CacheException.cs index bb36a8bf039..20f92b96f77 100644 --- a/src/NHibernate/Cache/CacheException.cs +++ b/src/NHibernate/Cache/CacheException.cs @@ -60,8 +60,10 @@ public CacheException(string message, Exception innerException) : base(message, /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected CacheException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/CallbackException.cs b/src/NHibernate/CallbackException.cs index a0b3441eacc..26f288f2237 100644 --- a/src/NHibernate/CallbackException.cs +++ b/src/NHibernate/CallbackException.cs @@ -51,6 +51,8 @@ public CallbackException(string message, Exception innerException) : base(messag /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected CallbackException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Cfg/HibernateConfigException.cs b/src/NHibernate/Cfg/HibernateConfigException.cs index 4b04670b489..665b3c601ca 100644 --- a/src/NHibernate/Cfg/HibernateConfigException.cs +++ b/src/NHibernate/Cfg/HibernateConfigException.cs @@ -68,8 +68,9 @@ public HibernateConfigException(string message, Exception innerException) /// /// The that contains contextual information about the source or destination. /// - protected HibernateConfigException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected HibernateConfigException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/Classic/ValidationFailure.cs b/src/NHibernate/Classic/ValidationFailure.cs index 446dd5f7f4c..704f71b2295 100644 --- a/src/NHibernate/Classic/ValidationFailure.cs +++ b/src/NHibernate/Classic/ValidationFailure.cs @@ -61,6 +61,8 @@ public ValidationFailure(string message, Exception innerException) : base(messag /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ValidationFailure(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Collection/Generic/SetHelpers/SetSnapShot.cs b/src/NHibernate/Collection/Generic/SetHelpers/SetSnapShot.cs index 475bebf6c2e..0c0169f8b06 100644 --- a/src/NHibernate/Collection/Generic/SetHelpers/SetSnapShot.cs +++ b/src/NHibernate/Collection/Generic/SetHelpers/SetSnapShot.cs @@ -151,6 +151,8 @@ public SetSnapShot(IEnumerable collection) : base(collection) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SetSnapShot(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/DuplicateMappingException.cs b/src/NHibernate/DuplicateMappingException.cs index 3b9d43ce626..4fe33607324 100644 --- a/src/NHibernate/DuplicateMappingException.cs +++ b/src/NHibernate/DuplicateMappingException.cs @@ -41,8 +41,9 @@ public DuplicateMappingException(string type, string name) /// /// The that contains contextual information about the source or destination. /// - public DuplicateMappingException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + public DuplicateMappingException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) { @@ -57,6 +58,9 @@ public DuplicateMappingException(SerializationInfo info, StreamingContext contex } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -64,6 +68,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("Type", Type); info.AddValue("Name", Name); } +#pragma warning restore CS0809 /// /// The type of the duplicated object diff --git a/src/NHibernate/Exceptions/ADOConnectionException.cs b/src/NHibernate/Exceptions/ADOConnectionException.cs index 94611a6d5d9..b52f0c21e97 100644 --- a/src/NHibernate/Exceptions/ADOConnectionException.cs +++ b/src/NHibernate/Exceptions/ADOConnectionException.cs @@ -10,6 +10,8 @@ namespace NHibernate.Exceptions [Serializable] public class ADOConnectionException : ADOException { + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] public ADOConnectionException(SerializationInfo info, StreamingContext context) : base(info, context) {} public ADOConnectionException(string message, Exception innerException, string sql) : base(message, innerException, sql) {} public ADOConnectionException(string message, Exception innerException) : base(message, innerException) {} diff --git a/src/NHibernate/Exceptions/AggregateHibernateException.cs b/src/NHibernate/Exceptions/AggregateHibernateException.cs index d33b41a6d2d..8424bd65845 100644 --- a/src/NHibernate/Exceptions/AggregateHibernateException.cs +++ b/src/NHibernate/Exceptions/AggregateHibernateException.cs @@ -81,17 +81,23 @@ private AggregateHibernateException(string message, IList innerExcept /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected AggregateHibernateException(SerializationInfo info, StreamingContext context) : base(info, context) { InnerExceptions = (ReadOnlyCollection) info.GetValue("InnerExceptions", typeof(ReadOnlyCollection)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("InnerExceptions", InnerExceptions); } +#pragma warning restore CS0809 /// /// Return a string representation of the aggregate exception. diff --git a/src/NHibernate/Exceptions/ConstraintViolationException.cs b/src/NHibernate/Exceptions/ConstraintViolationException.cs index 0e933f3b4f3..0485bcc2d03 100644 --- a/src/NHibernate/Exceptions/ConstraintViolationException.cs +++ b/src/NHibernate/Exceptions/ConstraintViolationException.cs @@ -23,8 +23,9 @@ public ConstraintViolationException(string message, Exception innerException, st ConstraintName = constraintName; } - public ConstraintViolationException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + public ConstraintViolationException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) { @@ -35,12 +36,16 @@ public ConstraintViolationException(SerializationInfo info, StreamingContext con } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("ConstraintName", ConstraintName); } +#pragma warning restore CS0809 /// /// Returns the name of the violated constraint, if known. diff --git a/src/NHibernate/Exceptions/DataException.cs b/src/NHibernate/Exceptions/DataException.cs index 99357d5e194..bfcc749da65 100644 --- a/src/NHibernate/Exceptions/DataException.cs +++ b/src/NHibernate/Exceptions/DataException.cs @@ -11,6 +11,8 @@ namespace NHibernate.Exceptions [Serializable] public class DataException : ADOException { + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] public DataException(SerializationInfo info, StreamingContext context) : base(info, context) {} public DataException(string message, Exception innerException, string sql) : base(message, innerException, sql) {} public DataException(string message, Exception innerException) : base(message, innerException) {} diff --git a/src/NHibernate/Exceptions/GenericADOException.cs b/src/NHibernate/Exceptions/GenericADOException.cs index b82dcfeb2b1..fd93ab85d30 100644 --- a/src/NHibernate/Exceptions/GenericADOException.cs +++ b/src/NHibernate/Exceptions/GenericADOException.cs @@ -10,6 +10,8 @@ public class GenericADOException : ADOException public GenericADOException() { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] public GenericADOException(SerializationInfo info, StreamingContext context) : base(info, context) { } public GenericADOException(string message, Exception innerException, string sql) : base(message, innerException, sql) { } public GenericADOException(string message, Exception innerException) : base(message, innerException) { } diff --git a/src/NHibernate/Exceptions/LockAcquisitionException.cs b/src/NHibernate/Exceptions/LockAcquisitionException.cs index 58a774b13f6..67bf824d065 100644 --- a/src/NHibernate/Exceptions/LockAcquisitionException.cs +++ b/src/NHibernate/Exceptions/LockAcquisitionException.cs @@ -10,6 +10,8 @@ namespace NHibernate.Exceptions [Serializable] public class LockAcquisitionException : ADOException { + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] public LockAcquisitionException(SerializationInfo info, StreamingContext context) : base(info, context) {} public LockAcquisitionException(string message, Exception innerException, string sql) : base(message, innerException, sql) {} public LockAcquisitionException(string message, Exception innerException) : base(message, innerException) {} diff --git a/src/NHibernate/Exceptions/SQLGrammarException.cs b/src/NHibernate/Exceptions/SQLGrammarException.cs index 29f655daac8..1b9821e899a 100644 --- a/src/NHibernate/Exceptions/SQLGrammarException.cs +++ b/src/NHibernate/Exceptions/SQLGrammarException.cs @@ -10,6 +10,8 @@ namespace NHibernate.Exceptions [Serializable] public class SQLGrammarException : ADOException { + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] public SQLGrammarException(SerializationInfo info, StreamingContext context) : base(info, context) {} public SQLGrammarException(string message, Exception innerException, string sql) : base(message, innerException, sql) {} public SQLGrammarException(string message, Exception innerException) : base(message, innerException) {} diff --git a/src/NHibernate/Exceptions/SqlParseException.cs b/src/NHibernate/Exceptions/SqlParseException.cs index 758b3414afa..4b5a5ba6af2 100644 --- a/src/NHibernate/Exceptions/SqlParseException.cs +++ b/src/NHibernate/Exceptions/SqlParseException.cs @@ -10,6 +10,8 @@ public SqlParseException(string message) : base(message) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SqlParseException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/FKUnmatchingColumnsException.cs b/src/NHibernate/FKUnmatchingColumnsException.cs index 1a0c2996f5f..531bdaf1a5c 100644 --- a/src/NHibernate/FKUnmatchingColumnsException.cs +++ b/src/NHibernate/FKUnmatchingColumnsException.cs @@ -43,8 +43,9 @@ public FKUnmatchingColumnsException(string message, Exception innerException) /// /// The that contains contextual information about the source or destination. /// - protected FKUnmatchingColumnsException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected FKUnmatchingColumnsException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/HibernateException.cs b/src/NHibernate/HibernateException.cs index bc029882c25..1a3fe1d2131 100644 --- a/src/NHibernate/HibernateException.cs +++ b/src/NHibernate/HibernateException.cs @@ -63,8 +63,10 @@ public HibernateException(string message, Exception innerException) : base(messa /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected HibernateException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/DetailedSemanticException.cs b/src/NHibernate/Hql/Ast/ANTLR/DetailedSemanticException.cs index 4e01696df12..8dd5e6a13da 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/DetailedSemanticException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/DetailedSemanticException.cs @@ -15,6 +15,8 @@ public DetailedSemanticException(string message, Exception inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected DetailedSemanticException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Hql/Ast/ANTLR/InvalidPathException.cs b/src/NHibernate/Hql/Ast/ANTLR/InvalidPathException.cs index 6ca3a9b75c4..77903067fc2 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/InvalidPathException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/InvalidPathException.cs @@ -15,6 +15,8 @@ public InvalidPathException(string s) : base(s) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected InvalidPathException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Hql/Ast/ANTLR/InvalidWithClauseException.cs b/src/NHibernate/Hql/Ast/ANTLR/InvalidWithClauseException.cs index 119e5c8163a..caacf575621 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/InvalidWithClauseException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/InvalidWithClauseException.cs @@ -11,6 +11,8 @@ protected InvalidWithClauseException() {} public InvalidWithClauseException(string message) : base(message) {} public InvalidWithClauseException(string message, Exception inner) : base(message, inner) {} + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected InvalidWithClauseException(SerializationInfo info, StreamingContext context) : base(info, context) {} } -} \ No newline at end of file +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs b/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs index 252a99416f5..cd588ac2cb5 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs @@ -15,6 +15,8 @@ public QuerySyntaxException(string message, string hql, Exception inner) : base( public QuerySyntaxException(string message) : base(message) {} public QuerySyntaxException(string message, Exception inner) : base(message, inner) {} + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QuerySyntaxException(SerializationInfo info, StreamingContext context) : base(info, context) {} public static QuerySyntaxException Convert(RecognitionException e) diff --git a/src/NHibernate/Hql/Ast/ANTLR/SemanticException.cs b/src/NHibernate/Hql/Ast/ANTLR/SemanticException.cs index e30b7aabb4b..9b280edc7e4 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/SemanticException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/SemanticException.cs @@ -15,6 +15,8 @@ public SemanticException(string message, Exception inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SemanticException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Hql/QueryExecutionRequestException.cs b/src/NHibernate/Hql/QueryExecutionRequestException.cs index c471d5f55ce..ee112c25819 100644 --- a/src/NHibernate/Hql/QueryExecutionRequestException.cs +++ b/src/NHibernate/Hql/QueryExecutionRequestException.cs @@ -10,6 +10,8 @@ public QueryExecutionRequestException(string message, string queryString) : base { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QueryExecutionRequestException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/Id/IdentifierGenerationException.cs b/src/NHibernate/Id/IdentifierGenerationException.cs index 1d76d44aec3..cb781005039 100644 --- a/src/NHibernate/Id/IdentifierGenerationException.cs +++ b/src/NHibernate/Id/IdentifierGenerationException.cs @@ -48,8 +48,10 @@ public IdentifierGenerationException(string message, Exception e) : base(message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected IdentifierGenerationException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/InstantiationException.cs b/src/NHibernate/InstantiationException.cs index 08496bffdc2..df7a57c41cd 100644 --- a/src/NHibernate/InstantiationException.cs +++ b/src/NHibernate/InstantiationException.cs @@ -74,11 +74,14 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected InstantiationException(SerializationInfo info, StreamingContext context) : base(info, context) { this.type = info.GetValue("type", typeof(System.Type)) as System.Type; } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -90,12 +93,15 @@ protected InstantiationException(SerializationInfo info, StreamingContext contex /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("type", type, typeof(System.Type)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/InvalidProxyTypeException.cs b/src/NHibernate/InvalidProxyTypeException.cs index 946478379ba..8eb770cf2e5 100644 --- a/src/NHibernate/InvalidProxyTypeException.cs +++ b/src/NHibernate/InvalidProxyTypeException.cs @@ -36,18 +36,23 @@ private static string FormatMessage(IEnumerable errors) #region Serialization - public InvalidProxyTypeException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + public InvalidProxyTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { - Errors = (ICollection)info.GetValue("errors", typeof(ICollection)); + Errors = (ICollection) info.GetValue("errors", typeof(ICollection)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("errors", Errors, typeof (ICollection)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/LazyInitializationException.cs b/src/NHibernate/LazyInitializationException.cs index 83cf6123541..0bbbb3e838b 100644 --- a/src/NHibernate/LazyInitializationException.cs +++ b/src/NHibernate/LazyInitializationException.cs @@ -74,6 +74,8 @@ public LazyInitializationException(string message, Exception innerException) : b /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected LazyInitializationException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) @@ -89,6 +91,9 @@ protected LazyInitializationException(SerializationInfo info, StreamingContext c } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -96,5 +101,6 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("EntityName", EntityName); info.AddValue("EntityId", EntityId, typeof(object)); } +#pragma warning restore CS0809 } } diff --git a/src/NHibernate/MappingException.cs b/src/NHibernate/MappingException.cs index b02ed5dc0b0..2d4226158d0 100644 --- a/src/NHibernate/MappingException.cs +++ b/src/NHibernate/MappingException.cs @@ -57,9 +57,10 @@ public MappingException(string message, Exception innerException) /// /// The that contains contextual information about the source or destination. /// - protected MappingException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected MappingException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 463078ec0dc..7440dc9429e 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -54,6 +54,10 @@ + + + + diff --git a/src/NHibernate/NonUniqueObjectException.cs b/src/NHibernate/NonUniqueObjectException.cs index ba7f60e4ffc..ba695cb8bb0 100644 --- a/src/NHibernate/NonUniqueObjectException.cs +++ b/src/NHibernate/NonUniqueObjectException.cs @@ -61,13 +61,15 @@ public string EntityName /// /// Initializes a new instance of the class. /// - protected NonUniqueObjectException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected NonUniqueObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { identifier = info.GetValue("identifier", typeof(Object)); entityName = info.GetValue("entityName", typeof(string)) as string; } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -79,6 +81,8 @@ protected NonUniqueObjectException(SerializationInfo info, StreamingContext cont /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -86,6 +90,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("identifier", identifier, typeof(Object)); info.AddValue("entityName", entityName, typeof(string)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/NonUniqueResultException.cs b/src/NHibernate/NonUniqueResultException.cs index 82ff46f6de5..81038d8e157 100644 --- a/src/NHibernate/NonUniqueResultException.cs +++ b/src/NHibernate/NonUniqueResultException.cs @@ -32,8 +32,9 @@ public NonUniqueResultException(int resultCount) /// /// The that contains contextual information about the source or destination. /// - protected NonUniqueResultException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected NonUniqueResultException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/ObjectDeletedException.cs b/src/NHibernate/ObjectDeletedException.cs index c3ee6a853c6..b763a97ba92 100644 --- a/src/NHibernate/ObjectDeletedException.cs +++ b/src/NHibernate/ObjectDeletedException.cs @@ -30,10 +30,12 @@ public ObjectDeletedException(string message, object identifier, string clazz) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ObjectDeletedException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs b/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs index f61442aaefc..9ffb72c47f3 100644 --- a/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs +++ b/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs @@ -36,13 +36,17 @@ public ObjectNotFoundByUniqueKeyException(string entityName, string propertyName #region Serialization - protected ObjectNotFoundByUniqueKeyException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected ObjectNotFoundByUniqueKeyException(SerializationInfo info, StreamingContext context) : base(info, context) { Key = info.GetValue(nameof(Key), typeof(object)); PropertyName = info.GetString(nameof(PropertyName)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -50,6 +54,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue(nameof(Key), Key); info.AddValue(nameof(PropertyName), PropertyName); } +#pragma warning restore CS0809 #endregion Serialization } diff --git a/src/NHibernate/ObjectNotFoundException.cs b/src/NHibernate/ObjectNotFoundException.cs index d09447b44b8..71fb3705c4e 100644 --- a/src/NHibernate/ObjectNotFoundException.cs +++ b/src/NHibernate/ObjectNotFoundException.cs @@ -38,10 +38,12 @@ public ObjectNotFoundException(object identifier, string entityName) : base(iden /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ObjectNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/PersistentObjectException.cs b/src/NHibernate/PersistentObjectException.cs index 0a3d7cc7563..e6384138424 100644 --- a/src/NHibernate/PersistentObjectException.cs +++ b/src/NHibernate/PersistentObjectException.cs @@ -29,8 +29,10 @@ public PersistentObjectException(string message) : base(message) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected PersistentObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/PropertyAccessException.cs b/src/NHibernate/PropertyAccessException.cs index 47666cd249a..66f9608698d 100644 --- a/src/NHibernate/PropertyAccessException.cs +++ b/src/NHibernate/PropertyAccessException.cs @@ -81,6 +81,8 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected PropertyAccessException(SerializationInfo info, StreamingContext context) : base(info, context) { persistentType = info.GetValue("persistentType", typeof(System.Type)) as System.Type; @@ -88,6 +90,7 @@ protected PropertyAccessException(SerializationInfo info, StreamingContext conte wasSetter = info.GetBoolean("wasSetter"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -99,6 +102,8 @@ protected PropertyAccessException(SerializationInfo info, StreamingContext conte /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -107,7 +112,8 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("propertyName", propertyName); info.AddValue("wasSetter", wasSetter); } +#pragma warning restore CS0809 #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/PropertyNotFoundException.cs b/src/NHibernate/PropertyNotFoundException.cs index d64108eaae3..3a13d5eb256 100644 --- a/src/NHibernate/PropertyNotFoundException.cs +++ b/src/NHibernate/PropertyNotFoundException.cs @@ -59,8 +59,9 @@ public PropertyNotFoundException(string propertyName, string fieldName, System.T /// /// The that contains contextual information about the source or destination. /// - protected PropertyNotFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected PropertyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) { @@ -81,6 +82,9 @@ protected PropertyNotFoundException(SerializationInfo info, StreamingContext con } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -89,6 +93,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("PropertyName", PropertyName); info.AddValue("AccessorType", AccessorType); } +#pragma warning restore CS0809 public System.Type TargetType { get; } diff --git a/src/NHibernate/PropertyValueException.cs b/src/NHibernate/PropertyValueException.cs index c58d57ed75f..fe62bd72b83 100644 --- a/src/NHibernate/PropertyValueException.cs +++ b/src/NHibernate/PropertyValueException.cs @@ -64,13 +64,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// - protected PropertyValueException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected PropertyValueException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; propertyName = info.GetString("propertyName"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -82,6 +84,8 @@ protected PropertyValueException(SerializationInfo info, StreamingContext contex /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -89,6 +93,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName); info.AddValue("propertyName", propertyName); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/QueryException.cs b/src/NHibernate/QueryException.cs index ff16cad0489..e26275d950e 100644 --- a/src/NHibernate/QueryException.cs +++ b/src/NHibernate/QueryException.cs @@ -112,11 +112,14 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QueryException(SerializationInfo info, StreamingContext context) : base(info, context) { queryString = info.GetString("queryString"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -128,12 +131,15 @@ protected QueryException(SerializationInfo info, StreamingContext context) : bas /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("queryString", queryString, typeof(String)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/QueryParameterException.cs b/src/NHibernate/QueryParameterException.cs index 959ab847de4..7948b0549b1 100644 --- a/src/NHibernate/QueryParameterException.cs +++ b/src/NHibernate/QueryParameterException.cs @@ -9,6 +9,8 @@ public class QueryParameterException : QueryException // TODO : without default constructor can't be serialized public QueryParameterException(string message) : base(message) { } public QueryParameterException(string message, Exception inner) : base(message, inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QueryParameterException(SerializationInfo info,StreamingContext context): base(info, context) { } } } diff --git a/src/NHibernate/SchemaValidationException.cs b/src/NHibernate/SchemaValidationException.cs index 2d654a07583..fdb2d0bc1b6 100644 --- a/src/NHibernate/SchemaValidationException.cs +++ b/src/NHibernate/SchemaValidationException.cs @@ -16,17 +16,23 @@ public SchemaValidationException(string msg, IList validationErrors) : b ValidationErrors = new ReadOnlyCollection(validationErrors); } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SchemaValidationException(SerializationInfo info, StreamingContext context) : base(info, context) { ValidationErrors = (ReadOnlyCollection) info.GetValue("ValidationErrors", typeof(ReadOnlyCollection)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("ValidationErrors", ValidationErrors); } +#pragma warning restore CS0809 } } diff --git a/src/NHibernate/SessionException.cs b/src/NHibernate/SessionException.cs index 96ce8ccc697..0c082fcb9ce 100644 --- a/src/NHibernate/SessionException.cs +++ b/src/NHibernate/SessionException.cs @@ -11,8 +11,9 @@ public SessionException(string message) { } - protected SessionException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected SessionException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/StaleObjectStateException.cs b/src/NHibernate/StaleObjectStateException.cs index b53e0155f53..a7e1d8f10cf 100644 --- a/src/NHibernate/StaleObjectStateException.cs +++ b/src/NHibernate/StaleObjectStateException.cs @@ -80,12 +80,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected StaleObjectStateException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; identifier = info.GetValue("identifier", typeof(object)); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -97,6 +100,8 @@ protected StaleObjectStateException(SerializationInfo info, StreamingContext con /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -104,6 +109,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName, typeof(string)); info.AddValue("identifier", identifier, typeof(object)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/StaleStateException.cs b/src/NHibernate/StaleStateException.cs index 2a08cc4e9be..b64ba058b6f 100644 --- a/src/NHibernate/StaleStateException.cs +++ b/src/NHibernate/StaleStateException.cs @@ -13,8 +13,9 @@ public StaleStateException(string message, Exception innerException) : base(mess { } - protected StaleStateException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected StaleStateException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/TransactionException.cs b/src/NHibernate/TransactionException.cs index e5964844593..f9a91236492 100644 --- a/src/NHibernate/TransactionException.cs +++ b/src/NHibernate/TransactionException.cs @@ -41,8 +41,10 @@ public TransactionException(string message, Exception innerException) : base(mes /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TransactionException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/TransientObjectException.cs b/src/NHibernate/TransientObjectException.cs index eb55554248e..42e1eb10da3 100644 --- a/src/NHibernate/TransientObjectException.cs +++ b/src/NHibernate/TransientObjectException.cs @@ -29,8 +29,10 @@ public TransientObjectException(string message) : base(message) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TransientObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs b/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs index 0a4075ca643..7584c3456db 100644 --- a/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs +++ b/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs @@ -37,7 +37,7 @@ protected override object CreateInstance() return base.CreateInstance(); } - var entity = _proxyFactory.GetFieldInterceptionProxy(base.CreateInstance); + var entity = ProxyFactoryExtensions.GetFieldInterceptionProxy(_proxyFactory, base.CreateInstance); _entityMetamodel.BytecodeEnhancementMetadata.InjectInterceptor(entity, null); return entity; } diff --git a/src/NHibernate/Tuple/PocoInstantiator.cs b/src/NHibernate/Tuple/PocoInstantiator.cs index 6af0682e6c6..3f4258e921d 100644 --- a/src/NHibernate/Tuple/PocoInstantiator.cs +++ b/src/NHibernate/Tuple/PocoInstantiator.cs @@ -100,11 +100,13 @@ public object Instantiate() { throw new InstantiationException("Cannot instantiate abstract class or interface: ", mappedClass); } + // 6.0 TODO: Remove if statement if (generateFieldInterceptionProxy) { - return proxyFactory.GetFieldInterceptionProxy(CreateInstance); + return ProxyFactoryExtensions.GetFieldInterceptionProxy(proxyFactory, CreateInstance); } + return CreateInstance(); } diff --git a/src/NHibernate/Type/SerializationException.cs b/src/NHibernate/Type/SerializationException.cs index 1118dbf5487..18fe754d3a2 100644 --- a/src/NHibernate/Type/SerializationException.cs +++ b/src/NHibernate/Type/SerializationException.cs @@ -49,8 +49,10 @@ public SerializationException(string message, Exception e) : base(message, e) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SerializationException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/TypeMismatchException.cs b/src/NHibernate/TypeMismatchException.cs index 5e511d6dadc..d3568109f01 100644 --- a/src/NHibernate/TypeMismatchException.cs +++ b/src/NHibernate/TypeMismatchException.cs @@ -11,6 +11,8 @@ public class TypeMismatchException : HibernateException { public TypeMismatchException(string message) : base(message) { } public TypeMismatchException(string message, Exception inner) : base(message, inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TypeMismatchException(SerializationInfo info,StreamingContext context): base(info, context) { } } } diff --git a/src/NHibernate/UnresolvableObjectException.cs b/src/NHibernate/UnresolvableObjectException.cs index d766bf2881a..75be1da8251 100644 --- a/src/NHibernate/UnresolvableObjectException.cs +++ b/src/NHibernate/UnresolvableObjectException.cs @@ -92,6 +92,9 @@ public static void ThrowIfNull(object o, object id, string entityName) #region ISerializable Members +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -100,9 +103,11 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("clazz", clazz); info.AddValue("entityName", entityName); } +#pragma warning restore CS0809 - protected UnresolvableObjectException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected UnresolvableObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { identifier = info.GetValue("identifier", typeof(object)); clazz = info.GetValue("clazz", typeof(System.Type)) as System.Type; diff --git a/src/NHibernate/Util/TypeNameParser.cs b/src/NHibernate/Util/TypeNameParser.cs index 6a56f862fb0..5d90c7bb4b5 100644 --- a/src/NHibernate/Util/TypeNameParser.cs +++ b/src/NHibernate/Util/TypeNameParser.cs @@ -12,6 +12,8 @@ public class ParserException : Exception { public ParserException(string message) : base(message) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ParserException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/WrongClassException.cs b/src/NHibernate/WrongClassException.cs index 90c7f1024dc..3018636d031 100644 --- a/src/NHibernate/WrongClassException.cs +++ b/src/NHibernate/WrongClassException.cs @@ -69,12 +69,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected WrongClassException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; identifier = info.GetValue("identifier", typeof(object)); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -86,6 +89,8 @@ protected WrongClassException(SerializationInfo info, StreamingContext context) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -93,6 +98,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName, typeof(string)); info.AddValue("identifier", identifier, typeof(object)); } +#pragma warning restore CS0809 #endregion } From f6af433af4b8b6aa8ff7eac9f5a03da88599a011 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 07:09:16 +0100 Subject: [PATCH 075/128] Update dependency gitreleasemanager.tool to v0.17.0 (#3372) --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index a988ff3648e..338a0f24652 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "gitreleasemanager.tool": { - "version": "0.11.0", + "version": "0.17.0", "commands": [ "dotnet-gitreleasemanager" ] From d1790e7d3bb408346059e21279635fb7ac1a902d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:16:33 +1000 Subject: [PATCH 076/128] Update dependency NUnit.Console to v3.17.0 (#3501) --- Tools/packages.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/packages.csproj b/Tools/packages.csproj index 5ec330d2986..5ca61c1f8fc 100644 --- a/Tools/packages.csproj +++ b/Tools/packages.csproj @@ -11,7 +11,7 @@ - + From 344b7f3702eae46a7b8fde0b847dff50ce44fd07 Mon Sep 17 00:00:00 2001 From: Mihai <961778+mihaicodrean@users.noreply.github.com> Date: Sat, 23 Mar 2024 22:25:34 +0200 Subject: [PATCH 077/128] Inserting multiple associations of the same entity fails (#3489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericdelaporte@users.noreply.github.com> --- .../BulkManipulation/HQLBulkOperations.cs | 18 +++++++++++- .../BulkManipulation/Course.cs | 8 +++++ .../BulkManipulation/Enrolment.cs | 12 ++++++++ .../BulkManipulation/Enrolment.hbm.xml | 29 +++++++++++++++++++ .../BulkManipulation/HQLBulkOperations.cs | 18 +++++++++++- .../BulkManipulation/Student.cs | 8 +++++ .../Hql/Ast/ANTLR/Tree/SelectClause.cs | 2 +- 7 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 src/NHibernate.Test/BulkManipulation/Course.cs create mode 100644 src/NHibernate.Test/BulkManipulation/Enrolment.cs create mode 100644 src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml create mode 100644 src/NHibernate.Test/BulkManipulation/Student.cs diff --git a/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs b/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs index 4dd0de91f8e..2bc13bba995 100644 --- a/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs +++ b/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs @@ -43,5 +43,21 @@ public async Task SimpleDeleteAsync() await (tx.CommitAsync()); } } + + [Test] + public async Task InsertFromSelectWithMultipleAssociationsAsync() + { + Assume.That(TestDialect.NativeGeneratorSupportsBulkInsertion, + "The dialect does not support a native generator compatible with bulk insertion."); + + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + + await (s.CreateQuery("insert into Enrolment (Course, Student)" + + " select e.Course, e.Student from Enrolment e") + .ExecuteUpdateAsync()); + + await (tx.CommitAsync()); + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/BulkManipulation/Course.cs b/src/NHibernate.Test/BulkManipulation/Course.cs new file mode 100644 index 00000000000..0ceb699b8f6 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Course.cs @@ -0,0 +1,8 @@ +namespace NHibernate.Test.BulkManipulation +{ + public class Course + { + public virtual long CourseId { get; set; } + public virtual string Description { get; set; } + } +} diff --git a/src/NHibernate.Test/BulkManipulation/Enrolment.cs b/src/NHibernate.Test/BulkManipulation/Enrolment.cs new file mode 100644 index 00000000000..547ecd52640 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Enrolment.cs @@ -0,0 +1,12 @@ +using System; + +namespace NHibernate.Test.BulkManipulation +{ + [Serializable] + public class Enrolment + { + public virtual long EnrolmentId { get; set; } + public virtual Student Student { get; set; } + public virtual Course Course { get; set; } + } +} diff --git a/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml b/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml new file mode 100644 index 00000000000..84e6a0b293d --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs b/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs index 66883da2301..4338c5148b5 100644 --- a/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs +++ b/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs @@ -32,5 +32,21 @@ public void SimpleDelete() tx.Commit(); } } + + [Test] + public void InsertFromSelectWithMultipleAssociations() + { + Assume.That(TestDialect.NativeGeneratorSupportsBulkInsertion, + "The dialect does not support a native generator compatible with bulk insertion."); + + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + + s.CreateQuery("insert into Enrolment (Course, Student)" + + " select e.Course, e.Student from Enrolment e") + .ExecuteUpdate(); + + tx.Commit(); + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/BulkManipulation/Student.cs b/src/NHibernate.Test/BulkManipulation/Student.cs new file mode 100644 index 00000000000..6dd9468adf3 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Student.cs @@ -0,0 +1,8 @@ +namespace NHibernate.Test.BulkManipulation +{ + public class Student + { + public virtual long StudentId { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/SelectClause.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/SelectClause.cs index 6119f5642e7..00993891bba 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/SelectClause.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/SelectClause.cs @@ -494,7 +494,7 @@ private void RenderNonScalarIdentifiers( } var node = (IASTNode) e; - if (processedElements.Add(fromElement)) + if (Walker.IsShallowQuery && node.Type == SqlGenerator.DOT || processedElements.Add(fromElement)) { combinedFromElements.Add(fromElement); RenderNonScalarIdentifiers(fromElement, inheritedExpressions.ContainsKey(e) ? null : e, appender); From 16f71d2ec6d8b3246e3140985d5711775b670617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:33:07 +0100 Subject: [PATCH 078/128] Enable 5.4.8 dev builds --- build-common/NHibernate.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index b36961fc58a..1fab9ed8b19 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,9 +3,9 @@ 5.4 - 7 + 8 - + dev 9.0 $(NhVersion).$(VersionPatch) From b3256e7e585fc2f12bd42487d31e9c45eb748a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 26 Mar 2024 20:21:49 +0100 Subject: [PATCH 079/128] Release 5.4.8 (#3507) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 1fab9ed8b19..a614470a18b 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.4 8 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index f9fbf217f26..2351054af6c 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,20 @@ -Build 5.4.7 +Build 5.4.8 +============================= + +Release notes - NHibernate - Version 5.4.8 + +2 issues were resolved in this release. + +** Bug + + * #3489 Inserting multiple associations of the same entity fails + +** Task + + * #3507 Release 5.4.8 + + +Build 5.4.7 ============================= Release notes - NHibernate - Version 5.4.7 From f25b398d897d937a21eda9ae065638f029256e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 28 Mar 2024 20:00:50 +0100 Subject: [PATCH 080/128] Release 5.5.1 (#3509) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 11300e597e8..d56d15ccbc4 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.5 1 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index 16c9cc81b84..9946de3fe76 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,21 @@ -Build 5.5.0 +Build 5.5.1 +============================= + +Release notes - NHibernate - Version 5.5.1 + +3 issues were resolved in this release. + +** Bug + + * #3465 Invalid SQL created for some joins in a subquery + +** Task + + * #3509 Release 5.5.1 + * #3508 Merge 5.4.8 into 5.5.x + + +Build 5.5.0 ============================= Release notes - NHibernate - Version 5.5.0 From 5a4823ea284b89560d3cdb75e54c5ef99f9a4138 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 5 Apr 2024 09:22:50 +1000 Subject: [PATCH 081/128] Fix reference errors in XML comments (#3519) --- src/NHibernate/Criterion/MatchMode.cs | 10 +++++----- .../Linq/Visitors/PreTransformationParameters.cs | 2 +- .../Linq/Visitors/PreTransformationResult.cs | 2 +- src/NHibernate/Multi/LinqBatchItem.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NHibernate/Criterion/MatchMode.cs b/src/NHibernate/Criterion/MatchMode.cs index c83f4031ff5..27b10c07602 100644 --- a/src/NHibernate/Criterion/MatchMode.cs +++ b/src/NHibernate/Criterion/MatchMode.cs @@ -92,7 +92,7 @@ public override string ToString() private class ExactMatchMode : MatchMode { /// - /// Initialize a new instance of the class. + /// Initialize a new instance of the class. /// public ExactMatchMode() : base(0, "EXACT") { @@ -115,7 +115,7 @@ public override string ToMatchString(string pattern) private class StartMatchMode : MatchMode { /// - /// Initialize a new instance of the class. + /// Initialize a new instance of the class. /// public StartMatchMode() : base(1, "START") { @@ -138,7 +138,7 @@ public override string ToMatchString(string pattern) private class EndMatchMode : MatchMode { /// - /// Initialize a new instance of the class. + /// Initialize a new instance of the class. /// public EndMatchMode() : base(2, "END") { @@ -162,7 +162,7 @@ public override string ToMatchString(string pattern) private class AnywhereMatchMode : MatchMode { /// - /// Initialize a new instance of the class. + /// Initialize a new instance of the class. /// public AnywhereMatchMode() : base(3, "ANYWHERE") { @@ -179,4 +179,4 @@ public override string ToMatchString(string pattern) } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Linq/Visitors/PreTransformationParameters.cs b/src/NHibernate/Linq/Visitors/PreTransformationParameters.cs index c5f713216a8..6f70d21cda6 100644 --- a/src/NHibernate/Linq/Visitors/PreTransformationParameters.cs +++ b/src/NHibernate/Linq/Visitors/PreTransformationParameters.cs @@ -7,7 +7,7 @@ namespace NHibernate.Linq.Visitors { /// - /// Contains the information needed by to perform an early transformation. + /// Contains the information needed by to perform an early transformation. /// public class PreTransformationParameters { diff --git a/src/NHibernate/Linq/Visitors/PreTransformationResult.cs b/src/NHibernate/Linq/Visitors/PreTransformationResult.cs index 6f55ddc7bba..ec0d527e9a9 100644 --- a/src/NHibernate/Linq/Visitors/PreTransformationResult.cs +++ b/src/NHibernate/Linq/Visitors/PreTransformationResult.cs @@ -5,7 +5,7 @@ namespace NHibernate.Linq.Visitors { /// - /// The result of method. + /// The result of method. /// public class PreTransformationResult { diff --git a/src/NHibernate/Multi/LinqBatchItem.cs b/src/NHibernate/Multi/LinqBatchItem.cs index 733b3115505..de9d951118a 100644 --- a/src/NHibernate/Multi/LinqBatchItem.cs +++ b/src/NHibernate/Multi/LinqBatchItem.cs @@ -43,7 +43,7 @@ private static LinqBatchItem GetForQuery(IQueryable query, Exp } /// - /// Create instance via methods + /// Create instance via methods /// /// Result type public partial class LinqBatchItem : QueryBatchItem, ILinqBatchItem From f3afcf91ff70cc893109a2b66eecd1011f6d0042 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sat, 6 Apr 2024 13:24:03 +1000 Subject: [PATCH 082/128] Add workaround for Rider to see the Antlr3 generated files at design time (#3518) --- .editorconfig | 11 ++--------- src/NHibernate/NHibernate.csproj | 13 +++++++++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.editorconfig b/.editorconfig index da812d88d1b..f0af598780e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -37,17 +37,10 @@ indent_style = tab indent_style = space indent_size = 2 -[*.xml] -indent_style = space -indent_size = 2 - -[*.csproj] -indent_style = space -indent_size = 2 - -[*.vbproj] +[{*.xml,*.csproj,*.vbproj}] indent_style = space indent_size = 2 +ij_xml_space_inside_empty_tag = true [*.g] indent_style = tab diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 7440dc9429e..3fb89402adf 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -1,4 +1,4 @@ - + @@ -14,7 +14,7 @@ ORM; O/RM; DataBase; DAL; ObjectRelationalMapping; NHibernate; ADO.Net; Core NHibernate.readme.md - + @@ -92,4 +92,13 @@ + + + + + From 3e1c0f0ac991dee0226f8e7efb13f458295b31cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 12:36:28 +0200 Subject: [PATCH 083/128] Update dependency NUnit.Analyzers to v4.1.0 (#3521) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index ee64e604146..852d35d6783 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -71,7 +71,7 @@ - + From 0d92dd8fb2a74eee7ff312bffc422c3e118dc1f7 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 8 Apr 2024 09:49:02 +1000 Subject: [PATCH 084/128] Fix NUnit2050 warnings in tests (#3522) --- .editorconfig | 2 -- .../Criteria/Lambda/IntegrationFixture.cs | 2 +- .../Async/Criteria/ProjectionsTest.cs | 2 +- .../Criteria/SelectModeTest/SelectModeTest.cs | 2 +- .../Async/Extralazy/ExtraLazyFixture.cs | 19 +++++++-------- .../Async/Hql/Ast/BulkManipulation.cs | 2 +- .../NativeGuid/NativeGuidGeneratorFixture.cs | 2 +- .../Async/Linq/FunctionTests.cs | 8 +++---- .../Async/NHSpecificTest/NH1253/Fixture.cs | 2 +- .../NativeSqlCollectionLoaderFixture.cs | 8 +++---- .../NH2195/SQLiteMultiCriteriaTest.cs | 4 ++-- .../NH3023/DeadlockConnectionPoolIssueTest.cs | 12 +++++----- .../Async/NHSpecificTest/NH3952/Fixture.cs | 2 +- .../NHSpecificTest/NH940/NH940Fixture.cs | 2 +- .../SqlConverterAndMultiQuery/Fixture.cs | 4 ++-- .../DistributedSystemTransactionFixture.cs | 5 ++-- .../SystemTransactionFixture.cs | 10 ++++---- .../SchemaValidateTableWithSchemaFixture.cs | 4 ++-- .../AsyncLocalSessionContextFixture.cs | 6 ++--- .../ThreadStaticSessionContextFixture.cs | 6 ++--- .../Criteria/Lambda/IntegrationFixture.cs | 2 +- .../Criteria/ProjectionsTest.cs | 2 +- .../Criteria/SelectModeTest/SelectModeTest.cs | 2 +- .../DialectTest/MsSql2005DialectFixture.cs | 6 ++--- .../DialectTest/MsSql2012DialectFixture.cs | 6 ++--- .../OracleDataClientDriverFixture.cs | 2 +- .../Extralazy/ExtraLazyFixture.cs | 19 +++++++-------- src/NHibernate.Test/Futures/FutureFixture.cs | 2 +- .../Hql/Ast/BulkManipulation.cs | 2 +- .../NativeGuid/NativeGuidGeneratorFixture.cs | 2 +- src/NHibernate.Test/Linq/FunctionTests.cs | 8 +++---- .../MappingTest/NonReflectiveBinderFixture.cs | 2 +- src/NHibernate.Test/NHAssert.cs | 24 +++++++++---------- .../NHSpecificTest/NH1253/Fixture.cs | 2 +- .../NativeSqlCollectionLoaderFixture.cs | 8 +++---- .../NH2195/SQLiteMultiCriteriaTest.cs | 4 ++-- .../NH3023/DeadlockConnectionPoolIssueTest.cs | 12 +++++----- .../NHSpecificTest/NH3850/MainFixture.cs | 12 +++++----- .../NHSpecificTest/NH3952/Fixture.cs | 20 +++++++--------- .../NHSpecificTest/NH940/NH940Fixture.cs | 2 +- .../SqlConverterAndMultiQuery/Fixture.cs | 4 ++-- src/NHibernate.Test/ProxyTest/PeVerifier.cs | 6 ++++- .../SqlCommandTest/SqlTokenizerFixture.cs | 13 +++++----- .../DistributedSystemTransactionFixture.cs | 7 +++--- .../SystemTransactionFixture.cs | 10 ++++---- .../SchemaValidateTableWithSchemaFixture.cs | 4 ++-- .../TypesTest/SerializableTypesFixture.cs | 2 +- .../TypesTest/TypeFactoryFixture.cs | 2 +- 48 files changed, 143 insertions(+), 148 deletions(-) diff --git a/.editorconfig b/.editorconfig index f0af598780e..15901d7cb25 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,8 +25,6 @@ dotnet_diagnostic.NUnit2006.severity = suggestion dotnet_diagnostic.NUnit2015.severity = suggestion dotnet_diagnostic.NUnit2031.severity = suggestion dotnet_diagnostic.NUnit2049.severity = suggestion -# NUnit 4 no longer supports string.Format specification for Assert -dotnet_diagnostic.NUnit2050.severity = suggestion # The SameAs constraint always fails on value types as the actual and the expected value cannot be the same reference dotnet_diagnostic.NUnit2040.severity = suggestion diff --git a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs index df178490384..c9a7f52a39c 100644 --- a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs @@ -358,7 +358,7 @@ public async Task MultiCriteriaAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); await (SetupPagingDataAsync()); diff --git a/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs b/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs index aca0e5d3660..5c4e82bc1fc 100644 --- a/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs +++ b/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs @@ -91,7 +91,7 @@ public async Task UsingSqlFunctions_Concat_WithCastAsync() { if(Dialect is Oracle8iDialect) { - Assert.Ignore("Not supported by the active dialect:{0}.", Dialect); + Assert.Ignore($"Not supported by the active dialect:{Dialect}."); } if (TestDialect.HasBrokenTypeInferenceOnSelectedParameters) Assert.Ignore("Current dialect does not support this test"); diff --git a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs index a54bec846f6..072a983f142 100644 --- a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs @@ -663,7 +663,7 @@ public async Task FetchModeEagerForEagerAsync() private void SkipFutureTestIfNotSupported() { if (Sfi.ConnectionProvider.Driver.SupportsMultipleQueries == false) - Assert.Ignore("Driver {0} does not support multi-queries", Sfi.ConnectionProvider.Driver.GetType().FullName); + Assert.Ignore($"Driver {Sfi.ConnectionProvider.Driver.GetType().FullName} does not support multi-queries"); } #region Test Setup diff --git a/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs b/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs index 351cb7daa3c..113983227d3 100644 --- a/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs +++ b/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs @@ -114,7 +114,7 @@ public async Task ListAddAsync(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after checking existence of non-flushed"); @@ -322,7 +322,7 @@ public async Task ListInsertAsync(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after existence check"); @@ -636,7 +636,7 @@ public async Task ListGetSetAsync(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), "Comparing added company at index {0}", i); + Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), $"Comparing added company at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after adding comparing"); @@ -676,7 +676,7 @@ public async Task ListGetSetAsync(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company ListIndex at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after comparing"); @@ -798,7 +798,7 @@ public async Task ListFlushAsync(bool initialize) { for (var i = 15; i < 20; i++) { - Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, "Removing transient company at index {0}", i); + Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, $"Removing transient company at index {i}"); } Assert.That(FindAllOccurrences(sqlLog.GetWholeLog(), "INSERT \n INTO"), Is.EqualTo(10), "Statements count after removing"); @@ -909,7 +909,7 @@ public async Task ListFlushAsync(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), $"Comparing company ListIndex at index {i}"); } if (initialize) @@ -1049,7 +1049,7 @@ public async Task ListClearAsync(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Credit cards count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, "Checking existence for item at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence for item at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Credit cards initialization status after loading again"); @@ -1140,7 +1140,7 @@ public async Task ListIndexOperationsAsync(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company index at {0}", i); + Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company index at {i}"); } if (initialize) @@ -1882,8 +1882,7 @@ public async Task SetClearAsync(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Permissions count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, - "Checking existence of added element at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence of added element at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Permissions initialization status after loading again"); diff --git a/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs b/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs index dbd820ee55f..b6a3f3c2bea 100644 --- a/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs +++ b/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs @@ -884,7 +884,7 @@ public async Task SimpleDeleteOnAnimalAsync() { if (Dialect.HasSelfReferentialForeignKeyBug) { - Assert.Ignore("self referential FK bug", "HQL delete testing"); + Assert.Ignore("self referential FK bug - HQL delete testing"); return; } diff --git a/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs b/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs index af898bcf8e6..62636575ef6 100644 --- a/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs +++ b/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs @@ -43,7 +43,7 @@ public async Task ReturnedValueIsGuidAsync() } catch (NotSupportedException) { - Assert.Ignore("This test does not apply to {0}", Dialect.Dialect.GetDialect()); + Assert.Ignore($"This test does not apply to {Dialect.Dialect.GetDialect()}"); } var gen = new NativeGuidGenerator(); diff --git a/src/NHibernate.Test/Async/Linq/FunctionTests.cs b/src/NHibernate.Test/Async/Linq/FunctionTests.cs index c39ff901df4..2a46df8e1e1 100644 --- a/src/NHibernate.Test/Async/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Async/Linq/FunctionTests.cs @@ -204,7 +204,7 @@ where lowerName.IndexOf('a') == 0 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -220,7 +220,7 @@ where lowerName.IndexOf('a', 2) == -1 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -236,7 +236,7 @@ where lowerName.IndexOf("an") == 0 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -252,7 +252,7 @@ where lowerName.Contains("a") select lowerName.IndexOf("a", 1); var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs index 20691ec53ea..aa36b45ef3d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs @@ -85,7 +85,7 @@ public async Task MultiQuerySingleInListAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (var tx = s.BeginTransaction()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index a98b448d4a9..4687e62be28 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -244,7 +244,7 @@ public async Task LoadEntityCollectionWithCustomLoaderAsync() [Test] public async Task NativeUpdateQueryWithoutResultsAsync() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -259,7 +259,7 @@ public async Task NativeUpdateQueryWithoutResultsAsync() [Test] public async Task NativeScalarQueryWithoutResultsAsync() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -278,7 +278,7 @@ public async Task NativeScalarQueryWithUndefinedResultsetAsync() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { @@ -301,7 +301,7 @@ public async Task NativeScalarQueryWithDefinedResultsetAsync() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index 2d379ed23f5..8a1297d09e9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -102,7 +102,7 @@ public async Task MultiCriteriaQueriesWithIntsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying IntData using (ISession session = this.OpenSession()) @@ -131,7 +131,7 @@ public async Task MultiCriteriaQueriesWithStringsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying StringData using (ISession session = this.OpenSession()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs index ad960e60d4c..2cb7e05afdb 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs @@ -124,7 +124,7 @@ public async Task ConnectionPoolCorruptionAfterDeadlockAsync(bool distributed, b // // ? This shouldn't happen // - Assert.Fail("Surprising exception when trying to force a deadlock: {0}", x); + Assert.Fail($"Surprising exception when trying to force a deadlock: {x}"); } _log.WarnFormat("Initial session seemingly not deadlocked at attempt {0}", tryCount); @@ -254,11 +254,11 @@ public async Task ConnectionPoolCorruptionAfterDeadlockAsync(bool distributed, b } } - Assert.Fail("{0}; {1} subsequent requests failed.", - missingDeadlock - ? "Deadlock not reported on initial request, and initial request failed" - : "Initial request failed", - subsequentFailedRequests); + Assert.Fail( + missingDeadlock + ? $"Deadlock not reported on initial request, and initial request failed; {subsequentFailedRequests} subsequent requests failed." + : $"Initial request failed; {subsequentFailedRequests} subsequent requests failed."); + } while (tryCount < 3); // // I'll change this to while(true) sometimes so I don't have to keep running the test diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs index c074a9df506..c782d087a29 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs @@ -106,4 +106,4 @@ public static MethodInfo GetMethodDefinition2(Func func, return method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs index df98794f251..f4c4d9cc279 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs @@ -48,7 +48,7 @@ public async Task BugAsync() } catch (Exception e) { - Assert.Fail("Should have thrown MyException, thrown {0} instead", e); + Assert.Fail($"Should have thrown MyException, thrown {e} instead"); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index 4e4c3d5c4bc..4268b4948ea 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -54,7 +54,7 @@ public void MultiHqlShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) @@ -96,7 +96,7 @@ public void MultiCriteriaShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) diff --git a/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs b/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs index 7973f10aa17..772522d5131 100644 --- a/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs +++ b/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs @@ -528,10 +528,11 @@ public async Task CanUseSessionOutsideOfScopeAfterScopeAsync(bool explicitFlush) } var count = 0; Assert.DoesNotThrowAsync(async () => count = await (s.Query().CountAsync()), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } diff --git a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs index a87793c3d9b..a234b0e178f 100644 --- a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs @@ -296,10 +296,11 @@ public async Task CanUseSessionOutsideOfScopeAfterScopeAsync(bool explicitFlush) } var count = 0; Assert.DoesNotThrowAsync(async () => count = await (s.Query().CountAsync()), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } @@ -644,10 +645,9 @@ public async Task SupportsTransactionTimeoutAsync() Assert.That( _unhandledExceptions.Count, Is.EqualTo(0), - "Unhandled exceptions have occurred: {0}", - string.Join(@" + $"Unhandled exceptions have occurred: {string.Join(@" -", _unhandledExceptions)); +", _unhandledExceptions)}"); // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly // more than 10% of the attempts. diff --git a/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs b/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs index 3e719891bfe..3de1d4f3ea4 100644 --- a/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs +++ b/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs @@ -64,7 +64,7 @@ protected override void CreateSchema() { // Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider // viewer. - Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); Console.WriteLine("Creating the schema failed, assuming it already exists."); Console.WriteLine(ex); } @@ -113,7 +113,7 @@ public async Task ShouldVerifyAsync() } catch (SchemaValidationException sve) { - Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve); + Assert.Fail($"Validation failed: {StringHelper.CollectionToString(sve.ValidationErrors)}.\n{sve}"); } } } diff --git a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs index 18e4fcec7da..f39f344ce62 100644 --- a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs @@ -58,9 +58,7 @@ private void AssertCurrentSession(ISession session, string message) Assert.That( Sfi.GetCurrentSession(), Is.EqualTo(session), - "{0} {1} instead of {2}.", message, - Sfi.GetCurrentSession().GetSessionImplementation().SessionId, - session.GetSessionImplementation().SessionId); + $"{message} {Sfi.GetCurrentSession().GetSessionImplementation().SessionId} instead of {session.GetSessionImplementation().SessionId}."); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs index 5967e9bf626..c2cad0ea0ef 100644 --- a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs @@ -79,9 +79,7 @@ private void AssertCurrentSession(ISessionFactory factory, ISession session, str Assert.That( factory.GetCurrentSession(), Is.EqualTo(session), - "{0} {1} instead of {2}.", message, - factory.GetCurrentSession().GetSessionImplementation().SessionId, - session.GetSessionImplementation().SessionId); + $"{message} {factory.GetCurrentSession().GetSessionImplementation().SessionId} instead of {session.GetSessionImplementation().SessionId}."); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs index dd23c4b91b4..17f5ae5a169 100644 --- a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs @@ -346,7 +346,7 @@ public void MultiCriteria() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); SetupPagingData(); diff --git a/src/NHibernate.Test/Criteria/ProjectionsTest.cs b/src/NHibernate.Test/Criteria/ProjectionsTest.cs index 0eb03b33a60..1e79dfd92ff 100644 --- a/src/NHibernate.Test/Criteria/ProjectionsTest.cs +++ b/src/NHibernate.Test/Criteria/ProjectionsTest.cs @@ -80,7 +80,7 @@ public void UsingSqlFunctions_Concat_WithCast() { if(Dialect is Oracle8iDialect) { - Assert.Ignore("Not supported by the active dialect:{0}.", Dialect); + Assert.Ignore($"Not supported by the active dialect:{Dialect}."); } if (TestDialect.HasBrokenTypeInferenceOnSelectedParameters) Assert.Ignore("Current dialect does not support this test"); diff --git a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs index bcd00d7c9e5..652207aa15b 100644 --- a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs @@ -694,7 +694,7 @@ public void FetchModeEagerForEager() private void SkipFutureTestIfNotSupported() { if (Sfi.ConnectionProvider.Driver.SupportsMultipleQueries == false) - Assert.Ignore("Driver {0} does not support multi-queries", Sfi.ConnectionProvider.Driver.GetType().FullName); + Assert.Ignore($"Driver {Sfi.ConnectionProvider.Driver.GetType().FullName} does not support multi-queries"); } #region Test Setup diff --git a/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs index 3e5b162a61a..eaa2016adf7 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs @@ -357,13 +357,13 @@ private static void VerifyLimitStringForStoredProcedureCalls(string sql) { var d = new MsSql2005Dialect(); var limitSql = d.GetLimitString(new SqlString(sql), null, new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), null); - Assert.That(limitSql, Is.Null, "Offset only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Offset only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit and Offset: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit and Offset: {sql}"); } [Test] diff --git a/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs index 04ebc9c638b..2f7ae070123 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs @@ -167,13 +167,13 @@ private static void VerifyLimitStringForStoredProcedureCalls(string sql) { var d = new MsSql2012Dialect(); var limitSql = d.GetLimitString(new SqlString(sql), null, new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), null); - Assert.That(limitSql, Is.Null, "Offset only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Offset only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit and Offset: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit and Offset: {sql}"); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs b/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs index 93034e9dc3d..e673a18adec 100644 --- a/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs +++ b/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs @@ -121,7 +121,7 @@ private static OracleDataClientDriverBase GetDriver(bool managed, IDictionary(), message, args); + Assert.That(clazz, Has.Attribute(), message); } public static void InheritedAreMarkedSerializable(System.Type clazz) @@ -54,15 +54,15 @@ public static void InheritedAreMarkedSerializable(System.Type clazz, string mess public static void IsSerializable(object obj) { - IsSerializable(obj, null, null); + IsSerializable(obj, null); } - public static void IsSerializable(object obj, string message, params object[] args) + public static void IsSerializable(object obj, string message) { #if NETFX - Assert.That(obj, Is.BinarySerializable, message, args); + Assert.That(obj, Is.BinarySerializable, message); #else - if (obj == null) throw new ArgumentNullException(nameof(args)); + if (obj == null) throw new ArgumentNullException(nameof(obj)); var formatter = new BinaryFormatter { SurrogateSelector = new SerializationHelper.SurrogateSelector() @@ -83,19 +83,19 @@ public static void IsSerializable(object obj, string message, params object[] ar } } - Assert.That(isSuccess, message, args); + Assert.That(isSuccess, message); #endif } public static void IsXmlSerializable(object obj) { - IsXmlSerializable(obj, null, null); + IsXmlSerializable(obj, null); } - public static void IsXmlSerializable(object obj, string message, params object[] args) + public static void IsXmlSerializable(object obj, string message) { #if NETFX - Assert.That(obj, Is.XmlSerializable, message, args); + Assert.That(obj, Is.XmlSerializable, message); #else if (obj == null) throw new ArgumentNullException(nameof(obj)); var isSuccess = false; @@ -116,7 +116,7 @@ public static void IsXmlSerializable(object obj, string message, params object[] } } - Assert.That(isSuccess, message, args); + Assert.That(isSuccess, message); #endif } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs index 04479bee70f..670feb9c0c3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs @@ -74,7 +74,7 @@ public void MultiQuerySingleInList() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (var tx = s.BeginTransaction()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index c2171e57609..fd7fa20ce5f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -232,7 +232,7 @@ private void Save(TArea area) where TArea : Area [Test] public void NativeUpdateQueryWithoutResults() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -247,7 +247,7 @@ public void NativeUpdateQueryWithoutResults() [Test] public void NativeScalarQueryWithoutResults() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -266,7 +266,7 @@ public void NativeScalarQueryWithUndefinedResultset() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { @@ -289,7 +289,7 @@ public void NativeScalarQueryWithDefinedResultset() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index b8441edf39a..235afc084b3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -91,7 +91,7 @@ public void MultiCriteriaQueriesWithIntsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying IntData using (ISession session = this.OpenSession()) @@ -120,7 +120,7 @@ public void MultiCriteriaQueriesWithStringsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying StringData using (ISession session = this.OpenSession()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs index 0c6e98895a4..47e0171160f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs @@ -113,7 +113,7 @@ public void ConnectionPoolCorruptionAfterDeadlock(bool distributed, bool dispose // // ? This shouldn't happen // - Assert.Fail("Surprising exception when trying to force a deadlock: {0}", x); + Assert.Fail($"Surprising exception when trying to force a deadlock: {x}"); } _log.WarnFormat("Initial session seemingly not deadlocked at attempt {0}", tryCount); @@ -243,11 +243,11 @@ public void ConnectionPoolCorruptionAfterDeadlock(bool distributed, bool dispose } } - Assert.Fail("{0}; {1} subsequent requests failed.", - missingDeadlock - ? "Deadlock not reported on initial request, and initial request failed" - : "Initial request failed", - subsequentFailedRequests); + Assert.Fail( + missingDeadlock + ? $"Deadlock not reported on initial request, and initial request failed; {subsequentFailedRequests} subsequent requests failed." + : $"Initial request failed; {subsequentFailedRequests} subsequent requests failed."); + } while (tryCount < 3); // // I'll change this to while(true) sometimes so I don't have to keep running the test diff --git a/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs index 1996d943be9..41562a8e13a 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs @@ -1430,12 +1430,12 @@ public void OverloadReflectionBluntPerfCompare() } swEnHlp.Stop(); - Assert.Pass(@"Blunt perf timings: -Direct reflection: {0} -Current impl, same overload: {1} -Current impl, other overload: {2} -EnumerableHelper.GetMethod(non generic overload): {3}", - swNoSameParamsCheck.Elapsed, swCurrentChoiceSameType.Elapsed, swCurrentChoice.Elapsed, swEnHlp.Elapsed); + Assert.Pass( + $@"Blunt perf timings: +Direct reflection: {swNoSameParamsCheck.Elapsed} +Current impl, same overload: {swCurrentChoiceSameType.Elapsed} +Current impl, other overload: {swCurrentChoice.Elapsed} +EnumerableHelper.GetMethod(non generic overload): {swEnHlp.Elapsed}"); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs index 200e338cd15..0eca4c718e1 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs @@ -160,16 +160,14 @@ public void ReflectionBluntPerfCompare() } swEnHlp.Stop(); - Assert.Pass(@"Blunt perf timings: -Cached method: {0} -Cached method definition + make gen: {1} -Hazzik GetMethod: {5} -Hazzik GetMethodDefinition + make gen: {6} -ReflectHelper.GetMethod: {2} -ReflectHelper.GetMethodDefinition + make gen: {3} -EnumerableHelper.GetMethod(generic overload): {4}", - swCached.Elapsed, swCachedDef.Elapsed, swRefl.Elapsed, swReflDef.Elapsed, swEnHlp.Elapsed, - swRefl2.Elapsed, swRefl2Def.Elapsed); + Assert.Pass($@"Blunt perf timings: +Cached method: {swCached.Elapsed} +Cached method definition + make gen: {swCachedDef.Elapsed} +Hazzik GetMethod: {swRefl2.Elapsed} +Hazzik GetMethodDefinition + make gen: {swRefl2Def.Elapsed} +ReflectHelper.GetMethod: {swRefl.Elapsed} +ReflectHelper.GetMethodDefinition + make gen: {swReflDef.Elapsed} +EnumerableHelper.GetMethod(generic overload): {swEnHlp.Elapsed}"); } public static MethodInfo GetMethod2(Func func, T arg1) @@ -183,4 +181,4 @@ public static MethodInfo GetMethodDefinition2(Func func, return method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs index 28c088902b6..657c0bb738e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs @@ -37,7 +37,7 @@ public void Bug() } catch (Exception e) { - Assert.Fail("Should have thrown MyException, thrown {0} instead", e); + Assert.Fail($"Should have thrown MyException, thrown {e} instead"); } } diff --git a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index 7c170ebf0c6..d22b0d8fbf5 100644 --- a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -43,7 +43,7 @@ public void MultiHqlShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) @@ -85,7 +85,7 @@ public void MultiCriteriaShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) diff --git a/src/NHibernate.Test/ProxyTest/PeVerifier.cs b/src/NHibernate.Test/ProxyTest/PeVerifier.cs index f5f4d027221..08db481d283 100644 --- a/src/NHibernate.Test/ProxyTest/PeVerifier.cs +++ b/src/NHibernate.Test/ProxyTest/PeVerifier.cs @@ -62,7 +62,11 @@ public void AssertIsValid() var result = process.ExitCode + " code "; if (process.ExitCode != 0) - Assert.Fail("PeVerify reported error(s): " + Environment.NewLine + processOutput, result); + Assert.Fail( + $@"PeVerify reported error(s): +{processOutput} + +{result}"); } } } diff --git a/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs index 3cb38216fad..54332e78098 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs @@ -115,15 +115,14 @@ private static void VerifyTokenizer(string sql, params ExpectedToken[] expectedT { if (tokenIndex >= expectedTokens.Length) { - Assert.Fail("Tokenizer returns more than expected '{0}' tokens. \nSQL: {1}\nLast Token: {2}({3})", - expectedTokens.Length, sql, token.TokenType, token.Value); + Assert.Fail($"Tokenizer returns more than expected '{expectedTokens.Length}' tokens. \nSQL: {sql}\nLast Token: {token.TokenType}({token.Value})"); } var expectedToken = expectedTokens[tokenIndex]; - Assert.That(token.TokenType, Is.EqualTo(expectedToken.TokenType), "[Token #{0} in '{1}']TokenType", tokenIndex, sql); - Assert.That(token.Value, Is.EqualTo(expectedToken.Value), "[Token #{0} in {1}]Value", tokenIndex, sql); - Assert.That(token.SqlIndex, Is.EqualTo(sqlIndex), "[Token #{0} in {1}]SqlIndex", tokenIndex, sql); - Assert.That(token.Length, Is.EqualTo(expectedToken.Length), "[Token #{0} in {1}]Length", tokenIndex, sql); + Assert.That(token.TokenType, Is.EqualTo(expectedToken.TokenType), $"[Token #{tokenIndex} in '{sql}']TokenType"); + Assert.That(token.Value, Is.EqualTo(expectedToken.Value), $"[Token #{tokenIndex} in {sql}]Value"); + Assert.That(token.SqlIndex, Is.EqualTo(sqlIndex), $"[Token #{tokenIndex} in {sql}]SqlIndex"); + Assert.That(token.Length, Is.EqualTo(expectedToken.Length), $"[Token #{tokenIndex} in {sql}]Length"); tokenIndex++; sqlIndex += expectedToken.Length; @@ -131,7 +130,7 @@ private static void VerifyTokenizer(string sql, params ExpectedToken[] expectedT if (tokenIndex < expectedTokens.Length) { - Assert.Fail("Tokenizer returns less than expected '{0}' tokens.\nSQL: {1}", expectedTokens.Length, sql); + Assert.Fail($"Tokenizer returns less than expected '{expectedTokens.Length}' tokens.\nSQL: {sql}"); } } diff --git a/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs index b7d931e0809..c16175432c9 100644 --- a/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs @@ -362,7 +362,7 @@ public void MultiThreadedTransaction() var errors = mtr.GetErrors(); if (errors.Length > 0) { - Assert.Fail("One or more thread failed, found {0} errors. First exception: {1}", errors.Length, errors[0]); + Assert.Fail($"One or more thread failed, found {errors.Length} errors. First exception: {errors[0]}"); } } @@ -539,10 +539,11 @@ public void CanUseSessionOutsideOfScopeAfterScope(bool explicitFlush) } var count = 0; Assert.DoesNotThrow(() => count = s.Query().Count(), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } diff --git a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs index 8503de97948..1a42ae71e19 100644 --- a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs @@ -284,10 +284,11 @@ public void CanUseSessionOutsideOfScopeAfterScope(bool explicitFlush) } var count = 0; Assert.DoesNotThrow(() => count = s.Query().Count(), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } @@ -762,10 +763,9 @@ public void SupportsTransactionTimeout() Assert.That( _unhandledExceptions.Count, Is.EqualTo(0), - "Unhandled exceptions have occurred: {0}", - string.Join(@" + $"Unhandled exceptions have occurred: {string.Join(@" -", _unhandledExceptions)); +", _unhandledExceptions)}"); // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly // more than 10% of the attempts. diff --git a/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs b/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs index 87afcd89625..29a30b11bf5 100644 --- a/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs +++ b/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs @@ -53,7 +53,7 @@ protected override void CreateSchema() { // Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider // viewer. - Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); Console.WriteLine("Creating the schema failed, assuming it already exists."); Console.WriteLine(ex); } @@ -102,7 +102,7 @@ public void ShouldVerify() } catch (SchemaValidationException sve) { - Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve); + Assert.Fail($"Validation failed: {StringHelper.CollectionToString(sve.ValidationErrors)}.\n{sve}"); } } } diff --git a/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs b/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs index 6c6e6d72cf0..f1bca0035a6 100644 --- a/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs +++ b/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs @@ -33,7 +33,7 @@ public void EachEmbeddedBasicTypeIsSerializable() foreach (var fieldInfo in builtInCustomTypes) { var ntp = (IType) fieldInfo.GetValue(null); - NHAssert.IsSerializable(ntp, fieldInfo.Name + " is not serializable"); + NHAssert.IsSerializable(ntp, $"{fieldInfo.Name} is not serializable"); } if (typeof(System.Type).IsSerializable) diff --git a/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs b/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs index 3efb4bbf5b5..a11d304c69a 100644 --- a/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs +++ b/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs @@ -87,7 +87,7 @@ public void MultiThreadAccess() var errors = mtr.GetErrors(); if (errors.Length > 0) { - Assert.Fail("One or more thread failed, found {0} errors. First exception: {1}", errors.Length, errors[0]); + Assert.Fail($"One or more thread failed, found {errors.Length} errors. First exception: {errors[0]}"); } } From 07c05021be261a377bb81f6c3dccbd1f7dae9312 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Fri, 12 Apr 2024 12:20:52 +0200 Subject: [PATCH 085/128] Fix setting ScaleDefined in SqlType (#3524) --- src/NHibernate/SqlTypes/SqlType.cs | 62 +++++++++--------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/src/NHibernate/SqlTypes/SqlType.cs b/src/NHibernate/SqlTypes/SqlType.cs index 29523e9122e..0aca2e81921 100644 --- a/src/NHibernate/SqlTypes/SqlType.cs +++ b/src/NHibernate/SqlTypes/SqlType.cs @@ -23,71 +23,45 @@ namespace NHibernate.SqlTypes [Serializable] public class SqlType : IEquatable { - private readonly DbType dbType; - private readonly int length; - private readonly byte precision; - private readonly byte scale; - private readonly bool lengthDefined; - private readonly bool precisionDefined; + private readonly int? _length; + private readonly byte? _precision; + private readonly byte? _scale; public SqlType(DbType dbType) { - this.dbType = dbType; + DbType = dbType; } public SqlType(DbType dbType, int length) { - this.dbType = dbType; - this.length = length; - lengthDefined = true; + DbType = dbType; + _length = length; } public SqlType(DbType dbType, byte precision, byte scale) { - this.dbType = dbType; - this.precision = precision; - this.scale = scale; - precisionDefined = true; + DbType = dbType; + _precision = precision; + _scale = scale; } public SqlType(DbType dbType, byte scale) { - this.dbType = dbType; - this.scale = scale; - ScaleDefined = true; + DbType = dbType; + _scale = scale; } - public DbType DbType - { - get { return dbType; } - } - - public int Length - { - get { return length; } - } - - public byte Precision - { - get { return precision; } - } + public DbType DbType { get; } - public byte Scale - { - get { return scale; } - } + public int Length => _length.GetValueOrDefault(); + public byte Precision => _precision.GetValueOrDefault(); + public byte Scale => _scale.GetValueOrDefault(); + public bool LengthDefined => _length.HasValue; - public bool LengthDefined - { - get { return lengthDefined; } - } + public bool PrecisionDefined => _precision.HasValue; - public bool PrecisionDefined - { - get { return precisionDefined; } - } - public bool ScaleDefined { get; } + public bool ScaleDefined => _scale.HasValue; #region System.Object Members From ae03161e49479da21eb63de429a5f624cfe01694 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 29 Apr 2024 02:24:06 +1000 Subject: [PATCH 086/128] Remove mentions of Prevalence cache from documentation (#3532) --- doc/reference/modules/nhibernate_caches.xml | 27 +-------------------- doc/reference/modules/performance.xml | 13 ---------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/doc/reference/modules/nhibernate_caches.xml b/doc/reference/modules/nhibernate_caches.xml index 3b3c1f5c0b7..74877aec459 100644 --- a/doc/reference/modules/nhibernate_caches.xml +++ b/doc/reference/modules/nhibernate_caches.xml @@ -43,17 +43,6 @@ Several cache providers have been contributed by NHibernate users: - - NHibernate.Caches.Prevalence - - - Uses Bamboo.Prevalence as the cache provider. Open the - file Bamboo.Prevalence.license.txt for more information about its license; - you can also visit its website. This - provider is available for the .Net Framework only. Also see . - - - NHibernate.Caches.SysCache @@ -158,8 +147,7 @@ Choose the cache provider you want to use and copy its assembly in your assemblies directory. - (For example, NHibernate.Caches.Prevalence.dll or - NHibernate.Caches.SysCache.dll.) + (For example, NHibernate.Caches.SysCache.dll.) @@ -279,19 +267,6 @@ -
- Prevalence Cache Configuration - - There is only one configurable parameter: prevalenceBase. This is the directory on the - file system where the Prevalence engine will save data. It can be relative to the current directory or a - full path. If the directory doesn't exist, it will be created. - - - The prevalenceBase setting can only be set programmatically through the NHibernate - configuration object, by example with Configuration.SetProperty. - -
-
SysCache Configuration diff --git a/doc/reference/modules/performance.xml b/doc/reference/modules/performance.xml index f44a5f6a9f8..2ac0cc800ba 100644 --- a/doc/reference/modules/performance.xml +++ b/doc/reference/modules/performance.xml @@ -709,13 +709,6 @@ using(var iter = session yes - - Prevalence Cache - NHibernate.Caches.Prevalence.PrevalenceCacheProvider, NHibernate.Caches.Prevalence - memory, disk - - yes - @@ -877,12 +870,6 @@ using(var iter = session yes yes - - PrevalenceCache - yes - yes - yes - From c7e558bdb37002f766519c2ab78316fa951f6981 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 29 Apr 2024 09:01:12 +1000 Subject: [PATCH 087/128] Update Iesi.Collections to 4.1.1 (#3533) --- src/NHibernate/NHibernate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 3fb89402adf..d370a6fae08 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -37,7 +37,7 @@ All - + From 25be55c1435cc1a35ec31e449636da78e24b8d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 30 Apr 2024 07:37:35 +0200 Subject: [PATCH 088/128] Fix wrong log message in LoadContexts (#3535) --- src/NHibernate/Engine/Loading/LoadContexts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Engine/Loading/LoadContexts.cs b/src/NHibernate/Engine/Loading/LoadContexts.cs index dd13812980a..fde1f7c7c7c 100644 --- a/src/NHibernate/Engine/Loading/LoadContexts.cs +++ b/src/NHibernate/Engine/Loading/LoadContexts.cs @@ -239,7 +239,7 @@ internal LoadingCollectionEntry LocateLoadingCollectionEntry(CollectionKey key) xrefLoadingCollectionEntries.TryGetValue(key, out rtn); if (log.IsDebugEnabled()) { - log.Debug("collection [{0}] {1} in load context", key, (rtn == null ? "located" : "not located")); + log.Debug("collection [{0}] {1} in load context", key, (rtn == null ? "not located" : "located")); } return rtn; } From 13dd50971112ec42cbc6d961d502cf611bb593ba Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sun, 5 May 2024 11:48:40 +1000 Subject: [PATCH 089/128] Treat all non-virtual methods of System.Object as not proxiable (#3538) --- build-common/NHibernate.props | 4 +- .../NHSpecificTest/ProxyValidator/Fixture.cs | 82 +++++----- .../ProxyValidator/ShouldBeProxiableTests.cs | 140 +++++++++++------- ...aultDynamicProxyMethodCheckerExtensions.cs | 8 +- src/NHibernate/Proxy/DynProxyTypeValidator.cs | 17 +-- 5 files changed, 147 insertions(+), 104 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index d56d15ccbc4..3564b80a784 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,9 +3,9 @@ 5.5 - 1 + 2 - + dev 9.0 $(NhVersion).$(VersionPatch) diff --git a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs index 2a16a4578a1..c110eb370ba 100644 --- a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs @@ -1,7 +1,6 @@ using System; using NHibernate.Proxy; using NUnit.Framework; -using System.Collections.Generic; namespace NHibernate.Test.NHSpecificTest.ProxyValidator { @@ -10,15 +9,6 @@ public class Fixture { private readonly IProxyValidator pv = new DynProxyTypeValidator(); - private void Validate(System.Type type) - { - ICollection errors = pv.ValidateType(type); - if (errors != null) - { - throw new InvalidProxyTypeException(errors); - } - } - public class ValidClass { private int privateField; @@ -64,12 +54,35 @@ protected int NonVirtualPrivateProperty #pragma warning restore 67 } + [Test] + public void ObjectIsValid() + { + var errors = pv.ValidateType(typeof(object)); + Assert.That(errors, Is.Null); + } + [Test] public void ValidClassTest() { - Validate(typeof(ValidClass)); + var errors = pv.ValidateType(typeof(ValidClass)); + Assert.That(errors, Is.Null); } + public class InvalidSealedToString : ValidClass + { + public sealed override string ToString() + { + return base.ToString(); + } + } + + [Test] + public void SealedObjectOverride() + { + var errors = pv.ValidateType(typeof(InvalidSealedToString)); + Assert.That(errors, Has.Count.EqualTo(1)); + } + public class InvalidPrivateConstructor : ValidClass { private InvalidPrivateConstructor() @@ -80,7 +93,8 @@ private InvalidPrivateConstructor() [Test] public void PrivateConstructor() { - Assert.Throws(() => Validate(typeof(InvalidPrivateConstructor))); + var errors = pv.ValidateType(typeof(InvalidPrivateConstructor)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidNonVirtualProperty : ValidClass @@ -95,7 +109,8 @@ public int NonVirtualProperty [Test] public void NonVirtualProperty() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } public class InvalidPublicField : ValidClass @@ -106,7 +121,8 @@ public class InvalidPublicField : ValidClass [Test] public void PublicField() { - Assert.Throws(() => Validate(typeof(InvalidPublicField))); + var errors = pv.ValidateType(typeof(InvalidPublicField)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidNonVirtualEvent : ValidClass @@ -119,7 +135,8 @@ public class InvalidNonVirtualEvent : ValidClass [Test] public void NonVirtualEvent() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualEvent))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualEvent)); + Assert.That(errors, Has.Count.EqualTo(2)); } public interface ValidInterface @@ -129,7 +146,8 @@ public interface ValidInterface [Test] public void Interface() { - Validate(typeof(ValidInterface)); + var errors = pv.ValidateType(typeof(ValidInterface)); + Assert.That(errors, Is.Null); } public class MultipleErrors @@ -153,15 +171,8 @@ public int NonVirtualProperty [Test] public void MultipleErrorsReported() { - try - { - Validate(typeof(MultipleErrors)); - Assert.Fail("Should have failed validation"); - } - catch (InvalidProxyTypeException e) - { - Assert.IsTrue(e.Errors.Count > 1); - } + var errors = pv.ValidateType(typeof(MultipleErrors)); + Assert.That(errors, Has.Count.GreaterThan(1)); } public class InvalidNonVirtualInternalProperty : ValidClass @@ -183,16 +194,18 @@ public class InvalidInternalField : ValidClass [Test] public void NonVirtualInternal() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualInternalProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualInternalProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } [Test] public void InternalField() { - Assert.Throws(() => Validate(typeof(InvalidInternalField))); + var errors = pv.ValidateType(typeof(InvalidInternalField)); + Assert.That(errors, Has.Count.EqualTo(1)); } - public class InvalidNonVirtualProtectedProperty : ValidClass + public class ValidNonVirtualProtectedProperty : ValidClass { protected int NonVirtualProperty { @@ -204,8 +217,8 @@ protected int NonVirtualProperty [Test] public void NonVirtualProtected() { - Validate(typeof(InvalidNonVirtualProtectedProperty)); - Assert.IsTrue(true, "Always should pass, protected members do not need to be virtual."); + var errors = pv.ValidateType(typeof(ValidNonVirtualProtectedProperty)); + Assert.That(errors, Is.Null); } public class InvalidNonVirtualProtectedInternalProperty : ValidClass @@ -220,7 +233,8 @@ protected internal int NonVirtualProperty [Test] public void NonVirtualProtectedInternal() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualProtectedInternalProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualProtectedInternalProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } interface INonVirtualPublicImplementsInterface @@ -239,7 +253,8 @@ public int NonVirtualMethodImplementsInterface [Test] public void VirtualPublicImplementsInterface() { - Assert.Throws(() => Validate(typeof(NonVirtualPublicImplementsInterface))); + var errors = pv.ValidateType(typeof(NonVirtualPublicImplementsInterface)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidVirtualPrivateAutoProperty : ValidClass @@ -254,7 +269,8 @@ public virtual int NonVirtualSetterProperty [Test] public void PrivateSetterOnVirtualPropertyShouldThrows() { - Assert.Throws(() => Validate(typeof(InvalidVirtualPrivateAutoProperty))); + var errors = pv.ValidateType(typeof(InvalidVirtualPrivateAutoProperty)); + Assert.That(errors, Has.Count.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs index 204a0c0997f..bb29e990bb2 100644 --- a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs @@ -46,80 +46,115 @@ protected internal void AProtectedInternal() { } } [Test] - public void GetTypeNotBeProxiable() + public void ObjectToStringShouldBeProxiable() { - var method = typeof(object).GetMethod("GetType"); - Assert.That(method.ShouldBeProxiable(), Is.False); + var method = typeof(object).GetMethod(nameof(ToString)); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] - public void DisposeNotBeProxiable() + public void ObjectGetHashCodeShouldBeProxiable() { - var method = typeof(MyClass).GetMethod("Dispose"); - Assert.That(method.ShouldBeProxiable(), Is.False); + var method = typeof(object).GetMethod(nameof(GetHashCode)); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] - public void ObjectDestructorShouldNotBeProxiable() + public void ObjectEqualsShouldBeProxiable() { - var method = typeof(object).GetMethod( - "Finalize", - BindingFlags.NonPublic | BindingFlags.Instance); - - Assert.That(method.ShouldBeProxiable(), Is.False); + var method = typeof(object).GetMethod(nameof(Equals), BindingFlags.Public | BindingFlags.Instance); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] - public void ObjectDestructorIsNotProxiable() + public void ObjectMemberwiseCloneShouldNotBeProxiable() { var method = typeof(object).GetMethod( - "Finalize", - BindingFlags.NonPublic | BindingFlags.Instance); + nameof(MemberwiseClone), + BindingFlags.Instance | BindingFlags.NonPublic); - Assert.That(method.IsProxiable(), Is.False); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); } - + [Test] - public void MyClassDestructorShouldNotBeProxiable() + public void ObjectGetTypeShouldNotBeProxiable() { - var method = typeof(MyClass).GetMethod( - "Finalize", - BindingFlags.NonPublic | BindingFlags.Instance, - null, - System.Type.EmptyTypes, - null); + var method = typeof(object).GetMethod("GetType"); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); + } - Assert.That(method.ShouldBeProxiable(), Is.False); + [Test] + public void MyClassDisposeNotBeProxiable() + { + var method = typeof(MyClass).GetMethod("Dispose"); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); } [Test] - public void MyClassDestructorIsNotProxiable() + public void ObjectDestructorShouldNotBeProxiable() { - var method = typeof(MyClass).GetMethod( + var method = typeof(object).GetMethod( "Finalize", - BindingFlags.NonPublic | BindingFlags.Instance, - null, - System.Type.EmptyTypes, - null); + BindingFlags.NonPublic | BindingFlags.Instance); - Assert.That(method.IsProxiable(), Is.False); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); } [Test] - public void MyClassLowerCaseFinalizeShouldBeProxiable() + public void MyClassDestructorShouldNotBeProxiable() { var method = typeof(MyClass).GetMethod( - "finalize", - BindingFlags.Public | BindingFlags.Instance, + "Finalize", + BindingFlags.NonPublic | BindingFlags.Instance, null, System.Type.EmptyTypes, null); - Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); } [Test] - public void MyClassLowerCaseFinalizeIsProxiable() + public void MyClassLowerCaseFinalizeShouldBeProxiable() { var method = typeof(MyClass).GetMethod( "finalize", @@ -128,24 +163,16 @@ public void MyClassLowerCaseFinalizeIsProxiable() System.Type.EmptyTypes, null); - Assert.That(method.IsProxiable(), Is.True); - } - - [Test] - public void MyClassFinalizeWithParametersShouldBeProxiable() - { - var method = typeof(MyClass).GetMethod( - "Finalize", - BindingFlags.Public | BindingFlags.Instance, - null, - new[] { typeof(int) }, - null); - - Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] - public void MyClassFinalizeWithParametersIsProxiable() + public void MyClassFinalizeWithParametersShouldBeProxiable() { var method = typeof(MyClass).GetMethod( "Finalize", @@ -154,14 +181,19 @@ public void MyClassFinalizeWithParametersIsProxiable() new[] { typeof(int) }, null); - Assert.That(method.IsProxiable(), Is.True); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] public void WhenProtectedNoVirtualPropertyThenShouldntBeProxiable() { var prop = typeof(ProtectedNoVirtualProperty).GetProperty("Aprop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - Assert.That(prop.ShouldBeProxiable(), Is.False); + Assert.That(prop.ShouldBeProxiable(), Is.False); } [Test] diff --git a/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs b/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs index b25c01c9fea..f57cf3fe287 100644 --- a/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs +++ b/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs @@ -23,12 +23,10 @@ public static bool IsProxiable(this MethodInfo method) public static bool ShouldBeProxiable(this MethodInfo method) { // to use only for real methods (no getter/setter) - return (method.DeclaringType != typeof (MarshalByRefObject)) && - !IsFinalizeMethod(method) && - (!(method.DeclaringType == typeof (object) && "GetType".Equals(method.Name))) && - (!(method.DeclaringType == typeof (object) && "obj_address".Equals(method.Name))) && // Mono-specific method + return method.DeclaringType != typeof(MarshalByRefObject) && + !(method.DeclaringType == typeof(object) && !method.IsVirtual) && !IsDisposeMethod(method) && - (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly); + (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly); } public static bool ShouldBeProxiable(this PropertyInfo propertyInfo) diff --git a/src/NHibernate/Proxy/DynProxyTypeValidator.cs b/src/NHibernate/Proxy/DynProxyTypeValidator.cs index 2f0370c3628..b53df86c5b6 100644 --- a/src/NHibernate/Proxy/DynProxyTypeValidator.cs +++ b/src/NHibernate/Proxy/DynProxyTypeValidator.cs @@ -50,9 +50,8 @@ protected virtual void CheckAccessibleMembersAreVirtual(System.Type type) foreach (var member in members) { - if (member is PropertyInfo) + if (member is PropertyInfo property) { - var property = (PropertyInfo) member; if(property.ShouldBeProxiable()) { MethodInfo[] accessors = property.GetAccessors(true); @@ -66,21 +65,19 @@ protected virtual void CheckAccessibleMembersAreVirtual(System.Type type) } } } - else if (member is MethodInfo) + else if (member is MethodInfo method) { - var methodInfo = (MethodInfo) member; // avoid the check of properties getter and setter because already checked when the PropertyInfo was found. - if (!IsPropertyMethod(methodInfo) && methodInfo.ShouldBeProxiable()) + if (!IsPropertyMethod(method) && method.ShouldBeProxiable()) { - CheckMethodIsVirtual(type, methodInfo); + CheckMethodIsVirtual(type, method); } } - else if (member is FieldInfo) + else if (member is FieldInfo field) { - var memberField = (FieldInfo) member; - if (memberField.IsPublic || memberField.IsAssembly || memberField.IsFamilyOrAssembly) + if (field.IsPublic || field.IsAssembly || field.IsFamilyOrAssembly) { - EnlistError(type, "field " + member.Name + " should not be public nor internal (ecapsulate it in a property)."); + EnlistError(type, "field " + field.Name + " should not be public nor internal (ecapsulate it in a property)."); } } } From a25aab96f5de92d035b1a0f43ace753eb3d0f8e3 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 7 May 2024 09:12:50 +1000 Subject: [PATCH 090/128] Obsolete JoinedEnumerable (#3543) --- src/NHibernate.Test/Async/Legacy/FooBarTest.cs | 15 +++++---------- src/NHibernate.Test/Legacy/FooBarTest.cs | 15 +++++---------- .../UtilityTest/JoinedEnumerableFixture.cs | 2 ++ src/NHibernate/Async/Engine/Query/HQLQueryPlan.cs | 3 ++- src/NHibernate/Engine/Query/HQLQueryPlan.cs | 14 +++++++++++++- src/NHibernate/IQueryOver.cs | 2 +- src/NHibernate/Util/JoinedEnumerable.cs | 2 ++ 7 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs index 8be620d638f..0254b826f9a 100644 --- a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs @@ -16,6 +16,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; @@ -1222,10 +1223,7 @@ public async Task BatchLoadAsync() await (s.DeleteAsync(baz2)); await (s.DeleteAsync(baz3)); - IEnumerable en = new JoinedEnumerable( - new IEnumerable[] {baz.FooSet, baz2.FooSet}); - - foreach (object obj in en) + foreach (var obj in baz.FooSet.Concat(baz2.FooSet)) { await (s.DeleteAsync(obj)); } @@ -5273,16 +5271,13 @@ public async Task TransientOrphanDeleteAsync() Baz baz = new Baz(); var bars = new HashSet { new Bar(), new Bar(), new Bar() }; baz.CascadingBars = bars; - IList foos = new List(); - foos.Add(new Foo()); - foos.Add(new Foo()); + var foos = new List { new Foo(), new Foo() }; baz.FooBag = foos; await (s.SaveAsync(baz)); - IEnumerator enumer = new JoinedEnumerable(new IEnumerable[] {foos, bars}).GetEnumerator(); - while (enumer.MoveNext()) + foreach (var foo in foos.Concat(bars.Cast())) { - FooComponent cmp = ((Foo) enumer.Current).Component; + var cmp = foo.Component; await (s.DeleteAsync(cmp.Glarch)); cmp.Glarch = null; } diff --git a/src/NHibernate.Test/Legacy/FooBarTest.cs b/src/NHibernate.Test/Legacy/FooBarTest.cs index 17bf3d8a317..7dc868b4222 100644 --- a/src/NHibernate.Test/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Legacy/FooBarTest.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; @@ -1210,10 +1211,7 @@ public void BatchLoad() s.Delete(baz2); s.Delete(baz3); - IEnumerable en = new JoinedEnumerable( - new IEnumerable[] {baz.FooSet, baz2.FooSet}); - - foreach (object obj in en) + foreach (var obj in baz.FooSet.Concat(baz2.FooSet)) { s.Delete(obj); } @@ -5261,16 +5259,13 @@ public void TransientOrphanDelete() Baz baz = new Baz(); var bars = new HashSet { new Bar(), new Bar(), new Bar() }; baz.CascadingBars = bars; - IList foos = new List(); - foos.Add(new Foo()); - foos.Add(new Foo()); + var foos = new List { new Foo(), new Foo() }; baz.FooBag = foos; s.Save(baz); - IEnumerator enumer = new JoinedEnumerable(new IEnumerable[] {foos, bars}).GetEnumerator(); - while (enumer.MoveNext()) + foreach (var foo in foos.Concat(bars.Cast())) { - FooComponent cmp = ((Foo) enumer.Current).Component; + var cmp = foo.Component; s.Delete(cmp.Glarch); cmp.Glarch = null; } diff --git a/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs b/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs index c037121dc7c..5c0cb512b27 100644 --- a/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs +++ b/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs @@ -8,6 +8,8 @@ namespace NHibernate.Test.UtilityTest /// /// Test cases for the class. /// + // Since v5.6 + [Obsolete] [TestFixture] public class JoinedEnumerableFixture { diff --git a/src/NHibernate/Async/Engine/Query/HQLQueryPlan.cs b/src/NHibernate/Async/Engine/Query/HQLQueryPlan.cs index a5ced8d10d7..134e4fa7e9d 100644 --- a/src/NHibernate/Async/Engine/Query/HQLQueryPlan.cs +++ b/src/NHibernate/Async/Engine/Query/HQLQueryPlan.cs @@ -122,7 +122,8 @@ public async Task PerformIterateAsync(QueryParameters queryParamete var result = await (Translators[i].GetEnumerableAsync(queryParameters, session, cancellationToken)).ConfigureAwait(false); results[i] = result; } - return new JoinedEnumerable(results); + + return Enumerate(results); } public async Task> PerformIterateAsync(QueryParameters queryParameters, IEventSource session, CancellationToken cancellationToken) diff --git a/src/NHibernate/Engine/Query/HQLQueryPlan.cs b/src/NHibernate/Engine/Query/HQLQueryPlan.cs index fd6717a3d33..a3a83f1c9c4 100644 --- a/src/NHibernate/Engine/Query/HQLQueryPlan.cs +++ b/src/NHibernate/Engine/Query/HQLQueryPlan.cs @@ -171,7 +171,19 @@ public IEnumerable PerformIterate(QueryParameters queryParameters, IEventSource var result = Translators[i].GetEnumerable(queryParameters, session); results[i] = result; } - return new JoinedEnumerable(results); + + return Enumerate(results); + } + + private static IEnumerable Enumerate(IEnumerable[] enumerables) + { + foreach (var enumerable in enumerables) + { + foreach (var o in enumerable) + { + yield return o; + } + } } public IEnumerable PerformIterate(QueryParameters queryParameters, IEventSource session) diff --git a/src/NHibernate/IQueryOver.cs b/src/NHibernate/IQueryOver.cs index 0320da91a49..d9e9d35d2b4 100644 --- a/src/NHibernate/IQueryOver.cs +++ b/src/NHibernate/IQueryOver.cs @@ -362,7 +362,7 @@ public interface IQueryOver : IQueryOver ///
/// A lambda expression path (e.g., ChildList[0].Granchildren[0].Pets). /// - // Since 5.2 + // Since v5.2 [Obsolete("Use Fetch(SelectMode mode, Expression> path) instead")] IQueryOverFetchBuilder Fetch(Expression> path); diff --git a/src/NHibernate/Util/JoinedEnumerable.cs b/src/NHibernate/Util/JoinedEnumerable.cs index 2e9d3ab6b50..5fedb70da46 100644 --- a/src/NHibernate/Util/JoinedEnumerable.cs +++ b/src/NHibernate/Util/JoinedEnumerable.cs @@ -8,6 +8,8 @@ namespace NHibernate.Util /// /// Concatenates multiple objects implementing into one. /// + // Since v5.6 + [Obsolete("This class has no more usages in NHibernate and will be removed in a future version.")] public class JoinedEnumerable : IEnumerable { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(JoinedEnumerable)); From 705d7941d31e07a5097ec3166ca3b1f7a3e96c57 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 7 May 2024 15:43:09 +1000 Subject: [PATCH 091/128] Add a security policy (#3542) --- SECURITY.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..50416634993 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 5.5.x | :white_check_mark: | +| 5.4.x | :white_check_mark: | +| < 5.4 | :x: | + +## Reporting a Vulnerability + +**Please do NOT report security vulnerabilities through public GitHub issues.** + +Instead, please submit vulnerabilities using this [form](https://github.com/nhibernate/nhibernate-core/security/advisories/new). +If the issue is confirmed, we will try to release a patch version as soon as possible depending on complexity. From fdd7fcf3a37528647b057eb7bed8e7bcf08f87b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sat, 11 May 2024 22:00:01 +0200 Subject: [PATCH 092/128] Obsolete literal AddColumn (#3517) --- .../SqlCommandTest/SqlInsertBuilderFixture.cs | 8 +++++++- .../SqlCommandTest/SqlUpdateBuilderFixture.cs | 4 +++- src/NHibernate/SqlCommand/SqlInsertBuilder.cs | 2 ++ src/NHibernate/SqlCommand/SqlUpdateBuilder.cs | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs index 795bddf586c..ec1d5c0cb4e 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs @@ -26,7 +26,9 @@ public void InsertSqlStringTest() insert.AddColumn("intColumn", NHibernateUtil.Int32); insert.AddColumn("longColumn", NHibernateUtil.Int64); +#pragma warning disable CS0618 // Type or member is obsolete insert.AddColumn("literalColumn", false, (ILiteralType) NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete insert.AddColumn("stringColumn", 5.ToString()); SqlCommandInfo sqlCommand = insert.ToSqlCommandInfo(); @@ -53,7 +55,9 @@ public void Commented() insert.SetTableName("test_insert_builder"); +#pragma warning disable CS0618 // Type or member is obsolete insert.AddColumn("stringColumn", "aSQLValue", (ILiteralType)NHibernateUtil.String); +#pragma warning restore CS0618 // Type or member is obsolete insert.SetComment("Test insert"); string expectedSql = "/* Test insert */ INSERT INTO test_insert_builder (stringColumn) VALUES ('aSQLValue')"; @@ -71,7 +75,9 @@ public void MixingParametersAndValues() insert.SetTableName("test_insert_builder"); +#pragma warning disable CS0618 // Type or member is obsolete insert.AddColumn("literalColumn", false, (ILiteralType)NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete insert.AddColumn("intColumn", NHibernateUtil.Int32); insert.AddColumn("stringColumn", 5.ToString()); insert.AddColumn("longColumn", NHibernateUtil.Int64); @@ -89,4 +95,4 @@ public void MixingParametersAndValues() Assert.AreEqual(SqlTypeFactory.Int64, actualParameterTypes[1], "Second Parameter Type"); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs index c0bd0ece22b..96a47f2e245 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs @@ -28,7 +28,9 @@ public void UpdateStringSqlTest() update.AddColumns(new string[] {"intColumn"}, NHibernateUtil.Int32); update.AddColumns(new string[] {"longColumn"}, NHibernateUtil.Int64); +#pragma warning disable CS0618 // Type or member is obsolete update.AddColumn("literalColumn", false, (ILiteralType) NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete update.AddColumn("stringColumn", 5.ToString()); update.SetIdentityColumn(new string[] {"decimalColumn"}, NHibernateUtil.Decimal); @@ -60,4 +62,4 @@ public void UpdateStringSqlTest() Assert.AreEqual(expectedParameterTypes[3], actualParameterTypes[3], "fourthParam Type"); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs index d73f98fd4d5..07cb35c2483 100644 --- a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs @@ -66,6 +66,8 @@ public virtual SqlInsertBuilder AddColumn(string columnName, IType propertyType) /// The value to set for the column. /// The NHibernateType to use to convert the value to a sql string. /// The SqlInsertBuilder. + // Since v5.6 + [Obsolete("This method is unsafe and has no more usages. Use the overload with a property type and use a parameterized query.")] public SqlInsertBuilder AddColumn(string columnName, object val, ILiteralType literalType) { return AddColumn(columnName, literalType.ObjectToSQLString(val, Dialect)); diff --git a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs index c9b7ccd1352..8ad1d6cb88a 100644 --- a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs @@ -47,6 +47,8 @@ public SqlUpdateBuilder SetComment(string comment) /// The value to set for the column. /// The NHibernateType to use to convert the value to a sql string. /// The SqlUpdateBuilder. + // Since v5.6 + [Obsolete("This method is unsafe and has no more usages. Use the overload with a property type and use a parameterized query.")] public SqlUpdateBuilder AddColumn(string columnName, object val, ILiteralType literalType) { return AddColumn(columnName, literalType.ObjectToSQLString(val, Dialect)); From b967119ad5aee9e8c16b91277b3427a5891c8259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 12 May 2024 17:15:58 +0200 Subject: [PATCH 093/128] Upgrade Npgsql to a non vulnerable version (#3545) Co-authored-by: Alex Zaytsev --- .../PostgresExceptionConverterExample.cs | 16 ++++++++-------- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs b/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs index e4142c32f7f..ee794f0b9de 100644 --- a/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs +++ b/src/NHibernate.Test/ExceptionsTest/PostgresExceptionConverterExample.cs @@ -1,6 +1,6 @@ using System; -using System.Data.Common; using NHibernate.Exceptions; +using Npgsql; namespace NHibernate.Test.ExceptionsTest { @@ -10,23 +10,23 @@ public class PostgresExceptionConverterExample : ISQLExceptionConverter public Exception Convert(AdoExceptionContextInfo exInfo) { - var sqle = ADOExceptionHelper.ExtractDbException(exInfo.SqlException) as DbException; - if (sqle != null) + if (ADOExceptionHelper.ExtractDbException(exInfo.SqlException) is PostgresException pge) { - string code = (string)sqle.GetType().GetProperty("Code").GetValue(sqle, null); - + string code = pge.SqlState; if (code == "23503") { - return new ConstraintViolationException(exInfo.Message, sqle.InnerException, exInfo.Sql, null); + return new ConstraintViolationException(exInfo.Message, pge.InnerException, exInfo.Sql, null); } + if (code == "42P01") { - return new SQLGrammarException(exInfo.Message, sqle.InnerException, exInfo.Sql); + return new SQLGrammarException(exInfo.Message, pge.InnerException, exInfo.Sql); } } + return SQLStateConverter.HandledNonSpecificException(exInfo.SqlException, exInfo.Message, exInfo.Sql); } #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index e5e553f5b30..3b2b0dab83b 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -66,7 +66,7 @@ - + From 218aac35984a8dddf29af0be5a15224ce608db79 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 17 May 2024 11:46:08 +1000 Subject: [PATCH 094/128] Fix incorrect import in DynamicClassFixture (#3546) --- .../Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs | 2 +- .../EntityModeTest/Map/Basic/DynamicClassFixture.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs b/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs index 79ed1ab2d69..23fc0eaf206 100644 --- a/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs +++ b/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs @@ -8,12 +8,12 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq.Dynamic.Core; using System.Linq; -using Antlr.Runtime.Misc; using NUnit.Framework; using NHibernate.Criterion; using NHibernate.Linq; diff --git a/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs b/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs index eefbb25286a..5a51a0a14fe 100644 --- a/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs +++ b/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs @@ -1,9 +1,9 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq.Dynamic.Core; using System.Linq; -using Antlr.Runtime.Misc; using NUnit.Framework; using NHibernate.Criterion; From cb8b285de222a53500422c83c2527f12e133ee48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 21 May 2024 20:15:40 +0200 Subject: [PATCH 095/128] Upgrade vulnerable test dependencies (#3544) --- build-common/NHibernate.props | 1 + src/NHibernate.Test/NHibernate.Test.csproj | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index a614470a18b..3c2d1bdc620 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -16,6 +16,7 @@ net48;net6.0 net461;net48;netcoreapp2.0;netstandard2.0;netstandard2.1;net6.0 + 2.0.3 false true diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 3b2b0dab83b..5d53ca45259 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -56,11 +56,11 @@ - + - + @@ -76,14 +76,14 @@ - + - + - + From aaf03e6babfb1680ff55046ce037287bba7be9dd Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 22 May 2024 14:03:38 +1000 Subject: [PATCH 096/128] Obsolete NullableType.Get by column name (#3549) --- .../NHSpecific/NullableTypesType.cs | 5 ----- .../Async/TypesTest/BooleanTypeFixture.cs | 1 + .../Async/TypesTest/GuidTypeFixture.cs | 2 +- .../TypesTest/BooleanTypeFixture.cs | 14 ++++++++----- .../TypesTest/CharBooleanTypeFixture.cs | 6 ++++-- .../TypesTest/GuidTypeFixture.cs | 21 ++++++++++--------- src/NHibernate/Type/AbstractBinaryType.cs | 5 ----- src/NHibernate/Type/AbstractCharType.cs | 5 ----- src/NHibernate/Type/AbstractDateTimeType.cs | 4 ---- src/NHibernate/Type/AbstractStringType.cs | 5 ----- src/NHibernate/Type/BooleanType.cs | 5 ----- src/NHibernate/Type/ByteType.cs | 9 -------- src/NHibernate/Type/CharBooleanType.cs | 5 ----- src/NHibernate/Type/CultureInfoType.cs | 6 ------ src/NHibernate/Type/DateTimeOffSetType.cs | 5 ----- src/NHibernate/Type/DecimalType.cs | 5 ----- src/NHibernate/Type/DoubleType.cs | 9 -------- src/NHibernate/Type/EnumCharType.cs | 5 ----- src/NHibernate/Type/EnumStringType.cs | 5 ----- src/NHibernate/Type/GuidType.cs | 5 ----- src/NHibernate/Type/Int16Type.cs | 16 -------------- src/NHibernate/Type/Int32Type.cs | 16 -------------- src/NHibernate/Type/Int64Type.cs | 16 -------------- src/NHibernate/Type/NullableType.cs | 5 ++++- src/NHibernate/Type/PersistentEnumType.cs | 5 ----- src/NHibernate/Type/SByteType.cs | 16 -------------- src/NHibernate/Type/SerializableType.cs | 5 ----- src/NHibernate/Type/SingleType.cs | 16 -------------- src/NHibernate/Type/TimeAsTimeSpanType.cs | 5 ----- src/NHibernate/Type/TimeSpanType.cs | 12 ----------- src/NHibernate/Type/TimeType.cs | 5 ----- src/NHibernate/Type/TypeType.cs | 20 ------------------ src/NHibernate/Type/UInt16Type.cs | 16 -------------- src/NHibernate/Type/UInt32Type.cs | 16 -------------- src/NHibernate/Type/UInt64Type.cs | 16 -------------- src/NHibernate/Type/UriType.cs | 5 ----- src/NHibernate/Type/XDocType.cs | 5 ----- src/NHibernate/Type/XmlDocType.cs | 5 ----- 38 files changed, 30 insertions(+), 297 deletions(-) diff --git a/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs b/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs index 748697b6eec..0a6f9fc1f17 100644 --- a/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs +++ b/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs @@ -30,11 +30,6 @@ public override object NullSafeGet(DbDataReader rs, string name, ISessionImpleme } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return ReturnedClass.Name; } diff --git a/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs index 85b11c47f27..04d2b18b22e 100644 --- a/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Data.Common; using NHibernate.Engine; using NHibernate.Type; diff --git a/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs index 9f3a2e6c2a2..af573bacd09 100644 --- a/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs @@ -83,4 +83,4 @@ public async Task GuidInWhereClauseAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs index cd124b00d0e..2c394a42472 100644 --- a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs @@ -1,3 +1,4 @@ +using System; using System.Data.Common; using NHibernate.Engine; using NHibernate.Type; @@ -69,21 +70,24 @@ public void GetByIndex(bool expected) } [Theory] + [Obsolete("Testing obsolete API")] public void GetByName(bool expected) { const string name0 = "name0"; const string name1 = "name1"; - BooleanType type = NHibernateUtil.Boolean; + var type = NHibernateUtil.Boolean; var session = Substitute.For(); var reader = Substitute.For(); - reader[name0].Returns(expected); - reader[name1].Returns(expected); + reader.GetOrdinal(name0).Returns(0); + reader.GetOrdinal(name1).Returns(1); + reader[0].Returns(expected); + reader[1].Returns(expected); var result0 = type.Get(reader, name0, session); var result1 = type.Get(reader, name1, session); - Assert.AreEqual(expected, (bool) result0); - Assert.AreSame(result0, result1); + Assert.That((bool) result0, Is.EqualTo(expected)); + Assert.That(result1, Is.SameAs(result0)); } [Test] diff --git a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs index d4448ad6023..d07c2856aaa 100644 --- a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs @@ -1,4 +1,5 @@ -using System.Data.Common; +using System; +using System.Data.Common; using NHibernate.Engine; using NHibernate.SqlTypes; using NHibernate.Type; @@ -29,6 +30,7 @@ public void GetByIndex(bool expected) } [Theory] + [Obsolete("Testing obsolete API")] public void GetByName(bool value) { const string name = "0"; @@ -42,7 +44,7 @@ public void GetByName(bool value) var result = type.Get(reader, name, session); - Assert.AreSame(expected, result); + Assert.That(result, Is.SameAs(expected)); } [Theory] diff --git a/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs b/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs index b87ec50892b..be2bb8e191a 100644 --- a/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs @@ -93,7 +93,7 @@ public void GuidInWhereClause() [Test] public void GetGuidWorksWhenUnderlyingTypeIsRepresentedByString() { - GuidType type = (GuidType)NHibernateUtil.Guid; + var type = NHibernateUtil.Guid; Guid value = Guid.NewGuid(); DataTable data = new DataTable("test"); @@ -106,14 +106,15 @@ public void GetGuidWorksWhenUnderlyingTypeIsRepresentedByString() var reader = data.CreateDataReader(); reader.Read(); - using (var s = OpenSession()) - { - var si = s.GetSessionImplementation(); - Assert.AreEqual(value, type.Get(reader, "guid", si)); - Assert.AreEqual(value, type.Get(reader, 0, si)); - Assert.AreEqual(value, type.Get(reader, "varchar", si)); - Assert.AreEqual(value, type.Get(reader, 1, si)); - } + using var s = OpenSession(); + var si = s.GetSessionImplementation(); + + Assert.That(type.Get(reader, 0, si), Is.EqualTo(value)); + Assert.That(type.Get(reader, 1, si), Is.EqualTo(value)); +#pragma warning disable CS0618 // Type or member is obsolete + Assert.That(type.Get(reader, "guid", si), Is.EqualTo(value)); + Assert.That(type.Get(reader, "varchar", si), Is.EqualTo(value)); +#pragma warning restore CS0618 // Type or member is obsolete } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Type/AbstractBinaryType.cs b/src/NHibernate/Type/AbstractBinaryType.cs index 2e5882731e6..a6adc443fdc 100644 --- a/src/NHibernate/Type/AbstractBinaryType.cs +++ b/src/NHibernate/Type/AbstractBinaryType.cs @@ -90,11 +90,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return ToExternalFormat(buffer); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override int GetHashCode(object x) { byte[] bytes = ToInternalFormat(x); diff --git a/src/NHibernate/Type/AbstractCharType.cs b/src/NHibernate/Type/AbstractCharType.cs index 5efb630c16c..f813c85fb60 100644 --- a/src/NHibernate/Type/AbstractCharType.cs +++ b/src/NHibernate/Type/AbstractCharType.cs @@ -30,11 +30,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return '\0'; // This line should never be executed } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override System.Type PrimitiveClass { get { return typeof(char); } diff --git a/src/NHibernate/Type/AbstractDateTimeType.cs b/src/NHibernate/Type/AbstractDateTimeType.cs index 8f95323cb78..b5b5b5c65c3 100644 --- a/src/NHibernate/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Type/AbstractDateTimeType.cs @@ -58,10 +58,6 @@ protected virtual DateTime AdjustDateTime(DateTime dateValue) => public override object Get(DbDataReader rs, int index, ISessionImplementor session) => GetDateTime(rs, index, session); - /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) => - Get(rs, rs.GetOrdinal(name), session); - /// /// Get the in the for the Property. /// diff --git a/src/NHibernate/Type/AbstractStringType.cs b/src/NHibernate/Type/AbstractStringType.cs index 9d47aaf07ff..e5c073b7df7 100644 --- a/src/NHibernate/Type/AbstractStringType.cs +++ b/src/NHibernate/Type/AbstractStringType.cs @@ -76,11 +76,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return Convert.ToString(rs[index]); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Convert.ToString(rs[name]); - } - public override bool IsEqual(object x, object y) { return Comparer.Equals(x, y); diff --git a/src/NHibernate/Type/BooleanType.cs b/src/NHibernate/Type/BooleanType.cs index 2a154211b7b..d93e23e0385 100644 --- a/src/NHibernate/Type/BooleanType.cs +++ b/src/NHibernate/Type/BooleanType.cs @@ -43,11 +43,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return GetBooleanAsObject(Convert.ToBoolean(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return GetBooleanAsObject(Convert.ToBoolean(rs[name])); - } - public override System.Type PrimitiveClass => typeof(bool); public override System.Type ReturnedClass => typeof(bool); diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index ed8196bac67..4a1e5fa7928 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -32,15 +32,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi }; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return rs[name] switch - { - BigInteger bi => (byte) bi, - var c => Convert.ToByte(c) - }; - } - public override System.Type ReturnedClass { get { return typeof(byte); } diff --git a/src/NHibernate/Type/CharBooleanType.cs b/src/NHibernate/Type/CharBooleanType.cs index 53dc6a9abb3..1224fb363d5 100644 --- a/src/NHibernate/Type/CharBooleanType.cs +++ b/src/NHibernate/Type/CharBooleanType.cs @@ -40,11 +40,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override void Set(DbCommand cmd, Object value, int index, ISessionImplementor session) { cmd.Parameters[index].Value = ToCharacter(value); diff --git a/src/NHibernate/Type/CultureInfoType.cs b/src/NHibernate/Type/CultureInfoType.cs index 417e4b2ef89..4ae13cf364e 100644 --- a/src/NHibernate/Type/CultureInfoType.cs +++ b/src/NHibernate/Type/CultureInfoType.cs @@ -32,12 +32,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return ParseStringRepresentation(NHibernateUtil.String.Get(rs, index, session)); } - /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { diff --git a/src/NHibernate/Type/DateTimeOffSetType.cs b/src/NHibernate/Type/DateTimeOffSetType.cs index 37837aec289..de9e8b2216c 100644 --- a/src/NHibernate/Type/DateTimeOffSetType.cs +++ b/src/NHibernate/Type/DateTimeOffSetType.cs @@ -73,11 +73,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public object Next(object current, ISessionImplementor session) { return Seed(session); diff --git a/src/NHibernate/Type/DecimalType.cs b/src/NHibernate/Type/DecimalType.cs index 158fa028fc7..06fb8d449d9 100644 --- a/src/NHibernate/Type/DecimalType.cs +++ b/src/NHibernate/Type/DecimalType.cs @@ -27,11 +27,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return Convert.ToDecimal(rs[index]); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Convert.ToDecimal(rs[name]); - } - public override System.Type ReturnedClass { get { return typeof(Decimal); } diff --git a/src/NHibernate/Type/DoubleType.cs b/src/NHibernate/Type/DoubleType.cs index 9fbe8a0ed71..fb5c159c9aa 100644 --- a/src/NHibernate/Type/DoubleType.cs +++ b/src/NHibernate/Type/DoubleType.cs @@ -30,15 +30,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi }; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return rs[name] switch - { - BigInteger bi => (double) bi, - var v => Convert.ToDouble(v) - }; - } - /// public override System.Type ReturnedClass { diff --git a/src/NHibernate/Type/EnumCharType.cs b/src/NHibernate/Type/EnumCharType.cs index ece3684ff6f..1068642ac09 100644 --- a/src/NHibernate/Type/EnumCharType.cs +++ b/src/NHibernate/Type/EnumCharType.cs @@ -119,11 +119,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return "enumchar - " + this.ReturnedClass.Name; } diff --git a/src/NHibernate/Type/EnumStringType.cs b/src/NHibernate/Type/EnumStringType.cs index 168ce03291f..01f8ce0d6c0 100644 --- a/src/NHibernate/Type/EnumStringType.cs +++ b/src/NHibernate/Type/EnumStringType.cs @@ -148,11 +148,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/GuidType.cs b/src/NHibernate/Type/GuidType.cs index a883f3a6b5a..938a5436af4 100644 --- a/src/NHibernate/Type/GuidType.cs +++ b/src/NHibernate/Type/GuidType.cs @@ -33,11 +33,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return new Guid(Convert.ToString(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override System.Type ReturnedClass { diff --git a/src/NHibernate/Type/Int16Type.cs b/src/NHibernate/Type/Int16Type.cs index f55c1d1b2f5..20d2975f0d8 100644 --- a/src/NHibernate/Type/Int16Type.cs +++ b/src/NHibernate/Type/Int16Type.cs @@ -44,22 +44,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name]switch - { - BigInteger bi => (short) bi, - var c => Convert.ToInt16(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(Int16); } diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index 02371f1bc3c..21c568ffb3a 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -45,22 +45,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (int) bi, - var c => Convert.ToInt32(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(Int32); } diff --git a/src/NHibernate/Type/Int64Type.cs b/src/NHibernate/Type/Int64Type.cs index 3fa7892f4bf..42899a25794 100644 --- a/src/NHibernate/Type/Int64Type.cs +++ b/src/NHibernate/Type/Int64Type.cs @@ -44,22 +44,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (long) bi, - var c => Convert.ToInt64(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(Int64); } diff --git a/src/NHibernate/Type/NullableType.cs b/src/NHibernate/Type/NullableType.cs index 883894ee971..caf386a631f 100644 --- a/src/NHibernate/Type/NullableType.cs +++ b/src/NHibernate/Type/NullableType.cs @@ -80,7 +80,10 @@ protected NullableType(SqlType sqlType) /// Most implementors just call the /// overload of this method. /// - public abstract object Get(DbDataReader rs, string name, ISessionImplementor session); + // Since v5.6 + [Obsolete("This method has no more usages and will be removed in a future version.")] + public virtual object Get(DbDataReader rs, string name, ISessionImplementor session) => + Get(rs, rs.GetOrdinal(name), session); /// /// A representation of the value to be embedded in an XML element diff --git a/src/NHibernate/Type/PersistentEnumType.cs b/src/NHibernate/Type/PersistentEnumType.cs index 51c10a4313f..ee2748033b1 100644 --- a/src/NHibernate/Type/PersistentEnumType.cs +++ b/src/NHibernate/Type/PersistentEnumType.cs @@ -226,11 +226,6 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme cmd.Parameters[index].Value = value != null ? GetValue(value) : DBNull.Value; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return ReturnedClass.FullName; } diff --git a/src/NHibernate/Type/SByteType.cs b/src/NHibernate/Type/SByteType.cs index 2f861bda232..304a034958c 100644 --- a/src/NHibernate/Type/SByteType.cs +++ b/src/NHibernate/Type/SByteType.cs @@ -44,22 +44,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (sbyte) bi, - var c => Convert.ToSByte(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(SByte); } diff --git a/src/NHibernate/Type/SerializableType.cs b/src/NHibernate/Type/SerializableType.cs index 54b85ecc3cb..2c38715fbe0 100644 --- a/src/NHibernate/Type/SerializableType.cs +++ b/src/NHibernate/Type/SerializableType.cs @@ -56,11 +56,6 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen binaryType.Set(st, ToBytes(value), index, session); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override object Get(DbDataReader rs, int index, ISessionImplementor session) { byte[] bytes = (byte[]) binaryType.Get(rs, index, session); diff --git a/src/NHibernate/Type/SingleType.cs b/src/NHibernate/Type/SingleType.cs index 0cab527f6a6..31166b2b925 100644 --- a/src/NHibernate/Type/SingleType.cs +++ b/src/NHibernate/Type/SingleType.cs @@ -48,22 +48,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (float) bi, - var v => Convert.ToSingle(v) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(Single); } diff --git a/src/NHibernate/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Type/TimeAsTimeSpanType.cs index e525ecfa555..993262af202 100644 --- a/src/NHibernate/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Type/TimeAsTimeSpanType.cs @@ -57,11 +57,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { if (session.Factory.ConnectionProvider.Driver.RequiresTimeSpanForTime) diff --git a/src/NHibernate/Type/TimeSpanType.cs b/src/NHibernate/Type/TimeSpanType.cs index 5ca576454b9..5123362a34a 100644 --- a/src/NHibernate/Type/TimeSpanType.cs +++ b/src/NHibernate/Type/TimeSpanType.cs @@ -38,18 +38,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return new TimeSpan(Convert.ToInt64(rs[name])); - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - /// public override System.Type ReturnedClass { diff --git a/src/NHibernate/Type/TimeType.cs b/src/NHibernate/Type/TimeType.cs index be487f81cff..c095ef0c0d2 100644 --- a/src/NHibernate/Type/TimeType.cs +++ b/src/NHibernate/Type/TimeType.cs @@ -66,11 +66,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override System.Type ReturnedClass { get { return typeof(DateTime); } diff --git a/src/NHibernate/Type/TypeType.cs b/src/NHibernate/Type/TypeType.cs index 6d5b541257a..f19edaaabb0 100644 --- a/src/NHibernate/Type/TypeType.cs +++ b/src/NHibernate/Type/TypeType.cs @@ -46,26 +46,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return ParseStringRepresentation(NHibernateUtil.String.Get(rs, index, session)); } - /// - /// Gets the in the for the Property. - /// - /// The that contains the value. - /// The name of the field to get the value from. - /// The session for which the operation is done. - /// The from the database. - /// - /// This just calls gets the index of the name in the DbDataReader - /// and calls the overloaded version - /// (DbDataReader, Int32). - /// - /// - /// Thrown when the value in the database can not be loaded as a - /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// /// Puts the Assembly Qualified Name of the /// Property into to the . diff --git a/src/NHibernate/Type/UInt16Type.cs b/src/NHibernate/Type/UInt16Type.cs index 8628e8d4a91..ae50718c1e2 100644 --- a/src/NHibernate/Type/UInt16Type.cs +++ b/src/NHibernate/Type/UInt16Type.cs @@ -44,22 +44,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (ushort) bi, - var c => Convert.ToUInt16(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(UInt16); } diff --git a/src/NHibernate/Type/UInt32Type.cs b/src/NHibernate/Type/UInt32Type.cs index 274d101b5ae..0aa02ca8722 100644 --- a/src/NHibernate/Type/UInt32Type.cs +++ b/src/NHibernate/Type/UInt32Type.cs @@ -44,22 +44,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (uint) bi, - var c => Convert.ToUInt32(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(UInt32); } diff --git a/src/NHibernate/Type/UInt64Type.cs b/src/NHibernate/Type/UInt64Type.cs index 83d710a47f3..8c1064f6f8a 100644 --- a/src/NHibernate/Type/UInt64Type.cs +++ b/src/NHibernate/Type/UInt64Type.cs @@ -43,22 +43,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (ulong) bi, - var c => Convert.ToUInt64(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - public override System.Type ReturnedClass { get { return typeof(UInt64); } diff --git a/src/NHibernate/Type/UriType.cs b/src/NHibernate/Type/UriType.cs index 68f319606d3..48fbe91a9c8 100644 --- a/src/NHibernate/Type/UriType.cs +++ b/src/NHibernate/Type/UriType.cs @@ -54,11 +54,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return StringToObject(Convert.ToString(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return StringToObject(Convert.ToString(rs[name])); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/XDocType.cs b/src/NHibernate/Type/XDocType.cs index fc29eaf478f..69912c8ec77 100644 --- a/src/NHibernate/Type/XDocType.cs +++ b/src/NHibernate/Type/XDocType.cs @@ -47,11 +47,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi #pragma warning restore 618 } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/XmlDocType.cs b/src/NHibernate/Type/XmlDocType.cs index a138ee56b46..d4b26317f29 100644 --- a/src/NHibernate/Type/XmlDocType.cs +++ b/src/NHibernate/Type/XmlDocType.cs @@ -46,11 +46,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi #pragma warning restore 618 } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { From c3662c90cccd64e14595ea6970f16223e068b850 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sat, 25 May 2024 06:03:19 +1000 Subject: [PATCH 097/128] Cache zero values to reduce boxing in PrimitiveType.DefaultValue (#3552) --- src/NHibernate/Async/Type/Int16Type.cs | 4 --- src/NHibernate/Type/AbstractCharType.cs | 19 ++++------- src/NHibernate/Type/AbstractDateTimeType.cs | 13 +++----- src/NHibernate/Type/ByteType.cs | 33 ++++++------------- src/NHibernate/Type/DateTimeOffSetType.cs | 35 +++++---------------- src/NHibernate/Type/DateType.cs | 5 +-- src/NHibernate/Type/DecimalType.cs | 24 +++++--------- src/NHibernate/Type/DoubleType.cs | 29 +++++++---------- src/NHibernate/Type/GuidType.cs | 24 +++++--------- src/NHibernate/Type/Int16Type.cs | 34 +++++--------------- src/NHibernate/Type/Int32Type.cs | 31 +++++------------- src/NHibernate/Type/Int64Type.cs | 30 +++++------------- src/NHibernate/Type/PrimitiveType.cs | 14 +++------ src/NHibernate/Type/SByteType.cs | 34 +++++--------------- src/NHibernate/Type/SingleType.cs | 31 +++++++----------- src/NHibernate/Type/TimeAsTimeSpanType.cs | 35 +++++---------------- src/NHibernate/Type/TimeSpanType.cs | 31 +++++------------- src/NHibernate/Type/UInt16Type.cs | 30 +++++------------- src/NHibernate/Type/UInt32Type.cs | 30 +++++------------- src/NHibernate/Type/UInt64Type.cs | 30 +++++------------- 20 files changed, 142 insertions(+), 374 deletions(-) diff --git a/src/NHibernate/Async/Type/Int16Type.cs b/src/NHibernate/Async/Type/Int16Type.cs index 804d767eafd..598f83c5aa5 100644 --- a/src/NHibernate/Async/Type/Int16Type.cs +++ b/src/NHibernate/Async/Type/Int16Type.cs @@ -24,8 +24,6 @@ namespace NHibernate.Type public partial class Int16Type : PrimitiveType, IDiscriminatorType, IVersionType { - #region IVersionType Members - public virtual Task NextAsync(object current, ISessionImplementor session, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) @@ -57,7 +55,5 @@ public virtual Task SeedAsync(ISessionImplementor session, CancellationT return Task.FromException(ex); } } - - #endregion } } diff --git a/src/NHibernate/Type/AbstractCharType.cs b/src/NHibernate/Type/AbstractCharType.cs index f813c85fb60..ba2ad5bb761 100644 --- a/src/NHibernate/Type/AbstractCharType.cs +++ b/src/NHibernate/Type/AbstractCharType.cs @@ -11,14 +11,13 @@ namespace NHibernate.Type [Serializable] public abstract class AbstractCharType : PrimitiveType, IDiscriminatorType { - public AbstractCharType(SqlType sqlType) - : base(sqlType) {} - - public override object DefaultValue + /// + public AbstractCharType(SqlType sqlType) : base(sqlType) { - get { throw new NotSupportedException("not a valid id type"); } } + public override object DefaultValue => throw new NotSupportedException("not a valid id type"); + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { string dbValue = Convert.ToString(rs[index]); @@ -30,15 +29,9 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return '\0'; // This line should never be executed } - public override System.Type PrimitiveClass - { - get { return typeof(char); } - } + public override System.Type PrimitiveClass => typeof(char); - public override System.Type ReturnedClass - { - get { return typeof(char); } - } + public override System.Type ReturnedClass => typeof(char); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { diff --git a/src/NHibernate/Type/AbstractDateTimeType.cs b/src/NHibernate/Type/AbstractDateTimeType.cs index b5b5b5c65c3..9deb2273d3e 100644 --- a/src/NHibernate/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Type/AbstractDateTimeType.cs @@ -14,7 +14,7 @@ namespace NHibernate.Type [Serializable] public abstract partial class AbstractDateTimeType : PrimitiveType, IIdentifierType, ILiteralType, IVersionType { - private static readonly DateTime BaseDateValue = DateTime.MinValue; + private static readonly object BaseDateValue = DateTime.MinValue; /// /// Returns the for the type. @@ -31,17 +31,12 @@ public abstract partial class AbstractDateTimeType : PrimitiveType, IIdentifierT /// otherwise. protected virtual DateTime Now => Kind == DateTimeKind.Utc ? DateTime.UtcNow : DateTime.Now; - /// - /// Default constructor. - /// - protected AbstractDateTimeType() : base(SqlTypeFactory.DateTime) + /// + protected AbstractDateTimeType() : this(SqlTypeFactory.DateTime) { } - /// - /// Constructor for overriding the default . - /// - /// The to use. + /// protected AbstractDateTimeType(SqlType sqlTypeDateTime) : base(sqlTypeDateTime) { } diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index 4a1e5fa7928..f52071890ff 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -15,10 +15,10 @@ namespace NHibernate.Type [Serializable] public partial class ByteType : PrimitiveType, IDiscriminatorType, IVersionType { - private static readonly byte ZERO = 0; + private static readonly object ZeroObject = (byte) 0; - public ByteType() - : base(SqlTypeFactory.Byte) + /// + public ByteType() : base(SqlTypeFactory.Byte) { } @@ -32,15 +32,9 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi }; } - public override System.Type ReturnedClass - { - get { return typeof(byte); } - } + public override System.Type ReturnedClass => typeof(byte); - public override System.Type PrimitiveClass - { - get { return typeof(byte); } - } + public override System.Type PrimitiveClass => typeof(byte); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { @@ -48,10 +42,7 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme dp.Value = dp.DbType == DbType.Int16 ? Convert.ToInt16(value) : Convert.ToByte(value); } - public override string Name - { - get { return "Byte"; } - } + public override string Name => "Byte"; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { @@ -84,17 +75,11 @@ public virtual object Next(object current, ISessionImplementor session) public virtual object Seed(ISessionImplementor session) { - return ZERO; + return ZeroObject; } - public IComparer Comparator - { - get { return Comparer.DefaultInvariant; } - } + public IComparer Comparator => Comparer.DefaultInvariant; - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; } } diff --git a/src/NHibernate/Type/DateTimeOffSetType.cs b/src/NHibernate/Type/DateTimeOffSetType.cs index de9e8b2216c..10bfa4f6804 100644 --- a/src/NHibernate/Type/DateTimeOffSetType.cs +++ b/src/NHibernate/Type/DateTimeOffSetType.cs @@ -14,47 +14,26 @@ namespace NHibernate.Type [Serializable] public partial class DateTimeOffsetType : PrimitiveType, IIdentifierType, ILiteralType, IVersionType { - static readonly DateTimeOffset BaseDateValue = DateTimeOffset.MinValue; + private static readonly object BaseDateValue = DateTimeOffset.MinValue; - /// - /// Default constructor. - /// public DateTimeOffsetType() : base(SqlTypeFactory.DateTimeOffSet) { } - /// - /// Constructor for specifying a datetimeoffset with a scale. Use . - /// - /// The sql type to use for the type. + /// public DateTimeOffsetType(DateTimeOffsetSqlType sqlType) : base(sqlType) { } - public override string Name - { - get { return "DateTimeOffset"; } - } + public override string Name => "DateTimeOffset"; - public override System.Type ReturnedClass - { - get { return typeof (DateTimeOffset); } - } + public override System.Type ReturnedClass => typeof (DateTimeOffset); - public override System.Type PrimitiveClass - { - get { return typeof (DateTimeOffset); } - } + public override System.Type PrimitiveClass => typeof (DateTimeOffset); - public override object DefaultValue - { - get { return BaseDateValue; } - } + public override object DefaultValue => BaseDateValue; - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { diff --git a/src/NHibernate/Type/DateType.cs b/src/NHibernate/Type/DateType.cs index 76d3fbb99e9..7bf772c9e95 100644 --- a/src/NHibernate/Type/DateType.cs +++ b/src/NHibernate/Type/DateType.cs @@ -21,11 +21,12 @@ public class DateType : AbstractDateTimeType, IParameterizedType // Since v5.0 [Obsolete("Use DateTime.MinValue.")] public static readonly DateTime BaseDateValue = DateTime.MinValue; - private DateTime customBaseDate = _baseDateValue; private static readonly DateTime _baseDateValue = DateTime.MinValue; - /// Default constructor + private object customBaseDate = _baseDateValue; + + /// public DateType() : base(SqlTypeFactory.Date) { } diff --git a/src/NHibernate/Type/DecimalType.cs b/src/NHibernate/Type/DecimalType.cs index 06fb8d449d9..e2398ec4ce6 100644 --- a/src/NHibernate/Type/DecimalType.cs +++ b/src/NHibernate/Type/DecimalType.cs @@ -13,11 +13,15 @@ namespace NHibernate.Type [Serializable] public class DecimalType : PrimitiveType, IIdentifierType { + private static readonly object ZeroObject = 0m; + + /// public DecimalType() : this(SqlTypeFactory.Decimal) { } + /// public DecimalType(SqlType sqlType) : base(sqlType) { } @@ -27,30 +31,18 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return Convert.ToDecimal(rs[index]); } - public override System.Type ReturnedClass - { - get { return typeof(Decimal); } - } + public override System.Type ReturnedClass => typeof(Decimal); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { st.Parameters[index].Value = Convert.ToDecimal(value); } - public override string Name - { - get { return "Decimal"; } - } + public override string Name => "Decimal"; - public override System.Type PrimitiveClass - { - get { return typeof (Decimal); } - } + public override System.Type PrimitiveClass => typeof (Decimal); - public override object DefaultValue - { - get { return 0m; } - } + public override object DefaultValue => ZeroObject; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] diff --git a/src/NHibernate/Type/DoubleType.cs b/src/NHibernate/Type/DoubleType.cs index fb5c159c9aa..45b5713f525 100644 --- a/src/NHibernate/Type/DoubleType.cs +++ b/src/NHibernate/Type/DoubleType.cs @@ -14,12 +14,17 @@ namespace NHibernate.Type [Serializable] public class DoubleType : PrimitiveType { - /// + private static readonly object ZeroObject = 0D; + + /// public DoubleType() : base(SqlTypeFactory.Double) { } - public DoubleType(SqlType sqlType) : base(sqlType) {} + /// + public DoubleType(SqlType sqlType) : base(sqlType) + { + } public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -31,10 +36,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } /// - public override System.Type ReturnedClass - { - get { return typeof(double); } - } + public override System.Type ReturnedClass => typeof(double); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { @@ -42,10 +44,7 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen } /// - public override string Name - { - get { return "Double"; } - } + public override string Name => "Double"; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] @@ -54,15 +53,9 @@ public override object FromStringValue(string xml) return double.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(double); } - } + public override System.Type PrimitiveClass => typeof(double); - public override object DefaultValue - { - get { return 0D; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/GuidType.cs b/src/NHibernate/Type/GuidType.cs index 938a5436af4..2dc627d5d09 100644 --- a/src/NHibernate/Type/GuidType.cs +++ b/src/NHibernate/Type/GuidType.cs @@ -13,7 +13,9 @@ namespace NHibernate.Type [Serializable] public class GuidType : PrimitiveType, IDiscriminatorType { - /// + private static readonly object EmptyObject = Guid.Empty; + + /// public GuidType() : base(SqlTypeFactory.Guid) { } @@ -34,10 +36,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } /// - public override System.Type ReturnedClass - { - get { return typeof(Guid); } - } + public override System.Type ReturnedClass => typeof(Guid); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { @@ -47,10 +46,7 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme } /// - public override string Name - { - get { return "Guid"; } - } + public override string Name => "Guid"; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] @@ -71,15 +67,9 @@ public object StringToObject(string xml) #pragma warning restore 618 } - public override System.Type PrimitiveClass - { - get { return typeof(Guid); } - } + public override System.Type PrimitiveClass => typeof(Guid); - public override object DefaultValue - { - get { return Guid.Empty; } - } + public override object DefaultValue => EmptyObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/Int16Type.cs b/src/NHibernate/Type/Int16Type.cs index 20d2975f0d8..cfd21908465 100644 --- a/src/NHibernate/Type/Int16Type.cs +++ b/src/NHibernate/Type/Int16Type.cs @@ -16,18 +16,16 @@ namespace NHibernate.Type [Serializable] public partial class Int16Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = (short) 0; + + /// public Int16Type() : base(SqlTypeFactory.Int16) { } /// - public override string Name - { - get { return "Int16"; } - } + public override string Name => "Int16"; - private static readonly Int16 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(Int16); } - } + public override System.Type ReturnedClass => typeof(Int16); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -76,8 +71,6 @@ public override object FromStringValue(string xml) return Int16.Parse(xml); } - #region IVersionType Members - public virtual object Next(object current, ISessionImplementor session) { return (Int16)((Int16)current + 1); @@ -88,22 +81,11 @@ public virtual object Seed(ISessionImplementor session) return (Int16)1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; - #endregion + public override System.Type PrimitiveClass => typeof (Int16); - public override System.Type PrimitiveClass - { - get { return typeof (Int16); } - } - - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index 21c568ffb3a..f19fb1148fd 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -16,18 +16,15 @@ namespace NHibernate.Type [Serializable] public partial class Int32Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0; + + /// public Int32Type() : base(SqlTypeFactory.Int32) { } /// - public override string Name - { - get { return "Int32"; } - } - - private static readonly Int32 ZERO = 0; + public override string Name => "Int32"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -45,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(Int32); } - } + public override System.Type ReturnedClass => typeof(Int32); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -89,22 +83,13 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(Int32); } - } + public override System.Type PrimitiveClass => typeof(Int32); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/Int64Type.cs b/src/NHibernate/Type/Int64Type.cs index 42899a25794..b86cb619443 100644 --- a/src/NHibernate/Type/Int64Type.cs +++ b/src/NHibernate/Type/Int64Type.cs @@ -16,18 +16,16 @@ namespace NHibernate.Type [Serializable] public partial class Int64Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0L; + + /// public Int64Type() : base(SqlTypeFactory.Int64) { } /// - public override string Name - { - get { return "Int64"; } - } + public override string Name => "Int64"; - private static readonly Int64 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(Int64); } - } + public override System.Type ReturnedClass => typeof(Int64); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -88,22 +83,13 @@ public virtual object Seed(ISessionImplementor session) return 1L; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(Int64); } - } + public override System.Type PrimitiveClass => typeof(Int64); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/PrimitiveType.cs b/src/NHibernate/Type/PrimitiveType.cs index 7b452db3481..2956f394eb5 100644 --- a/src/NHibernate/Type/PrimitiveType.cs +++ b/src/NHibernate/Type/PrimitiveType.cs @@ -10,19 +10,15 @@ namespace NHibernate.Type [Serializable] public abstract class PrimitiveType : ImmutableType, ILiteralType { - /// - /// Initialize a new instance of the PrimitiveType class using a . - /// - /// The underlying . - protected PrimitiveType(SqlType sqlType) - : base(sqlType) {} + /// + protected PrimitiveType(SqlType sqlType) : base(sqlType) + { + } public abstract System.Type PrimitiveClass { get; } public abstract object DefaultValue { get; } - #region ILiteralType Members - /// /// When implemented by a class, return a representation /// of the value, suitable for embedding in an SQL statement @@ -32,8 +28,6 @@ protected PrimitiveType(SqlType sqlType) /// A string that containts a well formed SQL Statement. public abstract string ObjectToSQLString(object value, Dialect.Dialect dialect); - #endregion - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/SByteType.cs b/src/NHibernate/Type/SByteType.cs index 304a034958c..513cacb6e70 100644 --- a/src/NHibernate/Type/SByteType.cs +++ b/src/NHibernate/Type/SByteType.cs @@ -16,18 +16,16 @@ namespace NHibernate.Type [Serializable] public class SByteType : PrimitiveType, IDiscriminatorType { - /// + private static readonly object ZeroObject = (sbyte) 0; + + /// public SByteType() : base(SqlTypeFactory.SByte) { } /// - public override string Name - { - get { return "SByte"; } - } + public override string Name => "SByte"; - private static readonly SByte ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(SByte); } - } + public override System.Type ReturnedClass => typeof(SByte); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -72,8 +67,6 @@ public override object FromStringValue(string xml) return SByte.Parse(xml); } - #region IVersionType Members - // Since 5.2 [Obsolete("This member has no more usage and will be removed in a future version.")] public virtual object Next(object current, ISessionImplementor session) @@ -90,22 +83,11 @@ public virtual object Seed(ISessionImplementor session) // Since 5.2 [Obsolete("This member has no more usage and will be removed in a future version.")] - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; - #endregion + public override System.Type PrimitiveClass => typeof(SByte); - public override System.Type PrimitiveClass - { - get { return typeof(SByte); } - } - - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/SingleType.cs b/src/NHibernate/Type/SingleType.cs index 31166b2b925..a5d56ce9ade 100644 --- a/src/NHibernate/Type/SingleType.cs +++ b/src/NHibernate/Type/SingleType.cs @@ -18,20 +18,20 @@ namespace NHibernate.Type [Serializable] public class SingleType : PrimitiveType { - /// - public SingleType() : base(SqlTypeFactory.Single) + private static readonly object ZeroObject = 0F; + + public SingleType() : this(SqlTypeFactory.Single) { } - public SingleType(SqlType sqlType) : base(sqlType) {} - - /// - public override string Name + /// + public SingleType(SqlType sqlType) : base(sqlType) { - get { return "Single"; } } - private static readonly Single ZERO = 0; + /// + public override string Name => "Single"; + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -48,10 +48,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(Single); } - } + public override System.Type ReturnedClass => typeof(Single); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -72,15 +69,9 @@ public override object FromStringValue(string xml) return Single.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(Single); } - } + public override System.Type PrimitiveClass => typeof(Single); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Type/TimeAsTimeSpanType.cs index 993262af202..f5218c0775c 100644 --- a/src/NHibernate/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Type/TimeAsTimeSpanType.cs @@ -16,27 +16,20 @@ namespace NHibernate.Type [Serializable] public partial class TimeAsTimeSpanType : PrimitiveType, IVersionType { + private static readonly object ZeroObject = TimeSpan.Zero; private static readonly DateTime BaseDateValue = new DateTime(1753, 01, 01); - /// - /// Default constructor. - /// + /// public TimeAsTimeSpanType() : base(SqlTypeFactory.Time) { } - /// - /// Constructor for specifying a time with a scale. Use . - /// - /// The sql type to use for the type. + /// public TimeAsTimeSpanType(TimeSqlType sqlType) : base(sqlType) { } - public override string Name - { - get { return "TimeAsTimeSpan"; } - } + public override string Name => "TimeAsTimeSpan"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -65,10 +58,7 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen st.Parameters[index].Value = BaseDateValue.AddTicks(((TimeSpan)value).Ticks); } - public override System.Type ReturnedClass - { - get { return typeof(TimeSpan); } - } + public override System.Type ReturnedClass => typeof(TimeSpan); /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) @@ -106,10 +96,7 @@ public object StringToObject(string xml) return TimeSpan.Parse(xml); } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion @@ -124,15 +111,9 @@ public override object FromStringValue(string xml) return TimeSpan.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(TimeSpan); } - } + public override System.Type PrimitiveClass => typeof(TimeSpan); - public override object DefaultValue - { - get { return TimeSpan.Zero; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/TimeSpanType.cs b/src/NHibernate/Type/TimeSpanType.cs index 5123362a34a..ed37b4629d2 100644 --- a/src/NHibernate/Type/TimeSpanType.cs +++ b/src/NHibernate/Type/TimeSpanType.cs @@ -14,17 +14,14 @@ namespace NHibernate.Type [Serializable] public partial class TimeSpanType : PrimitiveType, IVersionType, ILiteralType { - /// - public TimeSpanType() - : base(SqlTypeFactory.Int64) + private static readonly object ZeroObject = TimeSpan.Zero; + + public TimeSpanType() : base(SqlTypeFactory.Int64) { } /// - public override string Name - { - get { return "TimeSpan"; } - } + public override string Name => "TimeSpan"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -39,10 +36,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } /// - public override System.Type ReturnedClass - { - get { return typeof(TimeSpan); } - } + public override System.Type ReturnedClass => typeof(TimeSpan); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { @@ -86,10 +80,7 @@ public object StringToObject(string xml) return TimeSpan.Parse(xml); } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion @@ -104,15 +95,9 @@ public override object FromStringValue(string xml) return TimeSpan.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(TimeSpan); } - } + public override System.Type PrimitiveClass => typeof(TimeSpan); - public override object DefaultValue - { - get { return TimeSpan.Zero; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/UInt16Type.cs b/src/NHibernate/Type/UInt16Type.cs index ae50718c1e2..c37bbfaca75 100644 --- a/src/NHibernate/Type/UInt16Type.cs +++ b/src/NHibernate/Type/UInt16Type.cs @@ -16,18 +16,16 @@ namespace NHibernate.Type [Serializable] public partial class UInt16Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = (ushort) 0; + + /// public UInt16Type() : base(SqlTypeFactory.UInt16) { } /// - public override string Name - { - get { return "UInt16"; } - } + public override string Name => "UInt16"; - private static readonly UInt16 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(UInt16); } - } + public override System.Type ReturnedClass => typeof(UInt16); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -88,22 +83,13 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt16); } - } + public override System.Type PrimitiveClass => typeof(UInt16); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/UInt32Type.cs b/src/NHibernate/Type/UInt32Type.cs index 0aa02ca8722..e0e30b65f2f 100644 --- a/src/NHibernate/Type/UInt32Type.cs +++ b/src/NHibernate/Type/UInt32Type.cs @@ -16,18 +16,16 @@ namespace NHibernate.Type [Serializable] public partial class UInt32Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0U; + + /// public UInt32Type() : base(SqlTypeFactory.UInt32) { } /// - public override string Name - { - get { return "UInt32"; } - } + public override string Name => "UInt32"; - private static readonly UInt32 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,10 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(UInt32); } - } + public override System.Type ReturnedClass => typeof(UInt32); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -88,22 +83,13 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt32); } - } + public override System.Type PrimitiveClass => typeof(UInt32); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { diff --git a/src/NHibernate/Type/UInt64Type.cs b/src/NHibernate/Type/UInt64Type.cs index 8c1064f6f8a..8d0c05d20b1 100644 --- a/src/NHibernate/Type/UInt64Type.cs +++ b/src/NHibernate/Type/UInt64Type.cs @@ -16,17 +16,15 @@ namespace NHibernate.Type [Serializable] public partial class UInt64Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0UL; + + /// public UInt64Type() : base(SqlTypeFactory.UInt64) { } - public override string Name - { - get { return "UInt64"; } - } + public override string Name => "UInt64"; - private static readonly UInt32 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -43,10 +41,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override System.Type ReturnedClass - { - get { return typeof(UInt64); } - } + public override System.Type ReturnedClass => typeof(UInt64); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -87,22 +82,13 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt64); } - } + public override System.Type PrimitiveClass => typeof(UInt64); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { From db22eaa439fa5de032e6b2a416511ccefa2e8ebc Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sat, 25 May 2024 13:38:46 +1000 Subject: [PATCH 098/128] Obsolete ForeignKeys.IsNotTransientSlow (#3553) --- src/NHibernate/Async/Engine/ForeignKeys.cs | 3 +++ src/NHibernate/Engine/ForeignKeys.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/NHibernate/Async/Engine/ForeignKeys.cs b/src/NHibernate/Async/Engine/ForeignKeys.cs index 8185a996af4..4e91d411bdb 100644 --- a/src/NHibernate/Async/Engine/ForeignKeys.cs +++ b/src/NHibernate/Async/Engine/ForeignKeys.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using NHibernate.Id; using NHibernate.Persister.Entity; using NHibernate.Proxy; @@ -152,6 +153,8 @@ private async Task IsNullifiableAsync(string entityName, object obj, Cance /// /// Hit the database to make the determination. /// + // Since v5.6 + [Obsolete("This method has no more usages and will be removed in a future version")] public static async Task IsNotTransientSlowAsync(string entityName, object entity, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Engine/ForeignKeys.cs b/src/NHibernate/Engine/ForeignKeys.cs index fe8dbb9cdea..ed2e7c404d3 100644 --- a/src/NHibernate/Engine/ForeignKeys.cs +++ b/src/NHibernate/Engine/ForeignKeys.cs @@ -1,3 +1,4 @@ +using System; using NHibernate.Id; using NHibernate.Persister.Entity; using NHibernate.Proxy; @@ -151,6 +152,8 @@ private bool IsNullifiable(string entityName, object obj) /// /// Hit the database to make the determination. /// + // Since v5.6 + [Obsolete("This method has no more usages and will be removed in a future version")] public static bool IsNotTransientSlow(string entityName, object entity, ISessionImplementor session) { return !IsTransientSlow(entityName, entity, session); From f9fcdcd73d27ce2794564cef08f2f299bc6d9c75 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 5 Jun 2024 08:56:59 +1000 Subject: [PATCH 099/128] Add support for .NET 8 Math functions (#3556) --- .../Linq/Functions/MathGenerator.cs | 44 +++++++++++++++++-- .../Linq/Functions/RoundGenerator.cs | 7 +++ .../Linq/Functions/TruncateGenerator.cs | 4 ++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/NHibernate/Linq/Functions/MathGenerator.cs b/src/NHibernate/Linq/Functions/MathGenerator.cs index 5f8351f1f3c..990ea27e0df 100644 --- a/src/NHibernate/Linq/Functions/MathGenerator.cs +++ b/src/NHibernate/Linq/Functions/MathGenerator.cs @@ -80,16 +80,52 @@ public MathGenerator() ReflectHelper.FastGetMethod(MathF.Ceiling, default(float)), ReflectHelper.FastGetMethod(MathF.Pow, default(float), default(float)), +#endif +#if NET8_0_OR_GREATER + ReflectHelper.FastGetMethod(float.Sin, default(float)), + ReflectHelper.FastGetMethod(float.Cos, default(float)), + ReflectHelper.FastGetMethod(float.Tan, default(float)), + ReflectHelper.FastGetMethod(float.Sinh, default(float)), + ReflectHelper.FastGetMethod(float.Cosh, default(float)), + ReflectHelper.FastGetMethod(float.Tanh, default(float)), + ReflectHelper.FastGetMethod(float.Asin, default(float)), + ReflectHelper.FastGetMethod(float.Acos, default(float)), + ReflectHelper.FastGetMethod(float.Atan, default(float)), + ReflectHelper.FastGetMethod(float.Atan2, default(float), default(float)), + ReflectHelper.FastGetMethod(float.Sqrt, default(float)), + ReflectHelper.FastGetMethod(float.Abs, default(float)), + ReflectHelper.FastGetMethod(float.Sign, default(float)), + ReflectHelper.FastGetMethod(float.Floor, default(float)), + ReflectHelper.FastGetMethod(float.Ceiling, default(float)), + ReflectHelper.FastGetMethod(float.Pow, default(float), default(float)), + + ReflectHelper.FastGetMethod(double.Sin, default(double)), + ReflectHelper.FastGetMethod(double.Cos, default(double)), + ReflectHelper.FastGetMethod(double.Tan, default(double)), + ReflectHelper.FastGetMethod(double.Sinh, default(double)), + ReflectHelper.FastGetMethod(double.Cosh, default(double)), + ReflectHelper.FastGetMethod(double.Tanh, default(double)), + ReflectHelper.FastGetMethod(double.Asin, default(double)), + ReflectHelper.FastGetMethod(double.Acos, default(double)), + ReflectHelper.FastGetMethod(double.Atan, default(double)), + ReflectHelper.FastGetMethod(double.Atan2, default(double), default(double)), + ReflectHelper.FastGetMethod(double.Sqrt, default(double)), + ReflectHelper.FastGetMethod(double.Abs, default(double)), + ReflectHelper.FastGetMethod(double.Sign, default(double)), + ReflectHelper.FastGetMethod(double.Floor, default(double)), + ReflectHelper.FastGetMethod(double.Ceiling, default(double)), + ReflectHelper.FastGetMethod(double.Pow, default(double), default(double)), #endif }; } public override HqlTreeNode BuildHql(MethodInfo method, Expression expression, ReadOnlyCollection arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { - string function = method.Name.ToLowerInvariant(); - - if (function == "pow") - function = "power"; + var function = method.Name.ToLowerInvariant() switch + { + "pow" => "power", + var f => f, + }; var firstArgument = visitor.Visit(arguments[0]).AsExpression(); diff --git a/src/NHibernate/Linq/Functions/RoundGenerator.cs b/src/NHibernate/Linq/Functions/RoundGenerator.cs index ec349b157d8..b5d82f6cc87 100644 --- a/src/NHibernate/Linq/Functions/RoundGenerator.cs +++ b/src/NHibernate/Linq/Functions/RoundGenerator.cs @@ -25,6 +25,13 @@ public RoundGenerator() ReflectHelper.FastGetMethod(MathF.Round, default(float)), ReflectHelper.FastGetMethod(MathF.Round, default(float), default(int)), #endif + +#if NET8_0_OR_GREATER + ReflectHelper.FastGetMethod(float.Round, default(float)), + ReflectHelper.FastGetMethod(float.Round, default(float), default(int)), + ReflectHelper.FastGetMethod(double.Round, default(double)), + ReflectHelper.FastGetMethod(double.Round, default(double), default(int)), +#endif }; } diff --git a/src/NHibernate/Linq/Functions/TruncateGenerator.cs b/src/NHibernate/Linq/Functions/TruncateGenerator.cs index d2f646f6ebd..ba404cdb9b2 100644 --- a/src/NHibernate/Linq/Functions/TruncateGenerator.cs +++ b/src/NHibernate/Linq/Functions/TruncateGenerator.cs @@ -20,6 +20,10 @@ public TruncateGenerator() #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER ReflectHelper.FastGetMethod(MathF.Truncate, default(float)), +#endif +#if NET8_0_OR_GREATER + ReflectHelper.FastGetMethod(float.Truncate, default(float)), + ReflectHelper.FastGetMethod(double.Truncate, default(double)), #endif }; } From 93b0d0ef975dd62a3249d3f7f3d54b18f89f81ff Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 7 Jun 2024 09:14:31 +1000 Subject: [PATCH 100/128] Migrate AppVeyor & TC builds to PostgreSQL 13 (#3558) --- appveyor.yml | 4 ++-- lib/teamcity/postgresql/postgresql_installation.txt | 10 +++++----- teamcity.build | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c9703d631ab..a050578f683 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,8 +47,8 @@ before_test: 'Odbc' { Start-Service 'MSSQL$SQL2017' } 'PostgreSQL' { # Enable prepared transactions - Add-Content -Path 'C:\Program Files\PostgreSQL\10\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" - Start-Service 'postgresql-x64-10' + Add-Content -Path 'C:\Program Files\PostgreSQL\13\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" + Start-Service 'postgresql-x64-13' } 'SqlServer2008' { Start-Service 'MSSQL$SQL2017' } 'SqlServer2012' { Start-Service 'MSSQL$SQL2017' } diff --git a/lib/teamcity/postgresql/postgresql_installation.txt b/lib/teamcity/postgresql/postgresql_installation.txt index b5deb92b10a..28e90cc7d5a 100644 --- a/lib/teamcity/postgresql/postgresql_installation.txt +++ b/lib/teamcity/postgresql/postgresql_installation.txt @@ -1,7 +1,7 @@ Installation steps for PostgreSQL for NH TeamCity: -1. Download PostgreSQL (postgresql-9.0.3-1-windows_x64.exe): http://www.enterprisedb.com/products-services-training/pgdownload#windows; +1. Download PostgreSQL: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads; 2. Run the installer ... when prompted to make a password for the service account, make it 'password'; 3. Leave the port number at the default (5432), and leave the default locale; 4. The setup should install PostgreSQL on the machine; @@ -12,8 +12,8 @@ Installation steps for PostgreSQL for NH TeamCity: Creating the NH user: -a. Open pgAdmin III (start -> programs -> PostgreSQL 9.0 -> pgAdmin III); -b. right-click the PostgreSQL 9.0 database, select connect, and enter the password from step 2 above; -c. right-clilck the Login Roles, and select "New Login Role ..."; -d. create a login with "Role name=nhibernate", "Password=nhibernate", and select Superuser on the Role privileges tab. +a. Open pgAdmin 4; +b. Right-click the PostgreSQL database, select connect, and enter the password from step 2 above; +c. Right-clilck the Login Roles, and select "New Login Role ..."; +d. Create a login with "Role name=nhibernate", "Password=nhibernate", and select Superuser on the Role privileges tab. diff --git a/teamcity.build b/teamcity.build index 7e90e13e430..e4345967d6a 100644 --- a/teamcity.build +++ b/teamcity.build @@ -124,7 +124,7 @@ - + From 3a651d0b9109309f3512f1a12353ae0b64c70ac9 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 7 Jun 2024 09:40:30 +1000 Subject: [PATCH 101/128] Fix support for nullable struct components (#3554) --- .../Async/NHSpecificTest/NH1284/Fixture.cs | 49 ++++++++++ .../NHSpecificTest/NH1284/Fixture.cs | 32 ++++--- .../NHSpecificTest/NH1284/Mappings.hbm.xml | 2 +- .../Cfg/XmlHbmBinding/ClassIdBinder.cs | 4 +- .../Cfg/XmlHbmBinding/PropertiesBinder.cs | 93 ++++++++----------- .../Tuple/Component/PocoComponentTuplizer.cs | 5 +- 6 files changed, 109 insertions(+), 76 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs new file mode 100644 index 00000000000..998c03fd985 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1284 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnTearDown() + { + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + s.Delete("from Person"); + tx.Commit(); + } + + [Test] + public async Task EmptyValueTypeComponentAsync() + { + Person jimmy; + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + var p = new Person("Jimmy Hendrix"); + await (s.SaveAsync(p)); + await (tx.CommitAsync()); + } + + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + jimmy = await (s.GetAsync("Jimmy Hendrix")); + await (tx.CommitAsync()); + } + + Assert.That(jimmy.Address, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs index c0bcf309e9d..5a2b8c4e6cb 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs @@ -2,35 +2,37 @@ namespace NHibernate.Test.NHSpecificTest.NH1284 { - [TestFixture, Ignore("Not supported yet.")] + [TestFixture] public class Fixture : BugTestCase { + protected override void OnTearDown() + { + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + s.Delete("from Person"); + tx.Commit(); + } + [Test] public void EmptyValueTypeComponent() { Person jimmy; - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) { - Person p = new Person("Jimmy Hendrix"); + var p = new Person("Jimmy Hendrix"); s.Save(p); tx.Commit(); } - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) { - jimmy = (Person)s.Get(typeof(Person), "Jimmy Hendrix"); + jimmy = s.Get("Jimmy Hendrix"); tx.Commit(); } - Assert.IsFalse(jimmy.Address.HasValue); - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) - { - s.Delete("from Person"); - tx.Commit(); - } + Assert.That(jimmy.Address, Is.Null); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml index 6b9e124d1c6..214bf7fb496 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs index e0a1c4ad245..89a7bef6faa 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs @@ -45,7 +45,7 @@ private void CreateIdentifierProperty(HbmId idSchema, PersistentClass rootClass, if (idSchema.name != null) { string access = idSchema.access ?? mappings.DefaultAccess; - id.SetTypeUsingReflection(rootClass.MappedClass == null ? null : rootClass.MappedClass.AssemblyQualifiedName, idSchema.name, access); + id.SetTypeUsingReflection(rootClass.MappedClass?.AssemblyQualifiedName, idSchema.name, access); var property = new Property(id) { Name = idSchema.name }; @@ -85,4 +85,4 @@ private static void BindUnsavedValue(HbmId idSchema, SimpleValue id) id.NullValue = idSchema.unsavedvalue ?? (id.IdentifierGeneratorStrategy == "assigned" ? "undefined" : null); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs index 3fbbc63aa57..80d4500e0fc 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs @@ -4,7 +4,6 @@ using NHibernate.Mapping; using System; using NHibernate.Util; -using Array = System.Array; namespace NHibernate.Cfg.XmlHbmBinding { @@ -14,7 +13,6 @@ public class PropertiesBinder : ClassBinder private readonly Component component; private readonly string entityName; private readonly System.Type mappedClass; - private readonly string className; private readonly bool componetDefaultNullable; private readonly string propertyBasePath; @@ -38,7 +36,6 @@ public PropertiesBinder(Mappings mappings, PersistentClass persistentClass) this.persistentClass = persistentClass; entityName = persistentClass.EntityName; propertyBasePath = entityName; - className = persistentClass.ClassName; mappedClass = persistentClass.MappedClass; componetDefaultNullable = true; component = null; @@ -50,7 +47,6 @@ public PropertiesBinder(Mappings mappings, Component component, string className persistentClass = component.Owner; this.component = component; entityName = className; - this.className = component.ComponentClassName; mappedClass = component.ComponentClass; propertyBasePath = path; componetDefaultNullable = isNullable; @@ -87,26 +83,14 @@ public void Bind(IEnumerable properties, Table table, ID string propertyName = entityPropertyMapping.Name; - ICollectionPropertiesMapping collectionMapping; - HbmManyToOne manyToOneMapping; - HbmAny anyMapping; - HbmOneToOne oneToOneMapping; - HbmProperty propertyMapping; - HbmComponent componentMapping; - HbmDynamicComponent dynamicComponentMapping; - HbmNestedCompositeElement nestedCompositeElementMapping; - HbmKeyProperty keyPropertyMapping; - HbmKeyManyToOne keyManyToOneMapping; - HbmProperties propertiesMapping; - - if ((propertyMapping = entityPropertyMapping as HbmProperty) != null) + if (entityPropertyMapping is HbmProperty propertyMapping) { var value = new SimpleValue(table); new ValuePropertyBinder(value, Mappings).BindSimpleValue(propertyMapping, propertyName, true); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindValueProperty(propertyMapping, property); } - else if ((collectionMapping = entityPropertyMapping as ICollectionPropertiesMapping) != null) + else if (entityPropertyMapping is ICollectionPropertiesMapping collectionMapping) { var collectionBinder = new CollectionBinder(Mappings); string propertyPath = propertyName == null ? null : StringHelper.Qualify(propertyBasePath, propertyName); @@ -116,59 +100,59 @@ public void Bind(IEnumerable properties, Table table, ID mappings.AddCollection(collection); - property = CreateProperty(collectionMapping, className, collection, inheritedMetas); + property = CreateProperty(collectionMapping, mappedClass, collection, inheritedMetas); BindCollectionProperty(collectionMapping, property); } - else if ((propertiesMapping = entityPropertyMapping as HbmProperties) != null) + else if (entityPropertyMapping is HbmProperties propertiesMapping) { var subpath = propertyName == null ? null : StringHelper.Qualify(propertyBasePath, propertyName); var value = CreateNewComponent(table); BindComponent(propertiesMapping, value, null, entityName, subpath, componetDefaultNullable, inheritedMetas); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindComponentProperty(propertiesMapping, property, value); } - else if ((manyToOneMapping = entityPropertyMapping as HbmManyToOne) != null) + else if (entityPropertyMapping is HbmManyToOne manyToOneMapping) { var value = new ManyToOne(table); BindManyToOne(manyToOneMapping, value, propertyName, true); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindManyToOneProperty(manyToOneMapping, property); } - else if ((componentMapping = entityPropertyMapping as HbmComponent) != null) + else if (entityPropertyMapping is HbmComponent componentMapping) { string subpath = propertyName == null ? null : StringHelper.Qualify(propertyBasePath, propertyName); var value = CreateNewComponent(table); // NH: Modified from H2.1 to allow specifying the type explicitly using class attribute System.Type reflectedClass = mappedClass == null ? null : GetPropertyType(componentMapping.Class, mappedClass, propertyName, componentMapping.Access); BindComponent(componentMapping, value, reflectedClass, entityName, subpath, componetDefaultNullable, inheritedMetas); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindComponentProperty(componentMapping, property, value); } - else if ((oneToOneMapping = entityPropertyMapping as HbmOneToOne) != null) + else if (entityPropertyMapping is HbmOneToOne oneToOneMapping) { var value = new OneToOne(table, persistentClass); BindOneToOne(oneToOneMapping, value); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindOneToOneProperty(oneToOneMapping, property); } - else if ((dynamicComponentMapping = entityPropertyMapping as HbmDynamicComponent) != null) + else if (entityPropertyMapping is HbmDynamicComponent dynamicComponentMapping) { string subpath = propertyName == null ? null : StringHelper.Qualify(propertyBasePath, propertyName); var value = CreateNewComponent(table); // NH: Modified from H2.1 to allow specifying the type explicitly using class attribute System.Type reflectedClass = mappedClass == null ? null : GetPropertyType(dynamicComponentMapping.Class, mappedClass, propertyName, dynamicComponentMapping.Access); BindComponent(dynamicComponentMapping, value, reflectedClass, entityName, subpath, componetDefaultNullable, inheritedMetas); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindComponentProperty(dynamicComponentMapping, property, value); } - else if ((anyMapping = entityPropertyMapping as HbmAny) != null) + else if (entityPropertyMapping is HbmAny anyMapping) { var value = new Any(table); BindAny(anyMapping, value, true); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); BindAnyProperty(anyMapping, property); } - else if ((nestedCompositeElementMapping = entityPropertyMapping as HbmNestedCompositeElement) != null) + else if (entityPropertyMapping is HbmNestedCompositeElement nestedCompositeElementMapping) { if (component == null) { @@ -179,19 +163,19 @@ public void Bind(IEnumerable properties, Table table, ID // NH: Modified from H2.1 to allow specifying the type explicitly using class attribute System.Type reflectedClass = mappedClass == null ? null : GetPropertyType(nestedCompositeElementMapping.Class, mappedClass, propertyName, nestedCompositeElementMapping.access); BindComponent(nestedCompositeElementMapping, value, reflectedClass, entityName, subpath, componetDefaultNullable, inheritedMetas); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); } - else if ((keyPropertyMapping = entityPropertyMapping as HbmKeyProperty) != null) + else if (entityPropertyMapping is HbmKeyProperty keyPropertyMapping) { var value = new SimpleValue(table); new ValuePropertyBinder(value, Mappings).BindSimpleValue(keyPropertyMapping, propertyName, componetDefaultNullable); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); } - else if ((keyManyToOneMapping = entityPropertyMapping as HbmKeyManyToOne) != null) + else if (entityPropertyMapping is HbmKeyManyToOne keyManyToOneMapping) { var value = new ManyToOne(table); BindKeyManyToOne(keyManyToOneMapping, value, propertyName, componetDefaultNullable); - property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property = CreateProperty(entityPropertyMapping, mappedClass, value, inheritedMetas); } if (property != null) @@ -402,30 +386,27 @@ private void BindCollectionProperty(ICollectionPropertiesMapping collectionMappi property.Cascade = collectionMapping.Cascade ?? mappings.DefaultCascade; } - private Property CreateProperty(IEntityPropertyMapping propertyMapping, string propertyOwnerClassName, IValue value, IDictionary inheritedMetas) + private Property CreateProperty(IEntityPropertyMapping propertyMapping, System.Type propertyOwnerType, IValue value, IDictionary inheritedMetas) { + var type = propertyOwnerType?.UnwrapIfNullable(); if (string.IsNullOrEmpty(propertyMapping.Name)) - { - throw new MappingException("A property mapping must define the name attribute [" + propertyOwnerClassName + "]"); - } + throw new MappingException("A property mapping must define the name attribute [" + type + "]"); var propertyAccessorName = GetPropertyAccessorName(propertyMapping.Access); - if (!string.IsNullOrEmpty(propertyOwnerClassName) && value.IsSimpleValue) - value.SetTypeUsingReflection(propertyOwnerClassName, propertyMapping.Name, propertyAccessorName); + if (type != null && value.IsSimpleValue) + value.SetTypeUsingReflection(type.AssemblyQualifiedName, propertyMapping.Name, propertyAccessorName); - var property = new Property - { - Name = propertyMapping.Name, - PropertyAccessorName = propertyAccessorName, - Value = value, - IsLazy = propertyMapping.IsLazyProperty, - LazyGroup = propertyMapping.GetLazyGroup(), - IsOptimisticLocked = propertyMapping.OptimisticLock, - MetaAttributes = GetMetas(propertyMapping, inheritedMetas) - }; - - return property; + return new Property + { + Name = propertyMapping.Name, + PropertyAccessorName = propertyAccessorName, + Value = value, + IsLazy = propertyMapping.IsLazyProperty, + LazyGroup = propertyMapping.GetLazyGroup(), + IsOptimisticLocked = propertyMapping.OptimisticLock, + MetaAttributes = GetMetas(propertyMapping, inheritedMetas) + }; } private string GetPropertyAccessorName(string propertyMappedAccessor) diff --git a/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs b/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs index 88fd793bc35..d4ae15b5aa4 100644 --- a/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs +++ b/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs @@ -3,6 +3,7 @@ using NHibernate.Bytecode.Lightweight; using NHibernate.Intercept; using NHibernate.Properties; +using NHibernate.Util; namespace NHibernate.Tuple.Component { @@ -155,12 +156,12 @@ protected internal override IInstantiator BuildInstantiator(Mapping.Component co protected internal override IGetter BuildGetter(Mapping.Component component, Mapping.Property prop) { - return prop.GetGetter(component.ComponentClass); + return prop.GetGetter(component.ComponentClass.UnwrapIfNullable()); } protected internal override ISetter BuildSetter(Mapping.Component component, Mapping.Property prop) { - return prop.GetSetter(component.ComponentClass); + return prop.GetSetter(component.ComponentClass.UnwrapIfNullable()); } protected void SetReflectionOptimizer() From bea3a31e64b736e7fd7e4f8bf9d3e73704f72842 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sun, 9 Jun 2024 12:01:06 +1000 Subject: [PATCH 102/128] Add new DB2NetDriver and obsolete DB2CoreDriver (#3559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- src/NHibernate.Test/TestDialect.cs | 7 ++++- .../TestDialects/DB2TestDialect.cs | 16 ++++++++++ .../TestDatabaseSetup.cs | 7 +++++ src/NHibernate/Dialect/DB2Dialect.cs | 5 ++++ src/NHibernate/Driver/DB2CoreDriver.cs | 24 +++++---------- src/NHibernate/Driver/DB2NetDriver.cs | 29 +++++++++++++++++++ 6 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 src/NHibernate.Test/TestDialects/DB2TestDialect.cs create mode 100644 src/NHibernate/Driver/DB2NetDriver.cs diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index 69ab31fcb37..bcf2218ccbf 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -123,10 +123,15 @@ public bool SupportsSqlType(SqlType sqlType) /// public virtual bool SupportsModuloOnDecimal => true; + /// + /// Supports sub-selects in order by clause + /// + public virtual bool SupportsSubSelectsInOrderBy => _dialect.SupportsScalarSubSelects; + /// /// Supports aggregating sub-selects in order by clause /// - public virtual bool SupportsAggregatingScalarSubSelectsInOrderBy => _dialect.SupportsScalarSubSelects; + public virtual bool SupportsAggregatingScalarSubSelectsInOrderBy => SupportsSubSelectsInOrderBy; /// /// Supports order by and limits/top in correlated sub-queries diff --git a/src/NHibernate.Test/TestDialects/DB2TestDialect.cs b/src/NHibernate.Test/TestDialects/DB2TestDialect.cs new file mode 100644 index 00000000000..a96b57eeb24 --- /dev/null +++ b/src/NHibernate.Test/TestDialects/DB2TestDialect.cs @@ -0,0 +1,16 @@ +namespace NHibernate.Test.TestDialects +{ + public class DB2TestDialect: TestDialect + { + public DB2TestDialect(Dialect.Dialect dialect) : base(dialect) + { + } + + public override bool HasBrokenTypeInferenceOnSelectedParameters => true; + public override bool SupportsCancelQuery => false; + public override bool SupportsComplexExpressionInGroupBy => false; + public override bool SupportsNonDataBoundCondition => false; + public override bool SupportsSelectForUpdateWithPaging => false; + public override bool SupportsSubSelectsInOrderBy => false; + } +} diff --git a/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs b/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs index 0856f339d02..a11b7f157b6 100644 --- a/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs +++ b/src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.cs @@ -32,6 +32,9 @@ public class DatabaseSetup {"NHibernate.Driver.OracleManagedDataClientDriver", SetupOracle}, {"NHibernate.Driver.OdbcDriver", SetupSqlServerOdbc}, {"NHibernate.Driver.SQLite20Driver", SetupSQLite}, + {"NHibernate.Driver.DB2Driver", SetupDB2}, + {"NHibernate.Driver.DB2CoreDriver", SetupDB2}, + {"NHibernate.Driver.DB2NetDriver", SetupDB2}, #if NETFX {"NHibernate.Driver.SqlServerCeDriver", SetupSqlServerCe}, {"NHibernate.Driver.SapSQLAnywhere17Driver", SetupSqlAnywhere} @@ -207,6 +210,10 @@ private static void SetupSQLite(Cfg.Configuration cfg) } } + private static void SetupDB2(Cfg.Configuration cfg) + { + } + private static void SetupOracle(Cfg.Configuration cfg) { // disabled until system password is set on TeamCity diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index a558e6d313d..042c206f1e7 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -214,6 +214,8 @@ public override bool SupportsSequences get { return true; } } + public override string QuerySequencesString => "select seqname from syscat.sequences"; + /// public override bool SupportsLimit { @@ -311,6 +313,9 @@ public override string ForUpdateString public override bool SupportsExistsInSelect => false; + /// + public override bool SupportsHavingOnGroupedByComputation => false; + public override bool DoesReadCommittedCauseWritersToBlockReaders => true; #endregion diff --git a/src/NHibernate/Driver/DB2CoreDriver.cs b/src/NHibernate/Driver/DB2CoreDriver.cs index 1838ee13373..80f8a922d98 100644 --- a/src/NHibernate/Driver/DB2CoreDriver.cs +++ b/src/NHibernate/Driver/DB2CoreDriver.cs @@ -1,27 +1,19 @@ -using System.Data.Common; -using NHibernate.SqlTypes; +using System; namespace NHibernate.Driver { /// /// A NHibernate Driver for using the IBM.Data.DB2.Core DataProvider. /// - public class DB2CoreDriver : DB2DriverBase - { - public DB2CoreDriver() : base("IBM.Data.DB2.Core") - { - } + // Since v5.6 + [Obsolete("Please use DB2NetDriver")] + public class DB2CoreDriver : DB2NetDriver + { + private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(DB2CoreDriver)); - public override bool UseNamedPrefixInSql => true; - - public override bool UseNamedPrefixInParameter => true; - - public override string NamedPrefix => "@"; - - protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType) + public DB2CoreDriver() : base("IBM.Data.DB2.Core") { - dbParam.ParameterName = FormatNameForParameter(name); - base.InitializeParameter(dbParam, name, sqlType); + Log.Warn("DB2CoreDriver is obsolete, please use DB2NetDriver instead."); } } } diff --git a/src/NHibernate/Driver/DB2NetDriver.cs b/src/NHibernate/Driver/DB2NetDriver.cs new file mode 100644 index 00000000000..0d05976d174 --- /dev/null +++ b/src/NHibernate/Driver/DB2NetDriver.cs @@ -0,0 +1,29 @@ +using System.Data.Common; +using NHibernate.SqlTypes; + +namespace NHibernate.Driver +{ + /// + /// A NHibernate Driver for using the Net5.IBM.Data.Db2/Net.IBM.Data.Db2 DataProvider. + /// + public class DB2NetDriver : DB2DriverBase + { + private protected DB2NetDriver(string assemblyName) : base(assemblyName) + { + } + + public DB2NetDriver() : base("IBM.Data.Db2") + { + } + + public override bool UseNamedPrefixInSql => true; + public override bool UseNamedPrefixInParameter => true; + public override string NamedPrefix => "@"; + + protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType) + { + dbParam.ParameterName = FormatNameForParameter(name); + base.InitializeParameter(dbParam, name, sqlType); + } + } +} From e8028fb802a13d02938cdccf81a33252821b8b02 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Sun, 9 Jun 2024 23:11:28 +1000 Subject: [PATCH 103/128] Migrate .NET Core SQLite Windows tests from AppVeyor to GitHub Actions (#3561) --- .github/workflows/NetCoreTests.yml | 14 +++++++++++--- appveyor.yml | 1 - 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index 81fb907d31e..61b2de7b7f0 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -7,42 +7,50 @@ jobs: strategy: fail-fast: false matrix: + DB: [SQLite] + OS: [ubuntu-latest, windows-latest, macos-13] include: - DB: SqlServer2008 CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" + OS: ubuntu-latest DB_INIT: | docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; - DB: SqlServer2008-MicrosoftDataSqlClientDriver CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" + OS: ubuntu-latest DB_INIT: | docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; - DB: PostgreSQL CONNECTION_STRING: "Host=localhost;Username=nhibernate;Password=nhibernate;Database=nhibernate;Enlist=true;" + OS: ubuntu-latest DB_INIT: | docker run -d -e POSTGRES_USER=nhibernate -e POSTGRES_PASSWORD=nhibernate -e POSTGRES_DB=nhibernate -p 5432:5432 postgres:13 - DB: Firebird CONNECTION_STRING: "DataSource=localhost;Database=nhibernate;User=SYSDBA;Password=nhibernate;charset=utf8;" + OS: ubuntu-latest DB_INIT: | docker run --name firebird -e EnableWireCrypt=true -e FIREBIRD_USER=nhibernate -e FIREBIRD_PASSWORD=nhibernate -e ISC_PASSWORD=nhibernate -e FIREBIRD_DATABASE=nhibernate -p 3050:3050 -d jacobalberty/firebird:v3.0 - DB: Firebird4 CONNECTION_STRING: "DataSource=localhost;Database=nhibernate;User=SYSDBA;Password=nhibernate;charset=utf8;" + OS: ubuntu-latest DB_INIT: | docker run --name firebird -e EnableWireCrypt=true -e FIREBIRD_USER=nhibernate -e FIREBIRD_PASSWORD=nhibernate -e ISC_PASSWORD=nhibernate -e FIREBIRD_DATABASE=nhibernate -p 3050:3050 -d jacobalberty/firebird:v4.0 - DB: MySQL CONNECTION_STRING: "Server=localhost;Uid=root;Password=nhibernate;Database=nhibernate;Old Guids=True;SslMode=none;" + OS: ubuntu-latest DB_INIT: | sudo service mysql stop docker run --name mysql -e MYSQL_ROOT_PASSWORD=nhibernate -e MYSQL_USER=nhibernate -e MYSQL_PASSWORD=nhibernate -e MYSQL_DATABASE=nhibernate -p 3306:3306 --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 -d mysql:5.7 mysqld --lower_case_table_names=1 --character-set-server=utf8 --collation-server=utf8_general_ci - DB: Oracle CONNECTION_STRING: "User ID=nhibernate;Password=nhibernate;Metadata Pooling=false;Self Tuning=false;Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XEPDB1)))" + OS: ubuntu-latest DB_INIT: | docker run -d -p 1521:1521 -e APP_USER=nhibernate -e APP_USER_PASSWORD=nhibernate -e ORACLE_PASSWORD=nhibernate gvenzl/oracle-xe:21-slim - - DB: SQLite - runs-on: ubuntu-latest + runs-on: ${{matrix.OS}} continue-on-error: ${{matrix.ALLOW_FAILURE == true}} env: LANG: en-US.UTF-8 #default POSIX locale doesn't support ignore case comparisons - name: ${{matrix.DB}} + name: ${{matrix.DB}} - ${{matrix.OS}} steps: - name: Set up ${{matrix.DB}} diff --git a/appveyor.yml b/appveyor.yml index 9c9962cb8af..9b2cf19943a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,6 @@ environment: - DB: Firebird4 - DB: MySQL CONNECTION_STRING: Server=127.0.0.1;Uid=root;Pwd=Password12!;Database=nhibernate;Old Guids=True;SslMode=none;CharSet=utf8; - - DB: SQLite init: # Required for having windows endlines in sources zip - git config --global core.autocrlf true From 55490c9be03b1db1b8d72610ad4cc67f060e8bf4 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 10 Jun 2024 08:46:53 +1000 Subject: [PATCH 104/128] Migrate .NET Core PostgreSQL Windows tests from AppVeyor to GitHub Actions (#3562) --- .github/workflows/NetCoreTests.yml | 18 +++++++++++++++--- appveyor.yml | 7 ------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index 61b2de7b7f0..093c1e99534 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -24,7 +24,14 @@ jobs: CONNECTION_STRING: "Host=localhost;Username=nhibernate;Password=nhibernate;Database=nhibernate;Enlist=true;" OS: ubuntu-latest DB_INIT: | - docker run -d -e POSTGRES_USER=nhibernate -e POSTGRES_PASSWORD=nhibernate -e POSTGRES_DB=nhibernate -p 5432:5432 postgres:13 + docker run -d -e POSTGRES_USER=nhibernate -e POSTGRES_PASSWORD=nhibernate -e POSTGRES_DB=nhibernate -p 5432:5432 postgres:13 + - DB: PostgreSQL + CONNECTION_STRING: "Host=localhost;Username=postgres;Password=nhibernate;Database=nhibernate;Enlist=true;" + OS: windows-latest + DB_INIT: | + choco install postgresql13 --no-progress --params '/Password:nhibernate' + Add-Content -Path 'C:\Program Files\PostgreSQL\13\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" + Start-Service 'postgresql-x64-13' - DB: Firebird CONNECTION_STRING: "DataSource=localhost;Database=nhibernate;User=SYSDBA;Password=nhibernate;charset=utf8;" OS: ubuntu-latest @@ -55,12 +62,17 @@ jobs: steps: - name: Set up ${{matrix.DB}} run: ${{matrix.DB_INIT}} - - uses: actions/checkout@v4 - - name: Setup .NET + + - name: Set up .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 8.0.x + - name: Checkout + uses: actions/checkout@v4 + with: + show-progress: false + - name: Build and Test run: | pwsh -noprofile -command "& ./build.ps1 -TaskList Set-Configuration,Test -properties @{'Database' = '${{matrix.DB}}';'ConnectionString'='${{matrix.CONNECTION_STRING}}'}" diff --git a/appveyor.yml b/appveyor.yml index 9b2cf19943a..e497e3469dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,8 +6,6 @@ environment: CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; - DB: SqlServer2008-MicrosoftDataSqlClientDriver CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; - - DB: PostgreSQL - CONNECTION_STRING: Host=localhost;Port=5432;Username=postgres;Password=Password12!;Database=nhibernate;Enlist=true; - DB: Firebird - DB: Firebird4 - DB: MySQL @@ -68,11 +66,6 @@ before_test: & 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql' -e 'CREATE DATABASE nhibernate CHARACTER SET utf8 COLLATE utf8_general_ci;' --user=root } 'Odbc' { Start-Service 'MSSQL$SQL2017' } - 'PostgreSQL' { - # Enable prepared transactions - Add-Content -Path 'C:\Program Files\PostgreSQL\10\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" - Start-Service 'postgresql-x64-10' - } 'SqlServer2008' { Start-Service 'MSSQL$SQL2017' } 'SqlServer2008-MicrosoftDataSqlClientDriver' { Start-Service 'MSSQL$SQL2017' } 'SqlServer2012' { Start-Service 'MSSQL$SQL2017' } From dd775292624246bde4253c73c9ab16e855b865bc Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Mon, 10 Jun 2024 16:40:07 +1000 Subject: [PATCH 105/128] Obsolete IValue SetTypeUsingReflection & associated methods (#3555) --- .../XmlHbmBinding/ClassCompositeIdBinder.cs | 4 +-- .../Cfg/XmlHbmBinding/ClassIdBinder.cs | 2 +- .../Cfg/XmlHbmBinding/PropertiesBinder.cs | 25 ++++++++++++++++--- src/NHibernate/Mapping/Any.cs | 6 +++++ src/NHibernate/Mapping/Collection.cs | 2 ++ src/NHibernate/Mapping/Component.cs | 6 +++++ src/NHibernate/Mapping/IValue.cs | 3 +++ src/NHibernate/Mapping/OneToMany.cs | 2 ++ src/NHibernate/Mapping/SimpleValue.cs | 21 ++++++++++++++++ src/NHibernate/Mapping/ToOne.cs | 11 ++++++++ src/NHibernate/Util/ReflectHelper.cs | 4 +++ 11 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs index 00e384c5e76..99ea0ad6b3c 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs @@ -190,7 +190,7 @@ private Property CreateProperty(ToOne value, string propertyName, System.Type pa { if (parentClass != null && value.IsSimpleValue) { - value.SetTypeUsingReflection(parentClass.AssemblyQualifiedName, propertyName, + value.SetTypeUsingReflection(parentClass, propertyName, keyManyToOneSchema.access ?? mappings.DefaultAccess); } @@ -242,7 +242,7 @@ private Property CreateProperty(SimpleValue value, string propertyName, System.T { if (parentClass != null && value.IsSimpleValue) { - value.SetTypeUsingReflection(parentClass.AssemblyQualifiedName, propertyName, + value.SetTypeUsingReflection(parentClass, propertyName, keyPropertySchema.access ?? mappings.DefaultAccess); } diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs index 89a7bef6faa..23618a368fc 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs @@ -45,7 +45,7 @@ private void CreateIdentifierProperty(HbmId idSchema, PersistentClass rootClass, if (idSchema.name != null) { string access = idSchema.access ?? mappings.DefaultAccess; - id.SetTypeUsingReflection(rootClass.MappedClass?.AssemblyQualifiedName, idSchema.name, access); + id.SetTypeUsingReflection(rootClass.MappedClass, idSchema.name, access); var property = new Property(id) { Name = idSchema.name }; diff --git a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs index 80d4500e0fc..27106d57ea2 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs @@ -386,7 +386,7 @@ private void BindCollectionProperty(ICollectionPropertiesMapping collectionMappi property.Cascade = collectionMapping.Cascade ?? mappings.DefaultCascade; } - private Property CreateProperty(IEntityPropertyMapping propertyMapping, System.Type propertyOwnerType, IValue value, IDictionary inheritedMetas) + private Property CreateProperty(IEntityPropertyMapping propertyMapping, System.Type propertyOwnerType, SimpleValue value, IDictionary inheritedMetas) { var type = propertyOwnerType?.UnwrapIfNullable(); if (string.IsNullOrEmpty(propertyMapping.Name)) @@ -394,8 +394,27 @@ private Property CreateProperty(IEntityPropertyMapping propertyMapping, System.T var propertyAccessorName = GetPropertyAccessorName(propertyMapping.Access); - if (type != null && value.IsSimpleValue) - value.SetTypeUsingReflection(type.AssemblyQualifiedName, propertyMapping.Name, propertyAccessorName); + if (type != null) + value.SetTypeUsingReflection(type, propertyMapping.Name, propertyAccessorName); + + return new Property + { + Name = propertyMapping.Name, + PropertyAccessorName = propertyAccessorName, + Value = value, + IsLazy = propertyMapping.IsLazyProperty, + LazyGroup = propertyMapping.GetLazyGroup(), + IsOptimisticLocked = propertyMapping.OptimisticLock, + MetaAttributes = GetMetas(propertyMapping, inheritedMetas) + }; + } + + private Property CreateProperty(IEntityPropertyMapping propertyMapping, System.Type propertyOwnerType, Mapping.Collection value, IDictionary inheritedMetas) + { + if (string.IsNullOrEmpty(propertyMapping.Name)) + throw new MappingException("A property mapping must define the name attribute [" + propertyOwnerType + "]"); + + var propertyAccessorName = GetPropertyAccessorName(propertyMapping.Access); return new Property { diff --git a/src/NHibernate/Mapping/Any.cs b/src/NHibernate/Mapping/Any.cs index 3be627b9d6b..8fd6d421ad9 100644 --- a/src/NHibernate/Mapping/Any.cs +++ b/src/NHibernate/Mapping/Any.cs @@ -72,10 +72,16 @@ public void ResetCachedType() _type = GetLazyType(); } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public override void SetTypeUsingReflection(string className, string propertyName, string access) { } + public override void SetTypeUsingReflection(System.Type propertyOwnerType, string propertyName, string access) + { + } + /// /// Get or set the metatype /// diff --git a/src/NHibernate/Mapping/Collection.cs b/src/NHibernate/Mapping/Collection.cs index 5ebcd301ebc..769e29e814c 100644 --- a/src/NHibernate/Mapping/Collection.cs +++ b/src/NHibernate/Mapping/Collection.cs @@ -593,6 +593,8 @@ public virtual bool IsAlternateUniqueKey get { return false; } } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public void SetTypeUsingReflection(string className, string propertyName, string access) { } diff --git a/src/NHibernate/Mapping/Component.cs b/src/NHibernate/Mapping/Component.cs index c9f1409cf6f..99a395e6686 100644 --- a/src/NHibernate/Mapping/Component.cs +++ b/src/NHibernate/Mapping/Component.cs @@ -105,10 +105,16 @@ public Component(Component component) owner = component.Owner; } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public override void SetTypeUsingReflection(string className, string propertyName, string accesorName) { } + public override void SetTypeUsingReflection(System.Type propertyOwnerType, string propertyName, string accesorName) + { + } + /// public bool IsEmbedded { diff --git a/src/NHibernate/Mapping/IValue.cs b/src/NHibernate/Mapping/IValue.cs index 1941b3dc563..9bfb3522b01 100644 --- a/src/NHibernate/Mapping/IValue.cs +++ b/src/NHibernate/Mapping/IValue.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NHibernate.Engine; using NHibernate.Type; @@ -78,6 +79,8 @@ public interface IValue FetchMode FetchMode { get; } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] void SetTypeUsingReflection(string className, string propertyName, string accesorName); object Accept(IValueVisitor visitor); diff --git a/src/NHibernate/Mapping/OneToMany.cs b/src/NHibernate/Mapping/OneToMany.cs index b349e4df98b..35a82f60a43 100644 --- a/src/NHibernate/Mapping/OneToMany.cs +++ b/src/NHibernate/Mapping/OneToMany.cs @@ -125,6 +125,8 @@ public bool IsAlternateUniqueKey get { return false; } } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public void SetTypeUsingReflection(string className, string propertyName, string accesorName) { } diff --git a/src/NHibernate/Mapping/SimpleValue.cs b/src/NHibernate/Mapping/SimpleValue.cs index 29de8c8927b..7714f120fd4 100644 --- a/src/NHibernate/Mapping/SimpleValue.cs +++ b/src/NHibernate/Mapping/SimpleValue.cs @@ -341,6 +341,8 @@ public bool IsAlternateUniqueKey set { isAlternateUniqueKey = value; } } + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public virtual void SetTypeUsingReflection(string className, string propertyName, string accesorName) { if (typeName == null) @@ -359,6 +361,25 @@ public virtual void SetTypeUsingReflection(string className, string propertyName } } } + + public virtual void SetTypeUsingReflection(System.Type propertyOwnerType, string propertyName, string accessorName) + { + if (typeName == null) + { + if (propertyOwnerType == null) + { + throw new MappingException("you must specify types for a dynamic entity: " + propertyName); + } + try + { + typeName = ReflectHelper.ReflectedPropertyClass(propertyOwnerType, propertyName, accessorName).AssemblyQualifiedName; + } + catch (HibernateException he) + { + throw new MappingException("Problem trying to set property type by reflection", he); + } + } + } public virtual object Accept(IValueVisitor visitor) { diff --git a/src/NHibernate/Mapping/ToOne.cs b/src/NHibernate/Mapping/ToOne.cs index c959216d4b4..a56245f32da 100644 --- a/src/NHibernate/Mapping/ToOne.cs +++ b/src/NHibernate/Mapping/ToOne.cs @@ -54,6 +54,8 @@ public bool IsLazy /// public abstract override void CreateForeignKey(); + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public override void SetTypeUsingReflection(string className, string propertyName, string accesorName) { if (referencedEntityName == null) @@ -63,6 +65,15 @@ public override void SetTypeUsingReflection(string className, string propertyNam } } + public override void SetTypeUsingReflection(System.Type propertyOwnerType, string propertyName, string accessorName) + { + if (referencedEntityName == null) + { + System.Type refType = ReflectHelper.ReflectedPropertyClass(propertyOwnerType, propertyName, accessorName); + referencedEntityName = refType.FullName; + } + } + public override bool IsValid(Engine.IMapping mapping) { if (referencedEntityName == null) diff --git a/src/NHibernate/Util/ReflectHelper.cs b/src/NHibernate/Util/ReflectHelper.cs index e665a68a9c3..b693956de95 100644 --- a/src/NHibernate/Util/ReflectHelper.cs +++ b/src/NHibernate/Util/ReflectHelper.cs @@ -391,6 +391,8 @@ public static IGetter GetGetter(System.Type theClass, string propertyName, strin /// /// The NHibernate for the named property. /// + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public static IType ReflectedPropertyType(System.Type theClass, string name, string access) { System.Type propertyClass = ReflectedPropertyClass(theClass, name, access); @@ -419,6 +421,8 @@ public static System.Type ReflectedPropertyClass(System.Type theClass, string na /// The name of the property/field to find in the class. /// The name of the property accessor for the property. /// The for the named property. + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public static System.Type ReflectedPropertyClass(string className, string name, string accessorName) { try From 7ed5bc82fc446ddaeed14c526fcde7bc5a65b28d Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 12 Jun 2024 09:17:35 +1000 Subject: [PATCH 106/128] Fix configuration order in tests (#3557) --- .../NativeSQLBulkOperationsWithCache.cs | 6 +++--- .../Circle/MultiPathCircleCascadeTest.cs | 1 - .../ConnectionTest/AggressiveReleaseTest.cs | 11 +++++----- .../Async/ConnectionTest/BatcherFixture.cs | 7 +++---- .../ReadonlyTests/QueryOverCacheableTests.cs | 1 - .../FetchLazyPropertiesFixture.cs | 1 - .../Async/Futures/FallbackFixture.cs | 3 +-- .../Identity/IdentityGeneratedKeysTest.cs | 1 - .../Async/Immutable/ImmutableTest.cs | 1 - .../Async/LazyGroup/LazyGroupFixture.cs | 1 - .../Async/Linq/ByMethod/GroupByHavingTests.cs | 1 - .../Async/Linq/ByMethod/OrderByTests.cs | 1 - .../Async/Linq/PreEvaluationTests.cs | 2 -- .../Async/Linq/QueryCacheableTests.cs | 7 +++---- .../Async/Linq/QueryFlushModeTests.cs | 1 - .../Async/Linq/QueryTimeoutTests.cs | 1 - .../DatabaseStrategyNoDbSpecificFixture.cs | 1 - .../Dates/DateTimeOffsetQueryFixture.cs | 1 - .../Fixture.cs | 1 - .../FileStreamSql2008/Fixture.cs | 4 ++-- .../Async/NHSpecificTest/GH1486/Fixture.cs | 1 - .../Async/NHSpecificTest/GH1496/Fixture.cs | 1 - .../Async/NHSpecificTest/GH1547/Fixture.cs | 2 -- .../Async/NHSpecificTest/GH1730/Fixture.cs | 2 +- .../CircularReferenceFetchDepth0Fixture.cs | 1 - .../CircularReferenceFetchDepthFixture.cs | 1 - .../NHSpecificTest/GH3113/FixtureByCode.cs | 2 -- .../NHSpecificTest/GH3176/FixtureByCode.cs | 1 - .../NHSpecificTest/GH3198/FixtureByCode.cs | 1 - .../NHSpecificTest/GH3215/FixtureByCode.cs | 1 - .../Async/NHSpecificTest/Logs/LogsFixture.cs | 1 - .../Async/NHSpecificTest/NH1001/Fixture.cs | 2 +- .../Async/NHSpecificTest/NH1101/Fixture.cs | 3 +-- .../Async/NHSpecificTest/NH1144/Fixture.cs | 5 +---- .../Async/NHSpecificTest/NH1452/Fixture.cs | 1 - .../SnapshotIsolationUpdateConflictTest.cs | 1 - .../NativeSqlCollectionLoaderFixture.cs | 1 - .../TestCollectionInitializingDuringFlush.cs | 1 - .../Async/NHSpecificTest/NH1989/Fixture.cs | 1 - .../Async/NHSpecificTest/NH2043/Fixture.cs | 1 - .../Async/NHSpecificTest/NH2055/Fixture.cs | 6 ------ .../Async/NHSpecificTest/NH2302/Fixture.cs | 21 ++++++++++--------- .../Async/NHSpecificTest/NH2318/Fixture.cs | 1 - .../NHSpecificTest/NH2439/NH2439Fixture.cs | 1 - .../Async/NHSpecificTest/NH2554/Fixture.cs | 1 - .../NHSpecificTest/NH2660And2661/Test.cs | 1 - .../Async/NHSpecificTest/NH2869/Fixture.cs | 3 +-- .../Async/NHSpecificTest/NH2898/Fixture.cs | 3 +-- .../Async/NHSpecificTest/NH3058/SampleTest.cs | 2 -- .../NHSpecificTest/NH3142/ChildrenTest.cs | 1 - .../Async/NHSpecificTest/NH3202/Fixture.cs | 6 +++--- .../Async/NHSpecificTest/NH3426/Fixture.cs | 2 -- .../NH3530/BatchFetchStyleFixture.cs | 1 - .../Async/NHSpecificTest/NH3848/Fixture.cs | 1 - .../NH3912/ReusableBatcherFixture.cs | 1 - .../NH4077/PostInsertFixture.cs | 1 - .../NH4077/PostUpdateFixture.cs | 1 - .../Immutable/ImmutableNaturalIdFixture.cs | 6 +++--- .../Mutable/MutableNaturalIdFixture.cs | 6 +++--- .../Async/Ondelete/JoinedSubclassFixture.cs | 4 ++-- .../Async/Ondelete/OnDeleteFixture.cs | 2 +- .../Async/Ondelete/ParentChildFixture.cs | 4 ++-- .../Async/Pagination/CustomDialectFixture.cs | 6 +++--- .../Async/Pagination/PaginationFixture.cs | 2 +- .../Async/QueryTest/MultiCriteriaFixture.cs | 2 -- .../SecondLevelCacheTest.cs | 3 +-- .../IdentityInsertWithStoredProcsTest.cs | 1 - .../Stateless/StatelessSessionQueryFixture.cs | 3 +-- .../SubselectFetchFixture.cs | 4 ++-- .../TypesTest/AbstractDateTimeTypeFixture.cs | 2 -- .../TypesTest/DateTimeOffsetTypeFixture.cs | 2 -- .../Async/TypesTest/DecimalTypeFixture.cs | 2 -- .../Unionsubclass/DatabaseKeywordsFixture.cs | 2 -- .../NativeSQLBulkOperationsWithCache.cs | 6 +++--- .../CacheTest/SyncOnlyCacheFixture.cs | 5 ++--- .../Circle/MultiPathCircleCascadeTest.cs | 1 - .../ConnectionTest/AggressiveReleaseTest.cs | 11 +++++----- .../AsyncLocalSessionContextFixture.cs | 3 +-- .../ConnectionTest/BatcherFixture.cs | 7 +++---- .../CustomCurrentSessionTest.cs | 3 +-- .../MapBasedSessionContextFixture.cs | 3 +-- .../ThreadLocalCurrentSessionTest.cs | 5 ++--- .../ThreadStaticSessionContextFixture.cs | 3 +-- .../ReadonlyTests/QueryOverCacheableTests.cs | 1 - .../FetchLazyPropertiesFixture.cs | 1 - .../Futures/FallbackFixture.cs | 3 +-- .../Identity/IdentityGeneratedKeysTest.cs | 1 - .../IdTest/UseIdentifierRollbackTest.cs | 3 +-- .../Immutable/ImmutableTest.cs | 1 - .../LazyGroup/LazyGroupFixture.cs | 1 - .../Linq/ByMethod/GroupByHavingTests.cs | 1 - .../Linq/ByMethod/OrderByTests.cs | 1 - .../Linq/PreEvaluationTests.cs | 2 -- .../Linq/QueryCacheableTests.cs | 7 +++---- .../Linq/QueryFlushModeTests.cs | 1 - src/NHibernate.Test/Linq/QueryTimeoutTests.cs | 1 - .../DatabaseStrategyNoDbSpecificFixture.cs | 1 - .../NHSpecificTest/BugTestCase.cs | 4 ++-- .../Dates/DateTimeOffsetQueryFixture.cs | 1 - .../Fixture.cs | 1 - .../FileStreamSql2008/Fixture.cs | 4 ++-- .../NHSpecificTest/GH1486/Fixture.cs | 1 - .../NHSpecificTest/GH1496/Fixture.cs | 1 - .../NHSpecificTest/GH1547/Fixture.cs | 2 -- .../NHSpecificTest/GH1730/Fixture.cs | 2 +- .../CircularReferenceFetchDepth0Fixture.cs | 1 - .../CircularReferenceFetchDepthFixture.cs | 1 - .../NHSpecificTest/GH3113/FixtureByCode.cs | 2 -- .../NHSpecificTest/GH3176/FixtureByCode.cs | 1 - .../NHSpecificTest/GH3198/FixtureByCode.cs | 1 - .../NHSpecificTest/GH3215/FixtureByCode.cs | 1 - .../NHSpecificTest/Logs/LogsFixture.cs | 1 - .../NHSpecificTest/NH1001/Fixture.cs | 2 +- .../NHSpecificTest/NH1101/Fixture.cs | 3 +-- .../NHSpecificTest/NH1144/Fixture.cs | 5 +---- .../NHSpecificTest/NH1230/Fixture.cs | 4 ++-- .../NHSpecificTest/NH1452/Fixture.cs | 1 - .../SnapshotIsolationUpdateConflictTest.cs | 1 - .../NativeSqlCollectionLoaderFixture.cs | 1 - .../NHSpecificTest/NH1849/Fixture.cs | 4 +--- .../TestCollectionInitializingDuringFlush.cs | 1 - .../NHSpecificTest/NH1989/Fixture.cs | 1 - .../NHSpecificTest/NH2043/Fixture.cs | 1 - .../NHSpecificTest/NH2055/Fixture.cs | 6 ------ .../NHSpecificTest/NH2302/Fixture.cs | 19 +++++++++-------- .../NHSpecificTest/NH2318/Fixture.cs | 1 - .../NHSpecificTest/NH2439/NH2439Fixture.cs | 1 - .../NHSpecificTest/NH2554/Fixture.cs | 1 - .../NH2583/AbstractMassTestingFixture.cs | 1 - .../NHSpecificTest/NH2660And2661/Test.cs | 1 - .../NHSpecificTest/NH2700/Fixture.cs | 2 +- .../NHSpecificTest/NH2869/Fixture.cs | 3 +-- .../NHSpecificTest/NH2898/Fixture.cs | 3 +-- .../NHSpecificTest/NH3058/SampleTest.cs | 2 -- .../NHSpecificTest/NH3142/ChildrenTest.cs | 1 - .../NHSpecificTest/NH3202/Fixture.cs | 6 +++--- .../NHSpecificTest/NH3426/Fixture.cs | 2 -- .../NHSpecificTest/NH3489/Fixture.cs | 1 - .../NH3530/BatchFetchStyleFixture.cs | 1 - .../NHSpecificTest/NH3848/Fixture.cs | 1 - .../NH3912/ReusableBatcherFixture.cs | 1 - .../NH4077/PostInsertFixture.cs | 1 - .../NH4077/PostUpdateFixture.cs | 1 - .../Immutable/ImmutableNaturalIdFixture.cs | 6 +++--- .../Mutable/MutableNaturalIdFixture.cs | 6 +++--- .../Ondelete/JoinedSubclassFixture.cs | 4 ++-- .../Ondelete/OnDeleteFixture.cs | 2 +- .../Ondelete/ParentChildFixture.cs | 4 ++-- .../Pagination/CustomDialectFixture.cs | 6 +++--- .../Pagination/PaginationFixture.cs | 2 +- .../QueryTest/MultiCriteriaFixture.cs | 2 -- .../ReadOnly/AbstractReadOnlyTest.cs | 1 - .../SecondLevelCacheTest.cs | 3 +-- .../IdentityInsertWithStoredProcsTest.cs | 1 - .../Stateless/StatelessSessionQueryFixture.cs | 3 +-- .../SubselectFetchFixture.cs | 4 ++-- src/NHibernate.Test/TestCase.cs | 4 ++-- .../TypesTest/AbstractDateTimeTypeFixture.cs | 2 -- .../TypesTest/ChangeDefaultTypeFixture.cs | 1 - .../ChangeDefaultTypeWithLengthFixture.cs | 1 - .../ChangeDefaultTypeWithPrecisionFixture.cs | 1 - .../TypesTest/DateTimeOffsetTypeFixture.cs | 2 -- .../TypesTest/DecimalTypeFixture.cs | 2 -- .../Unionsubclass/DatabaseKeywordsFixture.cs | 2 -- 164 files changed, 128 insertions(+), 293 deletions(-) diff --git a/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs index 4e75d4e63b6..9d451fa6da6 100644 --- a/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs +++ b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs @@ -33,9 +33,9 @@ public class NativeSQLBulkOperationsWithCacheAsync : TestCase protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); } [Test] diff --git a/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs b/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs index 7d7a4a491d1..70134f8b0c8 100644 --- a/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs +++ b/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs @@ -54,7 +54,6 @@ protected override string[] Mappings protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs b/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs index a0171cba778..55db59272b1 100644 --- a/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs +++ b/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs @@ -24,13 +24,12 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class AggressiveReleaseTestAsync : ConnectionManagementTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.ReleaseConnections, "after_transaction"); - //cfg.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); - //cfg.SetProperty(Environment.GenerateStatistics, "true"); - cfg.SetProperty(Environment.BatchSize, "0"); + configuration.SetProperty(Environment.ReleaseConnections, "after_transaction"); + //configuration.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); + //configuration.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.BatchSize, "0"); } protected override ISession GetSessionUnderTest() diff --git a/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs b/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs index 1145ecfe31c..18b0dc994b7 100644 --- a/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs +++ b/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs @@ -22,10 +22,9 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class BatcherFixtureAsync : ConnectionManagementTestCase { - protected override void Configure(Configuration config) + protected override void Configure(Configuration configuration) { - base.Configure(config); - config.SetProperty(Environment.BatchSize, "10"); + configuration.SetProperty(Environment.BatchSize, "10"); } protected override ISession GetSessionUnderTest() @@ -53,4 +52,4 @@ public async Task CanCloseCommandsAndUseBatcherAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs b/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs index b3f6e51b233..405750c3993 100644 --- a/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs +++ b/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs @@ -27,7 +27,6 @@ protected override void Configure(Configuration config) { config.SetProperty(Environment.UseQueryCache, "true"); config.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(config); } [Test] diff --git a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs index 18df844bd71..aeb9eb71a9d 100644 --- a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -44,7 +44,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; } diff --git a/src/NHibernate.Test/Async/Futures/FallbackFixture.cs b/src/NHibernate.Test/Async/Futures/FallbackFixture.cs index 52f091d60b9..68e2c8603da 100644 --- a/src/NHibernate.Test/Async/Futures/FallbackFixture.cs +++ b/src/NHibernate.Test/Async/Futures/FallbackFixture.cs @@ -43,8 +43,7 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + using (var cp = ConnectionProviderFactory.NewConnectionProvider(configuration.Properties)) { if (cp.Driver is SqlClientDriver) { diff --git a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 9756052f341..ea6dada5ab7 100644 --- a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -36,7 +36,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs b/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs index b75063bd44e..dec48eda73f 100644 --- a/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs +++ b/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs @@ -29,7 +29,6 @@ public class ImmutableTestAsync : TestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs b/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs index 009ba2ba2d7..5f5a7f2fc15 100644 --- a/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs +++ b/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs @@ -30,7 +30,6 @@ public class LazyGroupFixtureAsync : TestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs index c7b618793e4..5a332bb9865 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs @@ -22,7 +22,6 @@ public class GroupByHavingTestsAsync : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs index 99a234a483a..b40a07f6159 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs @@ -22,7 +22,6 @@ public class OrderByTestsAsync : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs index 1f55f7b6cb8..4c16951e8a0 100644 --- a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs @@ -36,8 +36,6 @@ public PreEvaluationTestsAsync(bool legacy, bool fallback) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.FormatSql, "false"); configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, LegacyPreEvaluation.ToString()); configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString()); diff --git a/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs b/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs index 3bc5fb1bedc..f8418a1c113 100644 --- a/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs @@ -21,11 +21,10 @@ namespace NHibernate.Test.Linq [TestFixture] public class QueryCacheableTestsAsync : LinqTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(cfg); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs b/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs index 54216c4642e..66f65c7bfab 100644 --- a/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs @@ -22,7 +22,6 @@ public class QueryFlushModeTestsAsync : LinqTestCase protected override void Configure(Configuration configuration) { configuration.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs b/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs index d7ae3c3917e..9bf5eaf04bf 100644 --- a/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs @@ -32,7 +32,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchStrategy, typeof(TimeoutCatchingNonBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs b/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs index 81f6b14b5cd..1734c5daaab 100644 --- a/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs +++ b/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs @@ -44,7 +44,6 @@ protected override void Configure(Configuration configuration) x.MultiTenancyConnectionProvider(); }); configuration.Properties[Cfg.Environment.GenerateStatistics] = "true"; - base.Configure(configuration); } private static void ValidateSqlServerConnectionAppName(ISession s, string tenantId) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs index 9485aff8ae1..f28d3983bc9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs @@ -45,7 +45,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs index ddd35ad0018..b49f3a1dd85 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs @@ -32,7 +32,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.LinqToHqlGeneratorsRegistry(); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs index 99930c1bdb5..bb1db7853e2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs @@ -39,10 +39,10 @@ protected override bool AppliesTo(Dialect.Dialect dialect) return dialect is MsSql2008Dialect; } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { //Points to the database created with FileStream Filegroup. - cfg.Properties["connection.connection_string"] = + configuration.Properties["connection.connection_string"] = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=FileStreamDB;Integrated Security=True;Pooling=False"; #region CREATE DATABASE example diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs index 69b6e469b6a..89a0d71729c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs @@ -24,7 +24,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(_interceptor); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs index 117d2290eb4..e3e0e0572ee 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs @@ -28,7 +28,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.AppendListeners(ListenerType.PostUpdate, new[] { _auditEventListener }); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs index a9b6818c04f..fc0c9255d40 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs @@ -34,8 +34,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); DriverForSubstitutedCommand.DriverClass = driverClass; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs index 3b9b66878df..dd7a05ab15d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs @@ -19,7 +19,7 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void OnTearDown() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs index 89586bfd9fb..1a71937cd19 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs @@ -26,7 +26,6 @@ public CircularReferenceFetchDepth0FixtureAsync() : base(0) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", "0"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs index 5687c0cac44..6365722a0cc 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs @@ -28,7 +28,6 @@ public CircularReferenceFetchDepthFixtureAsync(int depth) : base(depth) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", _depth.ToString()); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs index 13702eb1171..2a140d31b9c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs @@ -44,8 +44,6 @@ protected override void Configure(Configuration configuration) var dialect = NHibernate.Dialect.Dialect.GetDialect(configuration.Properties); if (dialect is Oracle8iDialect) configuration.SetProperty(Environment.Dialect, typeof(Oracle9iDialect).FullName); - - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs index 3694b370c39..c95a70f4286 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs @@ -60,7 +60,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs index a95cbcebfca..76b11bac687 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs @@ -32,7 +32,6 @@ protected override void Configure(Configuration configuration) { new TestEventListener() }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs index 8d5772bf3d5..89ceb740018 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs @@ -45,7 +45,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs index b528d151b8f..d41df353d6f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs @@ -46,7 +46,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs index 2fe3e8a8894..ec66ea4ef4c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs @@ -21,7 +21,7 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } private int employeeId; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs index 83fba185e25..56fecfc34d6 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs @@ -22,8 +22,7 @@ public class FixtureAsync : BugTestCase protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs index b5758daa27f..336968543bc 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs @@ -21,12 +21,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1144 [TestFixture] public class FixtureAsync : BugTestCase { - private Configuration configuration; - protected override void Configure(Configuration configuration) { - this.configuration = configuration; - this.configuration.Properties[Environment.BatchSize] = "10"; + configuration.Properties[Environment.BatchSize] = "10"; } [Test] diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs index c9fad064581..3183f6ac993 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs @@ -20,7 +20,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs index c1643f9a028..ae3d6fa4b33 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs @@ -205,7 +205,6 @@ protected override void OnTearDown() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.SqlExceptionConverter, typeof (SQLUpdateConflictToStaleStateExceptionConverter).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index 4687e62be28..34dec017aa4 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -24,7 +24,6 @@ public class NativeSqlCollectionLoaderFixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.UseQueryCache, WithQueryCache.ToString()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs index 3f90814e610..e14abf73457 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs @@ -30,7 +30,6 @@ protected override void Configure(Configuration configuration) { listener }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs index 48f8bf99ba5..92b05b1c650 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs @@ -31,7 +31,6 @@ protected override bool AppliesTo(ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs index 8d061a5b768..4d475edc44e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs @@ -30,7 +30,6 @@ public override string GetEntityName(object entity) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(new Namer()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs index 37e4fe39bc0..f4462e5589d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs @@ -27,12 +27,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) return (dialect is Dialect.MsSql2000Dialect); } - protected override void Configure(Configuration configuration) - { - base.Configure(configuration); - cfg = configuration; - } - [Test] public async Task CanCreateAndDropSchemaAsync() { diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs index 49fb2b1ccd9..03ff2ce2f05 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs @@ -9,6 +9,7 @@ using System.Data; +using NHibernate.Cfg; using NHibernate.Dialect; using NHibernate.Driver; using NHibernate.Mapping; @@ -17,30 +18,30 @@ namespace NHibernate.Test.NHSpecificTest.NH2302 { - using System.Threading.Tasks; - [TestFixture] - public class FixtureAsync : BugTestCase - { - protected override void Configure(Cfg.Configuration configuration) + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void AddMappings(Configuration configuration) { + base.AddMappings(configuration); + foreach (var cls in configuration.ClassMappings) { foreach (var prop in cls.PropertyIterator) { foreach (var col in prop.ColumnIterator) { - if (col is Column) + if (col is Column column && column.SqlType == "nvarchar(max)") { - var column = col as Column; - if (column.SqlType == "nvarchar(max)") - column.SqlType = Dialect.GetLongestTypeName(DbType.String); + column.SqlType = Dialect.GetLongestTypeName(DbType.String); } } } } } - protected override void OnTearDown() + protected override void OnTearDown() { CleanUp(); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs index 59a1d3d2cea..9a53bc89d6e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs @@ -25,7 +25,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty("linqtohql.generatorsregistry", "NHibernate.Test.NHSpecificTest.NH2318.ExtendedLinqtoHqlGeneratorsRegistry, NHibernate.Test"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs index 21019688492..479a108ca91 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs @@ -22,7 +22,6 @@ public class NH2439FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs index 89b6b3be7bd..b5cc0370e13 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs @@ -25,7 +25,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) protected override void Configure(NHibernate.Cfg.Configuration configuration) { configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "keywords"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs index d13589002f3..4eab3ee0a50 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs @@ -49,7 +49,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { // to be sure we are using the new drive - base.Configure(configuration); configuration.DataBaseIntegration(x=> x.Driver()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs index c3b2d51436a..9bfe3713a02 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs @@ -23,7 +23,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { configuration.LinqToHqlGeneratorsRegistry(); - base.Configure(configuration); } protected override void OnSetUp() @@ -66,4 +65,4 @@ public async Task CustomExtensionWithConstantArgumentShouldBeIncludedInHqlProjec } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs index ffa0243f311..618064daaeb 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs @@ -22,7 +22,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(BinaryFormatterCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -114,4 +113,4 @@ public async Task SecondLevelCacheWithHqlQueriesAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs index 0a66df764a6..07bbfd31c7b 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs @@ -19,8 +19,6 @@ public class SampleTestAsync : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - configuration.Properties.Add("current_session_context_class", "thread_static"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs index 386428efd12..c6b733fc8a5 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs @@ -32,7 +32,6 @@ public ChildrenTestAsync(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs index 0cbd29f617b..d0fcc95b676 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs @@ -27,11 +27,11 @@ protected override void Configure(Configuration configuration) if (!(Dialect is MsSql2008Dialect)) Assert.Ignore("Test is for MS SQL Server dialect only (custom dialect)."); - if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)))) + if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)))) Assert.Ignore("Test is for MS SQL Server driver only (custom driver is used)."); - cfg.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); } private OffsetStartsAtOneTestDialect OffsetStartsAtOneTestDialect diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs index afd515c3f44..6feae4bb697 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs @@ -50,8 +50,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is SQLiteDialect) { var connStr = configuration.Properties[Environment.ConnectionString]; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs index be33442597b..af6afac0188 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs @@ -36,7 +36,6 @@ public BatchFetchStyleFixtureAsync(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs index 242e8fc5fd2..4acd25ea77d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs @@ -88,7 +88,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Cache(c => { c.UseQueryCache = true; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs index d5bbb05a2be..f3a64b9ab29 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs @@ -47,7 +47,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchStrategy, typeof(OracleDataClientBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs index b1cf11738ad..4581284ba4d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs @@ -73,7 +73,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostInsertEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs index f2d2f9fc2ff..4ae7189d1c9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs @@ -67,7 +67,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostUpdateEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs b/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs index d3fccab6b8a..c8b15b5379f 100644 --- a/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs b/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs index 578f9cb2d9d..7d0e2729bb6 100644 --- a/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs @@ -32,9 +32,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs b/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs index db43fd24e57..92bc30bfc3b 100644 --- a/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.EFGJoinedSubclass.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs b/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs index 415190895fa..d7941caf38d 100644 --- a/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs @@ -30,7 +30,7 @@ protected override string[] Mappings protected override void Configure(Cfg.Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs b/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs index 9874cb0ce94..8bf34fa99ab 100644 --- a/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.ParentChild.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs index c33de557a91..cf46df6bd03 100644 --- a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs @@ -41,12 +41,12 @@ protected override void Configure(Configuration configuration) // Configure is called before Applies, must check here. if (!(Dialect is MsSql2005Dialect)) Assert.Ignore("Test is for SQL dialect only"); - var driverClass = ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)); + var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)); if (!typeof(SqlClientDriver).IsAssignableFrom(driverClass)) Assert.Ignore("Test is compatible only with Sql Server Client driver connection strings"); - cfg.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); } private CustomMsSqlDialect CustomDialect diff --git a/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs b/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs index 7921e7549da..fb9f4fc180c 100644 --- a/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs +++ b/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs @@ -34,7 +34,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.DefaultBatchFetchSize, "20"); + configuration.SetProperty(Environment.DefaultBatchFetchSize, "20"); } [Test] diff --git a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs index 848ead9056e..e63d4372109 100644 --- a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs @@ -41,8 +41,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs b/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs index 344109b3954..1c963ebbeb8 100644 --- a/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs +++ b/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs @@ -35,7 +35,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -273,4 +272,4 @@ public async Task SecondLevelCacheWithHqlQueriesAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs b/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs index ac20468608c..107bfe44729 100644 --- a/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs @@ -24,7 +24,6 @@ protected override string MappingsAssembly protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs b/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs index dc3c2189754..5f520fd4590 100644 --- a/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs +++ b/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs @@ -31,8 +31,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Environment.MaxFetchDepth, 1.ToString()); + configuration.SetProperty(Environment.MaxFetchDepth, 1.ToString()); } protected override bool AppliesTo(Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs index 2aa47a1b95d..87848c08536 100644 --- a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs @@ -20,9 +20,9 @@ namespace NHibernate.Test.SubselectFetchTest [TestFixture] public class SubselectFetchFixtureAsync : TestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs index 4307080f4cf..b3cbca7e1e3 100644 --- a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs @@ -40,8 +40,6 @@ public abstract class AbstractDateTimeTypeFixtureAsync : TypeFixtureBase protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; diff --git a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs index 1c604513d85..6ad79ddbd92 100644 --- a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs @@ -42,8 +42,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) => protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; diff --git a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs index 1917cbd0b4b..2b5f1ef3c38 100644 --- a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs @@ -33,8 +33,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is FirebirdDialect) { configuration.SetProperty(Environment.QueryDefaultCastPrecision, "18"); diff --git a/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs b/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs index d8a2c5ea89c..303012d48b0 100644 --- a/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs +++ b/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs @@ -30,8 +30,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs index f6b7887b665..fda256b835a 100644 --- a/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs +++ b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs @@ -22,9 +22,9 @@ public class NativeSQLBulkOperationsWithCache : TestCase protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); } [Test] diff --git a/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs b/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs index 267b74d015a..3adccdf0f53 100644 --- a/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs +++ b/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs @@ -11,10 +11,9 @@ namespace NHibernate.Test.CacheTest [TestFixture] public class SyncOnlyCacheFixture : CacheFixture { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CacheReadWriteLockFactory, "sync"); + configuration.SetProperty(Environment.CacheReadWriteLockFactory, "sync"); } [Test] diff --git a/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs b/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs index 06d190ba08c..1773d6448f5 100644 --- a/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs +++ b/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs @@ -42,7 +42,6 @@ protected override string[] Mappings protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs index bc0df5c5a65..0111d194ae6 100644 --- a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs +++ b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs @@ -12,13 +12,12 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class AggressiveReleaseTest : ConnectionManagementTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.ReleaseConnections, "after_transaction"); - //cfg.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); - //cfg.SetProperty(Environment.GenerateStatistics, "true"); - cfg.SetProperty(Environment.BatchSize, "0"); + configuration.SetProperty(Environment.ReleaseConnections, "after_transaction"); + //configuration.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); + //configuration.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.BatchSize, "0"); } protected override ISession GetSessionUnderTest() diff --git a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs index f39f344ce62..d11c69f711c 100644 --- a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs @@ -17,8 +17,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, "async_local"); + configuration.SetProperty(Environment.CurrentSessionContextClass, "async_local"); } [Test] diff --git a/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs b/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs index d96a7c205d5..b887d83a440 100644 --- a/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs @@ -11,10 +11,9 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class BatcherFixture : ConnectionManagementTestCase { - protected override void Configure(Configuration config) + protected override void Configure(Configuration configuration) { - base.Configure(config); - config.SetProperty(Environment.BatchSize, "10"); + configuration.SetProperty(Environment.BatchSize, "10"); } protected override ISession GetSessionUnderTest() @@ -42,4 +41,4 @@ public void CanCloseCommandsAndUseBatcher() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs b/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs index b22dcd6cd25..73a0bdce75b 100644 --- a/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs +++ b/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs @@ -17,8 +17,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof(CustomContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof(CustomContext).AssemblyQualifiedName); } protected override void Release(ISession session) diff --git a/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs index bd4fa61e38a..1893a2be2e9 100644 --- a/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs @@ -19,8 +19,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof(TestableMapBasedSessionContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof(TestableMapBasedSessionContext).AssemblyQualifiedName); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs b/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs index afd05fab790..59fafad6390 100644 --- a/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs +++ b/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs @@ -17,9 +17,8 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof (TestableThreadLocalContext).AssemblyQualifiedName); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof (TestableThreadLocalContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void Release(ISession session) diff --git a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs index c2cad0ea0ef..7ec9bef8e68 100644 --- a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs @@ -19,8 +19,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, "thread_static"); + configuration.SetProperty(Environment.CurrentSessionContextClass, "thread_static"); } [Test] diff --git a/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs b/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs index 749a5184354..7c4e17de210 100644 --- a/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs +++ b/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs @@ -16,7 +16,6 @@ protected override void Configure(Configuration config) { config.SetProperty(Environment.UseQueryCache, "true"); config.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(config); } [Test] diff --git a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs index f05c462e5c8..1fd3b8ed063 100644 --- a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -33,7 +33,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; } diff --git a/src/NHibernate.Test/Futures/FallbackFixture.cs b/src/NHibernate.Test/Futures/FallbackFixture.cs index b7fa34759a7..d9042acc6ce 100644 --- a/src/NHibernate.Test/Futures/FallbackFixture.cs +++ b/src/NHibernate.Test/Futures/FallbackFixture.cs @@ -35,8 +35,7 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + using (var cp = ConnectionProviderFactory.NewConnectionProvider(configuration.Properties)) { if (cp.Driver is SqlClientDriver) { diff --git a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 7eb3f8eb7d6..d197c037825 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -25,7 +25,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs b/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs index 77ade682908..5f623d9652c 100644 --- a/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs +++ b/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs @@ -20,8 +20,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseIdentifierRollBack, "true"); - base.Configure(configuration); + configuration.SetProperty(Environment.UseIdentifierRollBack, "true"); } public void SimpleRollback() diff --git a/src/NHibernate.Test/Immutable/ImmutableTest.cs b/src/NHibernate.Test/Immutable/ImmutableTest.cs index 214252925b1..18f476411d9 100644 --- a/src/NHibernate.Test/Immutable/ImmutableTest.cs +++ b/src/NHibernate.Test/Immutable/ImmutableTest.cs @@ -17,7 +17,6 @@ public class ImmutableTest : TestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs b/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs index 7f52de482e4..a0ff97f8a70 100644 --- a/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs +++ b/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs @@ -19,7 +19,6 @@ public class LazyGroupFixture : TestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs b/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs index 7e6258bfcaf..7b83694fcca 100644 --- a/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs @@ -10,7 +10,6 @@ public class GroupByHavingTests : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs b/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs index 01e21c1d1cd..a45b8d18c9f 100644 --- a/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs @@ -10,7 +10,6 @@ public class OrderByTests : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Linq/PreEvaluationTests.cs index 9284938842d..f0698f15906 100644 --- a/src/NHibernate.Test/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Linq/PreEvaluationTests.cs @@ -24,8 +24,6 @@ public PreEvaluationTests(bool legacy, bool fallback) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.FormatSql, "false"); configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, LegacyPreEvaluation.ToString()); configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString()); diff --git a/src/NHibernate.Test/Linq/QueryCacheableTests.cs b/src/NHibernate.Test/Linq/QueryCacheableTests.cs index de4529091bf..779a4514f3a 100644 --- a/src/NHibernate.Test/Linq/QueryCacheableTests.cs +++ b/src/NHibernate.Test/Linq/QueryCacheableTests.cs @@ -10,11 +10,10 @@ namespace NHibernate.Test.Linq [TestFixture] public class QueryCacheableTests : LinqTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(cfg); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Linq/QueryFlushModeTests.cs b/src/NHibernate.Test/Linq/QueryFlushModeTests.cs index 796a76bf0e0..9eb896ab4e3 100644 --- a/src/NHibernate.Test/Linq/QueryFlushModeTests.cs +++ b/src/NHibernate.Test/Linq/QueryFlushModeTests.cs @@ -11,7 +11,6 @@ public class QueryFlushModeTests : LinqTestCase protected override void Configure(Configuration configuration) { configuration.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/Linq/QueryTimeoutTests.cs b/src/NHibernate.Test/Linq/QueryTimeoutTests.cs index bf6ba97bec5..5b74ae4bf20 100644 --- a/src/NHibernate.Test/Linq/QueryTimeoutTests.cs +++ b/src/NHibernate.Test/Linq/QueryTimeoutTests.cs @@ -22,7 +22,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchStrategy, typeof(TimeoutCatchingNonBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs b/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs index fcd93d71595..32ddae24c52 100644 --- a/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs +++ b/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs @@ -32,7 +32,6 @@ protected override void Configure(Configuration configuration) x.MultiTenancyConnectionProvider(); }); configuration.Properties[Cfg.Environment.GenerateStatistics] = "true"; - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs b/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs index 76a18409c8e..3b0783d17c8 100644 --- a/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs +++ b/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs @@ -15,7 +15,7 @@ public abstract class BugTestCase : TestCase protected sealed override string MappingsAssembly => throw new InvalidOperationException("BugTestCase does not support overriding mapping assembly."); - protected sealed override void AddMappings(Configuration configuration) + protected override void AddMappings(Configuration configuration) { var mappings = Mappings; if (mappings == null || mappings.Length == 0) @@ -26,4 +26,4 @@ protected sealed override void AddMappings(Configuration configuration) configuration.AddResource(type.Namespace + "." + file, type.Assembly); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs b/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs index 096419a336e..cfbc9094e22 100644 --- a/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs @@ -34,7 +34,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs index 66e1a522eb5..abf6cd31583 100644 --- a/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs @@ -21,7 +21,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.LinqToHqlGeneratorsRegistry(); } diff --git a/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs index 1d6d19132d1..f13d1ef9a4f 100644 --- a/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs @@ -28,10 +28,10 @@ protected override bool AppliesTo(Dialect.Dialect dialect) return dialect is MsSql2008Dialect; } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { //Points to the database created with FileStream Filegroup. - cfg.Properties["connection.connection_string"] = + configuration.Properties["connection.connection_string"] = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=FileStreamDB;Integrated Security=True;Pooling=False"; #region CREATE DATABASE example diff --git a/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs index 85a727f1ec6..e395d644b15 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs @@ -12,7 +12,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(_interceptor); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs index 73c3be88fe8..a1be5480b81 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs @@ -17,7 +17,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.AppendListeners(ListenerType.PostUpdate, new[] { _auditEventListener }); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs index 22267fb030c..b4d3d2ee329 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs @@ -22,8 +22,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); DriverForSubstitutedCommand.DriverClass = driverClass; diff --git a/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs index 7d69c1c48bb..93e294a4067 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs @@ -8,7 +8,7 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void OnTearDown() diff --git a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs index d32bf89a58a..a9c4270ade2 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs @@ -15,7 +15,6 @@ public CircularReferenceFetchDepth0Fixture() : base(0) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", "0"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs index 68f834e4c02..f3fc4942303 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs @@ -17,7 +17,6 @@ public CircularReferenceFetchDepthFixture(int depth) : base(depth) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", _depth.ToString()); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs index 0138c8b8d27..f6a5d0536bb 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs @@ -32,8 +32,6 @@ protected override void Configure(Configuration configuration) var dialect = NHibernate.Dialect.Dialect.GetDialect(configuration.Properties); if (dialect is Oracle8iDialect) configuration.SetProperty(Environment.Dialect, typeof(Oracle9iDialect).FullName); - - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs index 18d56ce0b9a..0ef4c9e7029 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs @@ -49,7 +49,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs index 5702dec91da..1220858af09 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs @@ -22,7 +22,6 @@ protected override void Configure(Configuration configuration) { new TestEventListener() }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs index 9935fd79940..49c6953e049 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs @@ -34,7 +34,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs b/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs index 5ec72b4aa9e..bbdf7c4add0 100644 --- a/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs @@ -35,7 +35,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs index 1dabda7a0ef..7294b508928 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs @@ -10,7 +10,7 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } private int employeeId; diff --git a/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs index 75b8e5d8765..f14cb381461 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs @@ -11,8 +11,7 @@ public class Fixture : BugTestCase protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs index 092b7f9ead5..dfc95472917 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs @@ -10,12 +10,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1144 [TestFixture] public class Fixture : BugTestCase { - private Configuration configuration; - protected override void Configure(Configuration configuration) { - this.configuration = configuration; - this.configuration.Properties[Environment.BatchSize] = "10"; + configuration.Properties[Environment.BatchSize] = "10"; } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs index dc8e2d841a1..0a5ee99fbb8 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs @@ -7,9 +7,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1230 [TestFixture,Ignore("TODO(Dario)This test demostrate the need of eliminate the 'bool' on pre-insert eventlisteners.")] public class Fixture : BugTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetListener(ListenerType.PreInsert, new PreSaveDoVeto()); + configuration.SetListener(ListenerType.PreInsert, new PreSaveDoVeto()); } /// diff --git a/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs index d82d0ceae14..4f83381cce8 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs @@ -9,7 +9,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs index 28f81cea773..9563b583fef 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs @@ -182,7 +182,6 @@ protected override void OnTearDown() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.SqlExceptionConverter, typeof (SQLUpdateConflictToStaleStateExceptionConverter).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index fd7fa20ce5f..fd3d0460e06 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -12,7 +12,6 @@ public class NativeSqlCollectionLoaderFixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.UseQueryCache, WithQueryCache.ToString()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs index 88eac03b442..321b1c25833 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs @@ -29,8 +29,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - // Ugly hack. _OrignalDialectIsMsSql2005Dialect = Regex.IsMatch(configuration.GetProperty("dialect"), "MsSql200(5|8)Dialect"); @@ -53,4 +51,4 @@ public void ExecutesCustomSqlFunctionContains() Assert.AreEqual(1, plan.SqlStrings.Length); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs b/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs index 6f6804197b0..1174e67fe79 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs @@ -18,7 +18,6 @@ protected override void Configure(Configuration configuration) { listener }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs index 7b1ac3f7be7..d294510bce9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs @@ -19,7 +19,6 @@ protected override bool AppliesTo(ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs index 83bb483dda8..a9b616424bd 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs @@ -19,7 +19,6 @@ public override string GetEntityName(object entity) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(new Namer()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs index 54ed1c463ea..169cd406adb 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs @@ -16,12 +16,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) return (dialect is Dialect.MsSql2000Dialect); } - protected override void Configure(Configuration configuration) - { - base.Configure(configuration); - cfg = configuration; - } - [Test] public void CanCreateAndDropSchema() { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs index d214b5655f6..ddb45bbf22e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs @@ -1,4 +1,5 @@ using System.Data; +using NHibernate.Cfg; using NHibernate.Dialect; using NHibernate.Driver; using NHibernate.Mapping; @@ -7,29 +8,29 @@ namespace NHibernate.Test.NHSpecificTest.NH2302 { - [TestFixture] - public class Fixture : BugTestCase - { - protected override void Configure(Cfg.Configuration configuration) + [TestFixture] + public class Fixture : BugTestCase + { + protected override void AddMappings(Configuration configuration) { + base.AddMappings(configuration); + foreach (var cls in configuration.ClassMappings) { foreach (var prop in cls.PropertyIterator) { foreach (var col in prop.ColumnIterator) { - if (col is Column) + if (col is Column column && column.SqlType == "nvarchar(max)") { - var column = col as Column; - if (column.SqlType == "nvarchar(max)") - column.SqlType = Dialect.GetLongestTypeName(DbType.String); + column.SqlType = Dialect.GetLongestTypeName(DbType.String); } } } } } - protected override void OnTearDown() + protected override void OnTearDown() { CleanUp(); diff --git a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs index b5f15a3194a..f9e9f032c9e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs @@ -13,7 +13,6 @@ public class Fixture : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty("linqtohql.generatorsregistry", "NHibernate.Test.NHSpecificTest.NH2318.ExtendedLinqtoHqlGeneratorsRegistry, NHibernate.Test"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs index 0d1a2b43f13..6de826d4dae 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs @@ -11,7 +11,6 @@ public class NH2439Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs index ac6114feb78..4e753234f00 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs @@ -14,7 +14,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) protected override void Configure(NHibernate.Cfg.Configuration configuration) { configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "keywords"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs index 967cbf8e953..b5c7581f87f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs @@ -13,7 +13,6 @@ public abstract class AbstractMassTestingFixture : BugTestCase public const int BatchSize = 200; protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.DataBaseIntegration(x => x.BatchSize = BatchSize+5); List cacheSettings = new List(configuration.Properties.Keys.Where(x => x.Contains("cache"))); foreach (var cacheSetting in cacheSettings) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs b/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs index 19e7ae2a6d1..7918a27b16c 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs @@ -38,7 +38,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { // to be sure we are using the new drive - base.Configure(configuration); configuration.DataBaseIntegration(x=> x.Driver()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs index 56d685c8047..a69396a8fa9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs @@ -22,7 +22,7 @@ protected override void Configure(Cfg.Configuration configuration) { _originalDialect = Dialect; - cfg.SetProperty(Environment.Dialect, typeof(CustomDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomDialect).AssemblyQualifiedName); } public static string GetSql(ICriteria criteria) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs index 8280f1c3b8a..9ebc12e4f4e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs @@ -12,7 +12,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { configuration.LinqToHqlGeneratorsRegistry(); - base.Configure(configuration); } protected override void OnSetUp() @@ -55,4 +54,4 @@ public void CustomExtensionWithConstantArgumentShouldBeIncludedInHqlProjection() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs index cdff9247ad9..acf4c0fcd5f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs @@ -11,7 +11,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(BinaryFormatterCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -121,4 +120,4 @@ public void SecondLevelCacheWithHqlQueries() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs index 92e2994f147..1fd18d43f67 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs @@ -8,8 +8,6 @@ public class SampleTest : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - configuration.Properties.Add("current_session_context_class", "thread_static"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs index c9d982b2a4f..739cf8d5ec2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs @@ -21,7 +21,6 @@ public ChildrenTest(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs index 219ef8ad1bd..7bcc5f836a2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs @@ -16,11 +16,11 @@ protected override void Configure(Configuration configuration) if (!(Dialect is MsSql2008Dialect)) Assert.Ignore("Test is for MS SQL Server dialect only (custom dialect)."); - if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)))) + if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)))) Assert.Ignore("Test is for MS SQL Server driver only (custom driver is used)."); - cfg.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); } private OffsetStartsAtOneTestDialect OffsetStartsAtOneTestDialect diff --git a/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs index 8da7a871fc1..ec5d6d8be27 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs @@ -38,8 +38,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is SQLiteDialect) { var connStr = configuration.Properties[Environment.ConnectionString]; diff --git a/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs index 3625746d047..8e61e97ceea 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs @@ -61,7 +61,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchSize, batchSize.ToString(CultureInfo.InvariantCulture)); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs index 45ca778c972..396a5ed3ba5 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs @@ -24,7 +24,6 @@ public BatchFetchStyleFixture(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs index f617a69752f..c8021a7d7f6 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs @@ -76,7 +76,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Cache(c => { c.UseQueryCache = true; diff --git a/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs index 396fd38a48a..84007aa39a1 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs @@ -36,7 +36,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchStrategy, typeof(OracleDataClientBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs index 9cb011fc9b0..ac1ea430c36 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs @@ -61,7 +61,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostInsertEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs index ba2b9beb351..4a073046410 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs @@ -55,7 +55,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostUpdateEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs b/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs index 854867a5cc7..ff4a358ee3f 100644 --- a/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs b/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs index 7149e89a67c..324db05247c 100644 --- a/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs @@ -21,9 +21,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs b/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs index 62c8a151e45..5469c9f12b4 100644 --- a/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs +++ b/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.EFGJoinedSubclass.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs b/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs index 1af405c0a14..5ea4f1c967b 100644 --- a/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs +++ b/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs @@ -19,7 +19,7 @@ protected override string[] Mappings protected override void Configure(Cfg.Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Ondelete/ParentChildFixture.cs b/src/NHibernate.Test/Ondelete/ParentChildFixture.cs index d5303005de4..905de75dbe2 100644 --- a/src/NHibernate.Test/Ondelete/ParentChildFixture.cs +++ b/src/NHibernate.Test/Ondelete/ParentChildFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.ParentChild.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs index 3d0e571ae9a..bfba5aed930 100644 --- a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs @@ -30,12 +30,12 @@ protected override void Configure(Configuration configuration) // Configure is called before Applies, must check here. if (!(Dialect is MsSql2005Dialect)) Assert.Ignore("Test is for SQL dialect only"); - var driverClass = ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)); + var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)); if (!typeof(SqlClientDriver).IsAssignableFrom(driverClass)) Assert.Ignore("Test is compatible only with Sql Server Client driver connection strings"); - cfg.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); } private CustomMsSqlDialect CustomDialect diff --git a/src/NHibernate.Test/Pagination/PaginationFixture.cs b/src/NHibernate.Test/Pagination/PaginationFixture.cs index df9f578bc45..b921dbeda42 100644 --- a/src/NHibernate.Test/Pagination/PaginationFixture.cs +++ b/src/NHibernate.Test/Pagination/PaginationFixture.cs @@ -23,7 +23,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.DefaultBatchFetchSize, "20"); + configuration.SetProperty(Environment.DefaultBatchFetchSize, "20"); } [Test] diff --git a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs index acebb19a929..db2a020d380 100644 --- a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs @@ -29,8 +29,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs b/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs index 9957275d67a..f65135564b1 100644 --- a/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs +++ b/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs @@ -13,7 +13,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); configuration.SetProperty(Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs b/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs index f8c8581363e..731a0674890 100644 --- a/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs +++ b/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs @@ -24,7 +24,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -262,4 +261,4 @@ public void SecondLevelCacheWithHqlQueries() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs b/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs index 97dd424543b..c7b692d9a8f 100644 --- a/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs +++ b/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs @@ -13,7 +13,6 @@ protected override string MappingsAssembly protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs b/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs index 90501423ffc..d28827c4a35 100644 --- a/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs +++ b/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs @@ -19,8 +19,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Environment.MaxFetchDepth, 1.ToString()); + configuration.SetProperty(Environment.MaxFetchDepth, 1.ToString()); } protected override bool AppliesTo(Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs index 3b60b3367a1..7d05eac7cd6 100644 --- a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs @@ -9,9 +9,9 @@ namespace NHibernate.Test.SubselectFetchTest [TestFixture] public class SubselectFetchFixture : TestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index 137818e1e90..1335b6a722a 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -293,10 +293,10 @@ protected void Configure() { cfg = TestConfigurationHelper.GetDefaultConfiguration(); - AddMappings(cfg); - Configure(cfg); + AddMappings(cfg); + ApplyCacheSettings(cfg); } diff --git a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs index 0d95535b947..176c9954bf5 100644 --- a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs @@ -28,8 +28,6 @@ public abstract class AbstractDateTimeTypeFixture : TypeFixtureBase protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs index d54f3876f33..013d98814af 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs @@ -28,7 +28,6 @@ protected override void Configure(Configuration configuration) ? (IType) NHibernateUtil.DateTimeNoMs : NHibernateUtil.DateTime; TypeFactory.RegisterType(typeof(DateTime), _testDefaultDateTimeType, TypeFactory.EmptyAliases); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs index e8fbd52f2db..3f9ecc0b2c6 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs @@ -46,7 +46,6 @@ protected override void Configure(Configuration configuration) _testDefaultStringType, new[] {"string"}, length => new CustomStringType(length)); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs index 2d803f5b4e5..fd71f8da3da 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs @@ -47,7 +47,6 @@ protected override void Configure(Configuration configuration) _testDefaultType, new[] {"currency"}, (precision, scale) => new CustomCurrencyType(precision, scale)); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs index b38475b3a40..61a2bd59029 100644 --- a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs @@ -30,8 +30,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) => protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; diff --git a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs index 4f839a39df8..7a907c84267 100644 --- a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs @@ -24,8 +24,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is FirebirdDialect) { configuration.SetProperty(Environment.QueryDefaultCastPrecision, "18"); diff --git a/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs b/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs index 8f76ead9605..09e91e2483d 100644 --- a/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs +++ b/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs @@ -19,8 +19,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } From c2652208386d0f8127ac9420ae1b5cbf39332db3 Mon Sep 17 00:00:00 2001 From: tohidemyname <42423544+tohidemyname@users.noreply.github.com> Date: Sun, 30 Jun 2024 03:10:26 +0800 Subject: [PATCH 107/128] Fixing a typo in PersistEvent.cs (#3570) Co-authored-by: tohidemyname --- src/NHibernate/Event/PersistEvent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Event/PersistEvent.cs b/src/NHibernate/Event/PersistEvent.cs index 89a84a786db..8467d55ae86 100644 --- a/src/NHibernate/Event/PersistEvent.cs +++ b/src/NHibernate/Event/PersistEvent.cs @@ -13,7 +13,7 @@ public PersistEvent(object entity, IEventSource source) { if (entity == null) { - throw new ArgumentNullException("entity", "Attempt to create create event with null entity"); + throw new ArgumentNullException("entity", "Attempt to create event with null entity"); } this.entity = entity; } @@ -36,4 +36,4 @@ public object Entity set { entity = value; } } } -} \ No newline at end of file +} From b4a69d1a5ff5744312478d70308329af496e4ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:56:52 +0200 Subject: [PATCH 108/128] Handle SQL injection vulnerabilities within ObjectToSQLString (#3547) Co-authored-by: Alex Zaytsev Co-authored-by: github-actions[bot] --- doc/reference/modules/configuration.xml | 20 +- .../SapSQLAnywhere.cfg.xml | 2 +- .../NHSpecificTest/GH3516/FixtureByCode.cs | 399 ++++++++++++++++++ .../NHSpecificTest/GH3516/Entity.cs | 54 +++ .../NHSpecificTest/GH3516/FixtureByCode.cs | 388 +++++++++++++++++ .../NHSpecificTest/GH3516/Hierarchy.cs | 18 + .../SqlCommandTest/SqlInsertBuilderFixture.cs | 2 +- src/NHibernate.Test/TestDialect.cs | 2 +- .../TestDialects/Oracle10gTestDialect.cs | 14 +- .../SapSQLAnywhere17TestDialect.cs | 17 +- src/NHibernate/Async/Type/ByteType.cs | 1 + src/NHibernate/Async/Type/Int16Type.cs | 5 +- src/NHibernate/Async/Type/Int32Type.cs | 5 +- src/NHibernate/Async/Type/Int64Type.cs | 1 + src/NHibernate/Async/Type/TicksType.cs | 1 + .../Async/Type/TimeAsTimeSpanType.cs | 5 +- src/NHibernate/Async/Type/TimeSpanType.cs | 5 +- src/NHibernate/Async/Type/UInt16Type.cs | 1 + src/NHibernate/Async/Type/UInt32Type.cs | 1 + src/NHibernate/Async/Type/UInt64Type.cs | 1 + src/NHibernate/Cfg/Environment.cs | 6 + src/NHibernate/Dialect/DB2Dialect.cs | 25 ++ src/NHibernate/Dialect/Dialect.cs | 58 ++- src/NHibernate/Dialect/IngresDialect.cs | 5 + src/NHibernate/Dialect/MsSql2000Dialect.cs | 4 + src/NHibernate/Dialect/MySQLDialect.cs | 10 + src/NHibernate/Dialect/Oracle8iDialect.cs | 5 + src/NHibernate/Dialect/SybaseASA9Dialect.cs | 12 +- .../Dialect/SybaseSQLAnywhere10Dialect.cs | 10 + src/NHibernate/Type/AbstractCharType.cs | 4 +- src/NHibernate/Type/AbstractDateTimeType.cs | 4 +- src/NHibernate/Type/AbstractStringType.cs | 5 +- src/NHibernate/Type/ByteType.cs | 3 +- src/NHibernate/Type/CharBooleanType.cs | 5 +- src/NHibernate/Type/DateTimeOffSetType.cs | 4 +- src/NHibernate/Type/DateType.cs | 4 +- src/NHibernate/Type/DecimalType.cs | 3 +- src/NHibernate/Type/DoubleType.cs | 3 +- src/NHibernate/Type/EnumCharType.cs | 4 +- src/NHibernate/Type/GuidType.cs | 2 +- src/NHibernate/Type/Int16Type.cs | 7 +- src/NHibernate/Type/Int32Type.cs | 7 +- src/NHibernate/Type/Int64Type.cs | 3 +- src/NHibernate/Type/SByteType.cs | 3 +- src/NHibernate/Type/SingleType.cs | 3 +- src/NHibernate/Type/TicksType.cs | 3 +- src/NHibernate/Type/TimeAsTimeSpanType.cs | 7 +- src/NHibernate/Type/TimeSpanType.cs | 7 +- src/NHibernate/Type/TimeType.cs | 4 +- src/NHibernate/Type/UInt16Type.cs | 3 +- src/NHibernate/Type/UInt32Type.cs | 3 +- src/NHibernate/Type/UInt64Type.cs | 3 +- src/NHibernate/Type/UriType.cs | 4 +- src/NHibernate/nhibernate-configuration.xsd | 8 + 54 files changed, 1105 insertions(+), 78 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs diff --git a/doc/reference/modules/configuration.xml b/doc/reference/modules/configuration.xml index 15656f556c1..ee6644cadf7 100644 --- a/doc/reference/modules/configuration.xml +++ b/doc/reference/modules/configuration.xml @@ -871,6 +871,20 @@ var session = sessions.OpenSession(conn); + + + escape_backslash_in_strings + + + Indicates if the database needs to have backslash escaped in string literals. + The default value is dialect dependant. That is false for + most dialects. + + eg. + true | false + + + show_sql @@ -1515,12 +1529,6 @@ in the parameter binding. NHibernate.Dialect.PostgreSQLDialect - - PostgreSQL - NHibernate.Dialect.PostgreSQLDialect - - - PostgreSQL 8.1 NHibernate.Dialect.PostgreSQL81Dialect diff --git a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml index 9512fef12d6..1ce5a50bbbc 100644 --- a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml +++ b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml @@ -15,7 +15,7 @@ for your own use before compiling tests in Visual Studio. UID=DBA;PWD=sql;Server=localhost;DBN=nhibernate;DBF=c:\nhibernate.db;ASTOP=No;Enlist=false; - NHibernate.Dialect.SybaseSQLAnywhere12Dialect + NHibernate.Dialect.SapSQLAnywhere17Dialect true=1;false=0 diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs new file mode 100644 index 00000000000..f63dcb43745 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs @@ -0,0 +1,399 @@ +//------------------------------------------------------------------------------ +// +// 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.Collections; +using System.Collections.Generic; +using System.Globalization; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NHibernate.Type; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureByCodeAsync : TestCaseMappingByCode + { + + private readonly HashSet _unsupportedProperties = new(); + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.FirstChar); + rc.Property(x => x.CharacterEnum, m => m.Type>()); + rc.Property(x => x.UriProperty); + + rc.Property(x => x.ByteProperty); + rc.Property(x => x.DecimalProperty); + rc.Property(x => x.DoubleProperty); + rc.Property(x => x.FloatProperty); + rc.Property(x => x.ShortProperty); + rc.Property(x => x.IntProperty); + rc.Property(x => x.LongProperty); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.SByte)) + rc.Property(x => x.SByteProperty); + else + _unsupportedProperties.Add(nameof(Entity.SByteProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt16)) + rc.Property(x => x.UShortProperty); + else + _unsupportedProperties.Add(nameof(Entity.UShortProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt32)) + rc.Property(x => x.UIntProperty); + else + _unsupportedProperties.Add(nameof(Entity.UIntProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt64)) + rc.Property(x => x.ULongProperty); + else + _unsupportedProperties.Add(nameof(Entity.ULongProperty)); + + rc.Property(x => x.DateTimeProperty); + rc.Property(x => x.DateProperty, m => m.Type(NHibernateUtil.Date)); + if (TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet)) + rc.Property(x => x.DateTimeOffsetProperty); + else + _unsupportedProperties.Add(nameof(Entity.DateTimeOffsetProperty)); + rc.Property(x => x.TimeProperty, m => m.Type(NHibernateUtil.Time)); + + rc.Property(x => x.GuidProperty); + }); + + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Discriminator(x => x.Column("StringDiscriminator")); + rc.Property(x => x.Name); + rc.Abstract(true); + }); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithSingleQuote)); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithEscapedSingleQuote)); + + mapper.Import(); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private CultureInfo _backupCulture; + private CultureInfo _backupUICulture; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Save( + new Entity + { + Name = Entity.NameWithSingleQuote, + FirstChar = Entity.QuoteInitial, + CharacterEnum = CharEnum.SingleQuote, + UriProperty = Entity.UriWithSingleQuote + }); + session.Save( + new Entity + { + Name = Entity.NameWithEscapedSingleQuote, + FirstChar = Entity.BackslashInitial, + CharacterEnum = CharEnum.Backslash, + UriProperty = Entity.UriWithEscapedSingleQuote + }); + + transaction.Commit(); + + _backupCulture = CultureInfo.CurrentCulture; + _backupUICulture = CultureInfo.CurrentUICulture; + } + + protected override void OnTearDown() + { + if (_backupCulture != null) + { + CultureInfo.CurrentCulture = _backupCulture; + CultureInfo.CurrentUICulture = _backupUICulture; + } + + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + private static readonly string[] StringInjectionsProperties = + { + nameof(Entity.NameWithSingleQuote), nameof(Entity.NameWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(StringInjectionsProperties))] + public void SqlInjectionInStringsAsync(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.Name = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with name {propertyName}"); + } + + private static readonly string[] SpecialNames = + { + "\0; drop table Entity; --", + "\b; drop table Entity; --", + "\n; drop table Entity; --", + "\r; drop table Entity; --", + "\t; drop table Entity; --", + "\x1A; drop table Entity; --", + "\"; drop table Entity; --", + "\\; drop table Entity; --" + }; + + [TestCaseSource(nameof(SpecialNames))] + public async Task StringsWithSpecialCharactersAsync(string name) + { + // We may not even be able to insert the entity. + var wasInserted = false; + try + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var e = new Entity { Name = name }; + await (s.SaveAsync(e)); + await (t.CommitAsync()); + + wasInserted = true; + } + catch (Exception e) + { + Assert.Warn($"The entity insertion failed with message {e}"); + } + + try + { + using var session = OpenSession(); + Entity.ArbitraryStringValue = name; + var list = await (session.CreateQuery($"from Entity e where e.Name = Entity.{nameof(Entity.ArbitraryStringValue)}").ListAsync()); + if (wasInserted && list.Count != 1) + Assert.Warn($"Unable to find entity with name {nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception e) + { + Assert.Warn($"The query has failed with message {e}"); + } + + // Check the db is not wrecked. + if (wasInserted) + { + using var session = OpenSession(); + var list = await (session + .CreateQuery("from Entity e where e.Name = :name") + .SetString("name", name) + .ListAsync()); + Assert.That(list, Has.Count.EqualTo(1)); + } + else + { + using var session = OpenSession(); + var all = await (session.CreateQuery("from Entity e").ListAsync()); + Assert.That(all, Has.Count.GreaterThan(0)); + } + } + + [Test] + public async Task SqlInjectionInStringDiscriminatorAsync() + { + using var session = OpenSession(); + + await (session.SaveAsync(new Subclass1 { Name = "Subclass1" })); + await (session.SaveAsync(new Subclass2 { Name = "Subclass2" })); + + // ObjectToSQLString is used for generating the inserts. + Assert.That(session.Flush, Throws.Nothing, "Unable to flush the subclasses"); + + foreach (var entityName in new[] { nameof(Subclass1), nameof(Subclass2) }) + { + var query = session.CreateQuery($"from {entityName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, $"Unable to list entities of {entityName}"); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find the {entityName} entity"); + } + } + + private static readonly string[] CharInjectionsProperties = + { + nameof(Entity.QuoteInitial), nameof(Entity.BackslashInitial) + }; + + [TestCaseSource(nameof(CharInjectionsProperties))] + public void SqlInjectionInCharAsync(string propertyName) + { + using var session = OpenSession(); + var query = session.CreateQuery($"from Entity e where e.FirstChar = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Is.Not.Null.And.Count.EqualTo(1), $"Unable to find entity with initial {propertyName}"); + } + + private static readonly string[] CharEnumInjections = + { + nameof(CharEnum.SingleQuote), nameof(CharEnum.Backslash) + }; + + [TestCaseSource(nameof(CharEnumInjections))] + public void SqlInjectionWithCharEnumAsync(string enumName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.CharacterEnum = CharEnum.{enumName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with CharacterEnum {enumName}"); + } + + private static readonly string[] UriInjections = + { + nameof(Entity.UriWithSingleQuote), nameof(Entity.UriWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(UriInjections))] + public void SqlInjectionWithUriAsync(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.UriProperty = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with UriProperty {propertyName}"); + } + + private static readonly string[] NumericalTypesInjections = + { + nameof(Entity.ByteProperty), + nameof(Entity.DecimalProperty), + nameof(Entity.DoubleProperty), + nameof(Entity.FloatProperty), + nameof(Entity.ShortProperty), + nameof(Entity.IntProperty), + nameof(Entity.LongProperty), + nameof(Entity.SByteProperty), + nameof(Entity.UShortProperty), + nameof(Entity.UIntProperty), + nameof(Entity.ULongProperty) + }; + + [TestCaseSource(nameof(NumericalTypesInjections))] + public async Task SqlInjectionInNumericalTypeAsync(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + Entity.ArbitraryStringValue = "0; drop table Entity; --"; + using (var session = OpenSession()) + { + IQuery query; + // Defining that query is invalid and should throw. + try + { + query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception ex) + { + // All good. + Assert.Pass($"The wicked query creation has been rejected, as it should: {ex}"); + // Needed for the compiler who does not know "Pass" always throw. + return; + } + + // The query definition has been accepted, run it. + try + { + await (query.ListAsync()); + } + catch (Exception ex) + { + // Expecting no exception at that point, but the test is to check if the injection succeeded. + Assert.Warn($"The wicked query execution has failed: {ex}"); + } + } + + // Check if we can still query Entity. If it succeeds, at least it means the injection failed. + using (var session = OpenSession()) + { + IList list = null; + Assert.That(async () => list = await (session.CreateQuery("from Entity e").ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.GreaterThan(0)); + } + } + + private static readonly string[] DateTypesInjections = + { + nameof(Entity.DateTimeProperty), + nameof(Entity.DateProperty), + nameof(Entity.DateTimeOffsetProperty), + nameof(Entity.TimeProperty) + }; + + [TestCaseSource(nameof(DateTypesInjections))] + public void SqlInjectionWithDatetimeAsync(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + var wickedCulture = new CultureInfo("en-US"); + if (propertyName == nameof(Entity.TimeProperty)) + wickedCulture.DateTimeFormat.ShortTimePattern = "HH:mm:ss\\'\"; drop table Entity; --\""; + else + wickedCulture.DateTimeFormat.ShortDatePattern = "yyyy-MM-ddTHH:mm:ss\\'\"; drop table Entity; --\""; + CultureInfo.CurrentCulture = wickedCulture; + CultureInfo.CurrentUICulture = wickedCulture; + + using var session = OpenSession(); + + var staticPropertyName = propertyName == nameof(Entity.DateTimeOffsetProperty) ? + nameof(Entity.StaticDateTimeOffsetProperty) : nameof(Entity.StaticDateProperty); + var query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{staticPropertyName}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + + private static readonly string[] GuidInjections = + { + Entity.NameWithSingleQuote, Entity.NameWithEscapedSingleQuote + }; + + [TestCaseSource(nameof(GuidInjections))] + public void SqlInjectionWithGuidAsync(string injection) + { + Entity.ArbitraryStringValue = $"{Guid.NewGuid()}{injection}"; + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.GuidProperty = Entity.{nameof(Entity.ArbitraryStringValue)}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs new file mode 100644 index 00000000000..0326e557526 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs @@ -0,0 +1,54 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual char FirstChar { get; set; } + public virtual CharEnum CharacterEnum { get; set; } = CharEnum.SimpleChar; + public virtual Uri UriProperty { get; set; } + + public virtual byte ByteProperty { get; set; } + public virtual decimal DecimalProperty { get; set; } + public virtual double DoubleProperty { get; set; } + public virtual float FloatProperty { get; set; } + public virtual short ShortProperty { get; set; } + public virtual int IntProperty { get; set; } + public virtual long LongProperty { get; set; } + public virtual sbyte SByteProperty { get; set; } + public virtual ushort UShortProperty { get; set; } + public virtual uint UIntProperty { get; set; } + public virtual ulong ULongProperty { get; set; } + + public virtual DateTime DateTimeProperty { get; set; } = StaticDateProperty; + public virtual DateTime DateProperty { get; set; } = StaticDateProperty; + public virtual DateTimeOffset DateTimeOffsetProperty { get; set; } = StaticDateProperty; + public virtual DateTime TimeProperty { get; set; } = StaticDateProperty; + + public virtual Guid GuidProperty { get; set; } = Guid.Empty; + + public const string NameWithSingleQuote = "'; drop table Entity; --"; + public const string NameWithEscapedSingleQuote = @"\'; drop table Entity; --"; + + // Do not switch to property, the feature of referencing static fields in HQL does not work with properties. + public static string ArbitraryStringValue; + + public const char QuoteInitial = '\''; + public const char BackslashInitial = '\\'; + + public static readonly Uri UriWithSingleQuote = new("https://somewhere/?sql='; drop table Entity; --"); + public static readonly Uri UriWithEscapedSingleQuote = new(@"https://somewhere/?sql=\'; drop table Entity; --"); + + public static readonly DateTime StaticDateProperty = DateTime.Today; + public static readonly DateTimeOffset StaticDateTimeOffsetProperty = DateTimeOffset.Now; + } + + public enum CharEnum + { + SimpleChar = 'A', + SingleQuote = '\'', + Backslash = '\\' + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs new file mode 100644 index 00000000000..235fad90b75 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NHibernate.Type; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + [TestFixture] + public class FixtureByCode : TestCaseMappingByCode + { + + private readonly HashSet _unsupportedProperties = new(); + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.FirstChar); + rc.Property(x => x.CharacterEnum, m => m.Type>()); + rc.Property(x => x.UriProperty); + + rc.Property(x => x.ByteProperty); + rc.Property(x => x.DecimalProperty); + rc.Property(x => x.DoubleProperty); + rc.Property(x => x.FloatProperty); + rc.Property(x => x.ShortProperty); + rc.Property(x => x.IntProperty); + rc.Property(x => x.LongProperty); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.SByte)) + rc.Property(x => x.SByteProperty); + else + _unsupportedProperties.Add(nameof(Entity.SByteProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt16)) + rc.Property(x => x.UShortProperty); + else + _unsupportedProperties.Add(nameof(Entity.UShortProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt32)) + rc.Property(x => x.UIntProperty); + else + _unsupportedProperties.Add(nameof(Entity.UIntProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt64)) + rc.Property(x => x.ULongProperty); + else + _unsupportedProperties.Add(nameof(Entity.ULongProperty)); + + rc.Property(x => x.DateTimeProperty); + rc.Property(x => x.DateProperty, m => m.Type(NHibernateUtil.Date)); + if (TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet)) + rc.Property(x => x.DateTimeOffsetProperty); + else + _unsupportedProperties.Add(nameof(Entity.DateTimeOffsetProperty)); + rc.Property(x => x.TimeProperty, m => m.Type(NHibernateUtil.Time)); + + rc.Property(x => x.GuidProperty); + }); + + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Discriminator(x => x.Column("StringDiscriminator")); + rc.Property(x => x.Name); + rc.Abstract(true); + }); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithSingleQuote)); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithEscapedSingleQuote)); + + mapper.Import(); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private CultureInfo _backupCulture; + private CultureInfo _backupUICulture; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Save( + new Entity + { + Name = Entity.NameWithSingleQuote, + FirstChar = Entity.QuoteInitial, + CharacterEnum = CharEnum.SingleQuote, + UriProperty = Entity.UriWithSingleQuote + }); + session.Save( + new Entity + { + Name = Entity.NameWithEscapedSingleQuote, + FirstChar = Entity.BackslashInitial, + CharacterEnum = CharEnum.Backslash, + UriProperty = Entity.UriWithEscapedSingleQuote + }); + + transaction.Commit(); + + _backupCulture = CultureInfo.CurrentCulture; + _backupUICulture = CultureInfo.CurrentUICulture; + } + + protected override void OnTearDown() + { + if (_backupCulture != null) + { + CultureInfo.CurrentCulture = _backupCulture; + CultureInfo.CurrentUICulture = _backupUICulture; + } + + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + private static readonly string[] StringInjectionsProperties = + { + nameof(Entity.NameWithSingleQuote), nameof(Entity.NameWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(StringInjectionsProperties))] + public void SqlInjectionInStrings(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.Name = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with name {propertyName}"); + } + + private static readonly string[] SpecialNames = + { + "\0; drop table Entity; --", + "\b; drop table Entity; --", + "\n; drop table Entity; --", + "\r; drop table Entity; --", + "\t; drop table Entity; --", + "\x1A; drop table Entity; --", + "\"; drop table Entity; --", + "\\; drop table Entity; --" + }; + + [TestCaseSource(nameof(SpecialNames))] + public void StringsWithSpecialCharacters(string name) + { + // We may not even be able to insert the entity. + var wasInserted = false; + try + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var e = new Entity { Name = name }; + s.Save(e); + t.Commit(); + + wasInserted = true; + } + catch (Exception e) + { + Assert.Warn($"The entity insertion failed with message {e}"); + } + + try + { + using var session = OpenSession(); + Entity.ArbitraryStringValue = name; + var list = session.CreateQuery($"from Entity e where e.Name = Entity.{nameof(Entity.ArbitraryStringValue)}").List(); + if (wasInserted && list.Count != 1) + Assert.Warn($"Unable to find entity with name {nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception e) + { + Assert.Warn($"The query has failed with message {e}"); + } + + // Check the db is not wrecked. + if (wasInserted) + { + using var session = OpenSession(); + var list = session + .CreateQuery("from Entity e where e.Name = :name") + .SetString("name", name) + .List(); + Assert.That(list, Has.Count.EqualTo(1)); + } + else + { + using var session = OpenSession(); + var all = session.CreateQuery("from Entity e").List(); + Assert.That(all, Has.Count.GreaterThan(0)); + } + } + + [Test] + public void SqlInjectionInStringDiscriminator() + { + using var session = OpenSession(); + + session.Save(new Subclass1 { Name = "Subclass1" }); + session.Save(new Subclass2 { Name = "Subclass2" }); + + // ObjectToSQLString is used for generating the inserts. + Assert.That(session.Flush, Throws.Nothing, "Unable to flush the subclasses"); + + foreach (var entityName in new[] { nameof(Subclass1), nameof(Subclass2) }) + { + var query = session.CreateQuery($"from {entityName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing, $"Unable to list entities of {entityName}"); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find the {entityName} entity"); + } + } + + private static readonly string[] CharInjectionsProperties = + { + nameof(Entity.QuoteInitial), nameof(Entity.BackslashInitial) + }; + + [TestCaseSource(nameof(CharInjectionsProperties))] + public void SqlInjectionInChar(string propertyName) + { + using var session = OpenSession(); + var query = session.CreateQuery($"from Entity e where e.FirstChar = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Is.Not.Null.And.Count.EqualTo(1), $"Unable to find entity with initial {propertyName}"); + } + + private static readonly string[] CharEnumInjections = + { + nameof(CharEnum.SingleQuote), nameof(CharEnum.Backslash) + }; + + [TestCaseSource(nameof(CharEnumInjections))] + public void SqlInjectionWithCharEnum(string enumName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.CharacterEnum = CharEnum.{enumName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with CharacterEnum {enumName}"); + } + + private static readonly string[] UriInjections = + { + nameof(Entity.UriWithSingleQuote), nameof(Entity.UriWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(UriInjections))] + public void SqlInjectionWithUri(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.UriProperty = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with UriProperty {propertyName}"); + } + + private static readonly string[] NumericalTypesInjections = + { + nameof(Entity.ByteProperty), + nameof(Entity.DecimalProperty), + nameof(Entity.DoubleProperty), + nameof(Entity.FloatProperty), + nameof(Entity.ShortProperty), + nameof(Entity.IntProperty), + nameof(Entity.LongProperty), + nameof(Entity.SByteProperty), + nameof(Entity.UShortProperty), + nameof(Entity.UIntProperty), + nameof(Entity.ULongProperty) + }; + + [TestCaseSource(nameof(NumericalTypesInjections))] + public void SqlInjectionInNumericalType(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + Entity.ArbitraryStringValue = "0; drop table Entity; --"; + using (var session = OpenSession()) + { + IQuery query; + // Defining that query is invalid and should throw. + try + { + query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception ex) + { + // All good. + Assert.Pass($"The wicked query creation has been rejected, as it should: {ex}"); + // Needed for the compiler who does not know "Pass" always throw. + return; + } + + // The query definition has been accepted, run it. + try + { + query.List(); + } + catch (Exception ex) + { + // Expecting no exception at that point, but the test is to check if the injection succeeded. + Assert.Warn($"The wicked query execution has failed: {ex}"); + } + } + + // Check if we can still query Entity. If it succeeds, at least it means the injection failed. + using (var session = OpenSession()) + { + IList list = null; + Assert.That(() => list = session.CreateQuery("from Entity e").List(), Throws.Nothing); + Assert.That(list, Has.Count.GreaterThan(0)); + } + } + + private static readonly string[] DateTypesInjections = + { + nameof(Entity.DateTimeProperty), + nameof(Entity.DateProperty), + nameof(Entity.DateTimeOffsetProperty), + nameof(Entity.TimeProperty) + }; + + [TestCaseSource(nameof(DateTypesInjections))] + public void SqlInjectionWithDatetime(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + var wickedCulture = new CultureInfo("en-US"); + if (propertyName == nameof(Entity.TimeProperty)) + wickedCulture.DateTimeFormat.ShortTimePattern = "HH:mm:ss\\'\"; drop table Entity; --\""; + else + wickedCulture.DateTimeFormat.ShortDatePattern = "yyyy-MM-ddTHH:mm:ss\\'\"; drop table Entity; --\""; + CultureInfo.CurrentCulture = wickedCulture; + CultureInfo.CurrentUICulture = wickedCulture; + + using var session = OpenSession(); + + var staticPropertyName = propertyName == nameof(Entity.DateTimeOffsetProperty) ? + nameof(Entity.StaticDateTimeOffsetProperty) : nameof(Entity.StaticDateProperty); + var query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{staticPropertyName}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(() => list = query.List(), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + + private static readonly string[] GuidInjections = + { + Entity.NameWithSingleQuote, Entity.NameWithEscapedSingleQuote + }; + + [TestCaseSource(nameof(GuidInjections))] + public void SqlInjectionWithGuid(string injection) + { + Entity.ArbitraryStringValue = $"{Guid.NewGuid()}{injection}"; + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.GuidProperty = Entity.{nameof(Entity.ArbitraryStringValue)}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(() => list = query.List(), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs new file mode 100644 index 00000000000..cb5dca25868 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs @@ -0,0 +1,18 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + public class BaseClass + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } + + public class Subclass1 : BaseClass + { + } + + public class Subclass2 : BaseClass + { + } +} diff --git a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs index ec1d5c0cb4e..ce076e007bd 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs @@ -56,7 +56,7 @@ public void Commented() insert.SetTableName("test_insert_builder"); #pragma warning disable CS0618 // Type or member is obsolete - insert.AddColumn("stringColumn", "aSQLValue", (ILiteralType)NHibernateUtil.String); + insert.AddColumn("stringColumn", "aSQLValue", (ILiteralType)NHibernateUtil.AnsiString); #pragma warning restore CS0618 // Type or member is obsolete insert.SetComment("Test insert"); string expectedSql = diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index 49b2f7e0f69..0d1de762ae3 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -105,7 +105,7 @@ public bool SupportsEmptyInsertsOrHasNonIdentityNativeGenerator /// public virtual bool SupportsNonDataBoundCondition => true; - public bool SupportsSqlType(SqlType sqlType) + public virtual bool SupportsSqlType(SqlType sqlType) { try { diff --git a/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs b/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs index 4a5fb8d2322..281676a6c71 100644 --- a/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs +++ b/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs @@ -1,4 +1,6 @@ -using System.Runtime.InteropServices; +using System.Data; +using System.Runtime.InteropServices; +using NHibernate.SqlTypes; namespace NHibernate.Test.TestDialects { @@ -15,6 +17,16 @@ public Oracle10gTestDialect(Dialect.Dialect dialect) : base(dialect) public override bool SupportsAggregateInSubSelect => true; + public override bool SupportsSqlType(SqlType sqlType) + { + // The Oracle dialects define types for DbType the Oracle driver does not support. + return sqlType.DbType switch + { + DbType.UInt16 or DbType.UInt32 or DbType.UInt64 => false, + _ => base.SupportsSqlType(sqlType) + }; + } + /// /// Canceling a query hangs under Linux with OracleManagedDataClientDriver 21.6.1. public override bool SupportsCancelQuery => !RuntimeInformation.IsOSPlatform(OSPlatform.Linux); diff --git a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs index 35a35092ce3..ff3ba11b781 100644 --- a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs @@ -1,4 +1,7 @@ -namespace NHibernate.Test.TestDialects +using System.Data; +using NHibernate.SqlTypes; + +namespace NHibernate.Test.TestDialects { public class SapSQLAnywhere17TestDialect : TestDialect { @@ -40,8 +43,18 @@ public SapSQLAnywhere17TestDialect(Dialect.Dialect dialect) public override bool HasBrokenTypeInferenceOnSelectedParameters => true; /// - /// Does not support SELECT FOR UPDATE + /// Does not support SELECT FOR UPDATE. /// public override bool SupportsSelectForUpdate => false; + + public override bool SupportsSqlType(SqlType sqlType) + { + // The Anywhere dialects define types for DbType the Anywhere driver does not support. + return sqlType.DbType switch + { + DbType.SByte => false, + _ => base.SupportsSqlType(sqlType) + }; + } } } diff --git a/src/NHibernate/Async/Type/ByteType.cs b/src/NHibernate/Async/Type/ByteType.cs index c908d33432e..4ea953fa78d 100644 --- a/src/NHibernate/Async/Type/ByteType.cs +++ b/src/NHibernate/Async/Type/ByteType.cs @@ -12,6 +12,7 @@ using System.Collections; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/Int16Type.cs b/src/NHibernate/Async/Type/Int16Type.cs index 95cec493791..0d88cbdd280 100644 --- a/src/NHibernate/Async/Type/Int16Type.cs +++ b/src/NHibernate/Async/Type/Int16Type.cs @@ -10,11 +10,12 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/Int32Type.cs b/src/NHibernate/Async/Type/Int32Type.cs index e7897e1eafc..592c61d3b4c 100644 --- a/src/NHibernate/Async/Type/Int32Type.cs +++ b/src/NHibernate/Async/Type/Int32Type.cs @@ -10,11 +10,12 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/Int64Type.cs b/src/NHibernate/Async/Type/Int64Type.cs index a4dae360662..566b0e6b214 100644 --- a/src/NHibernate/Async/Type/Int64Type.cs +++ b/src/NHibernate/Async/Type/Int64Type.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/TicksType.cs b/src/NHibernate/Async/Type/TicksType.cs index 0ffb06b37f6..b6e003cd753 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 System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs index 185baa88eba..4ea5f86697d 100644 --- a/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Async/Type/TimeAsTimeSpanType.cs @@ -10,11 +10,12 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/TimeSpanType.cs b/src/NHibernate/Async/Type/TimeSpanType.cs index 0917413671c..9364c6599c6 100644 --- a/src/NHibernate/Async/Type/TimeSpanType.cs +++ b/src/NHibernate/Async/Type/TimeSpanType.cs @@ -10,11 +10,12 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { diff --git a/src/NHibernate/Async/Type/UInt16Type.cs b/src/NHibernate/Async/Type/UInt16Type.cs index b30c8ee87a4..7384a0c8464 100644 --- a/src/NHibernate/Async/Type/UInt16Type.cs +++ b/src/NHibernate/Async/Type/UInt16Type.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/UInt32Type.cs b/src/NHibernate/Async/Type/UInt32Type.cs index b5aa62179c0..a1f3bf5838a 100644 --- a/src/NHibernate/Async/Type/UInt32Type.cs +++ b/src/NHibernate/Async/Type/UInt32Type.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Async/Type/UInt64Type.cs b/src/NHibernate/Async/Type/UInt64Type.cs index 08e7c68a1e6..bee61c38a9c 100644 --- a/src/NHibernate/Async/Type/UInt64Type.cs +++ b/src/NHibernate/Async/Type/UInt64Type.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; diff --git a/src/NHibernate/Cfg/Environment.cs b/src/NHibernate/Cfg/Environment.cs index cc107802524..27da456948e 100644 --- a/src/NHibernate/Cfg/Environment.cs +++ b/src/NHibernate/Cfg/Environment.cs @@ -119,6 +119,12 @@ public static string Version /// Enable formatting of SQL logged to the console public const string FormatSql = "format_sql"; + /// + /// Indicates if the database needs to have backslash escaped in string literals. + /// + /// The default value is dialect dependent. + public const string EscapeBackslashInStrings = "escape_backslash_in_strings"; + // Since v5.0.1 [Obsolete("This setting has no usages and will be removed in a future version")] public const string UseGetGeneratedKeys = "jdbc.use_get_generated_keys"; diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index a558e6d313d..90668e26bae 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -5,6 +5,7 @@ using NHibernate.Dialect.Function; using NHibernate.Dialect.Schema; using NHibernate.SqlCommand; +using NHibernate.SqlTypes; namespace NHibernate.Dialect { @@ -296,6 +297,30 @@ public override string ForUpdateString public override long TimestampResolutionInTicks => 10L; // Microseconds. + /// + public override string ToStringLiteral(string value, SqlType type) + { + if (value == null) + throw new System.ArgumentNullException(nameof(value)); + if (type == null) + throw new System.ArgumentNullException(nameof(value)); + + // See https://www.ibm.com/docs/en/db2/11.5?topic=elements-constants#r0000731__title__7 + var literal = new StringBuilder(value); + var isUnicode = type.DbType == DbType.String || type.DbType == DbType.StringFixedLength; + if (isUnicode) + literal.Replace(@"\", @"\\"); + + literal + .Replace("'", "''") + .Insert(0, '\'') + .Append('\''); + + if (isUnicode) + literal.Insert(0, "U&"); + return literal.ToString(); + } + #region Overridden informational metadata public override bool SupportsNullInUnique => false; diff --git a/src/NHibernate/Dialect/Dialect.cs b/src/NHibernate/Dialect/Dialect.cs index 9a4db11880e..c76992e197c 100644 --- a/src/NHibernate/Dialect/Dialect.cs +++ b/src/NHibernate/Dialect/Dialect.cs @@ -208,6 +208,7 @@ public virtual void Configure(IDictionary settings) DefaultCastLength = PropertiesHelper.GetInt32(Environment.QueryDefaultCastLength, settings, 4000); DefaultCastPrecision = PropertiesHelper.GetByte(Environment.QueryDefaultCastPrecision, settings, null) ?? 29; DefaultCastScale = PropertiesHelper.GetByte(Environment.QueryDefaultCastScale, settings, null) ?? 10; + EscapeBackslashInStrings = PropertiesHelper.GetBoolean(Environment.EscapeBackslashInStrings, settings, EscapeBackslashInStrings); } #endregion @@ -1354,14 +1355,6 @@ public virtual CaseFragment CreateCaseFragment() return new ANSICaseFragment(this); } - /// The SQL literal value to which this database maps boolean values. - /// The boolean value - /// The appropriate SQL literal. - public virtual string ToBooleanValueString(bool value) - { - return value ? "1" : "0"; - } - internal static void ExtractColumnOrAliasNames(SqlString select, out List columnsOrAliases, out Dictionary aliasToColumn, out Dictionary columnToAlias) { columnsOrAliases = new List(); @@ -2076,6 +2069,55 @@ public virtual string ConvertQuotesForCatalogName(string catalogName) #endregion + #region Literals support + + /// The SQL literal value to which this database maps boolean values. + /// The boolean value. + /// The appropriate SQL literal. + public virtual string ToBooleanValueString(bool value) + => value ? "1" : "0"; + + /// + /// if the database needs to have backslash escaped in string literals. + /// + /// by default in the base dialect, to conform to SQL standard. + protected virtual bool EscapeBackslashInStrings { get; set; } + + /// + /// if the database needs to have Unicode literals prefixed by N. + /// + /// by default in the base dialect. + protected virtual bool UseNPrefixForUnicodeStrings => false; + + /// The SQL string literal value to which this database maps string values. + /// The string value. + /// The SQL type of the string value. + /// The appropriate SQL string literal. + /// Thrown if or + /// is . + public virtual string ToStringLiteral(string value, SqlType type) + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + if (type == null) + throw new ArgumentNullException(nameof(type)); + + var literal = new StringBuilder(value); + if (EscapeBackslashInStrings) + literal.Replace(@"\", @"\\"); + + literal + .Replace("'", "''") + .Insert(0, '\'') + .Append('\''); + + if (UseNPrefixForUnicodeStrings && (type.DbType == DbType.String || type.DbType == DbType.StringFixedLength)) + literal.Insert(0, 'N'); + return literal.ToString(); + } + + #endregion + #region Union subclass support /// diff --git a/src/NHibernate/Dialect/IngresDialect.cs b/src/NHibernate/Dialect/IngresDialect.cs index f6197f328ae..9f6e8e7b4e6 100644 --- a/src/NHibernate/Dialect/IngresDialect.cs +++ b/src/NHibernate/Dialect/IngresDialect.cs @@ -62,6 +62,11 @@ public IngresDialect() /// public override int MaxAliasLength => 32; + /// + /// by default for Ingres, + /// . + protected override bool UseNPrefixForUnicodeStrings => true; + #region Overridden informational metadata public override bool SupportsEmptyInList => false; diff --git a/src/NHibernate/Dialect/MsSql2000Dialect.cs b/src/NHibernate/Dialect/MsSql2000Dialect.cs index 1aec544ed2d..d6fb0e16781 100644 --- a/src/NHibernate/Dialect/MsSql2000Dialect.cs +++ b/src/NHibernate/Dialect/MsSql2000Dialect.cs @@ -755,6 +755,10 @@ public override bool SupportsSqlBatches /// public override int? MaxNumberOfParameters => 2097; + /// + /// by default for SQL Server. + protected override bool UseNPrefixForUnicodeStrings => true; + #region Overridden informational metadata public override bool SupportsEmptyInList => false; diff --git a/src/NHibernate/Dialect/MySQLDialect.cs b/src/NHibernate/Dialect/MySQLDialect.cs index d7b4be07d63..d6cf67b8097 100644 --- a/src/NHibernate/Dialect/MySQLDialect.cs +++ b/src/NHibernate/Dialect/MySQLDialect.cs @@ -530,6 +530,16 @@ public override long TimestampResolutionInTicks /// public override bool SupportsConcurrentWritingConnectionsInSameTransaction => false; + /// + /// by default for MySQL, + /// . + protected override bool EscapeBackslashInStrings { get; set; } = true; + + /// + /// by default for MySQL, + /// . + protected override bool UseNPrefixForUnicodeStrings => true; + #region Overridden informational metadata public override bool SupportsEmptyInList => false; diff --git a/src/NHibernate/Dialect/Oracle8iDialect.cs b/src/NHibernate/Dialect/Oracle8iDialect.cs index 9bbe3e7dfb9..13b9b1298ae 100644 --- a/src/NHibernate/Dialect/Oracle8iDialect.cs +++ b/src/NHibernate/Dialect/Oracle8iDialect.cs @@ -102,6 +102,7 @@ public override void Configure(IDictionary settings) // If changing the default value, keep it in sync with OracleDataClientDriverBase.Configure. UseNPrefixedTypesForUnicode = PropertiesHelper.GetBoolean(Environment.OracleUseNPrefixedTypesForUnicode, settings, false); + RegisterCharacterTypeMappings(); RegisterFloatingPointTypeMappings(); } @@ -561,6 +562,10 @@ public override long TimestampResolutionInTicks /// public override int MaxAliasLength => 30; + /// + /// Returns the same value as . + protected override bool UseNPrefixForUnicodeStrings => UseNPrefixedTypesForUnicode; + #region Overridden informational metadata public override bool SupportsEmptyInList diff --git a/src/NHibernate/Dialect/SybaseASA9Dialect.cs b/src/NHibernate/Dialect/SybaseASA9Dialect.cs index dfae7baa471..e994c85ccb8 100644 --- a/src/NHibernate/Dialect/SybaseASA9Dialect.cs +++ b/src/NHibernate/Dialect/SybaseASA9Dialect.cs @@ -9,7 +9,7 @@ namespace NHibernate.Dialect { /// - /// An SQL dialect for Sybase Adaptive Server Anywhere 9.0 + /// An SQL dialect for Sybase Adaptive Server Anywhere 9.0. (Renamed SQL Anywhere from its version 10.) /// /// ///

@@ -188,5 +188,15 @@ private static int GetAfterSelectInsertPoint(SqlString sql) } return 0; } + + /// + /// by default for SQL Anywhere, + /// . + protected override bool EscapeBackslashInStrings { get; set; } = true; + + /// + /// by default for SQL Anywhere, + /// . + protected override bool UseNPrefixForUnicodeStrings => true; } } diff --git a/src/NHibernate/Dialect/SybaseSQLAnywhere10Dialect.cs b/src/NHibernate/Dialect/SybaseSQLAnywhere10Dialect.cs index 290e626671f..ac5aa44f8e0 100644 --- a/src/NHibernate/Dialect/SybaseSQLAnywhere10Dialect.cs +++ b/src/NHibernate/Dialect/SybaseSQLAnywhere10Dialect.cs @@ -969,5 +969,15 @@ public override IDataBaseSchema GetDataBaseSchema(DbConnection connection) /// /// SQL Anywhere has a micro-second resolution. public override long TimestampResolutionInTicks => 10L; + + /// + /// by default for SQL Anywhere, + /// . + protected override bool EscapeBackslashInStrings { get; set; } = true; + + /// + /// by default for SQL Anywhere, + /// . + protected override bool UseNPrefixForUnicodeStrings => true; } } diff --git a/src/NHibernate/Type/AbstractCharType.cs b/src/NHibernate/Type/AbstractCharType.cs index 5efb630c16c..d47e3c5b21c 100644 --- a/src/NHibernate/Type/AbstractCharType.cs +++ b/src/NHibernate/Type/AbstractCharType.cs @@ -51,9 +51,7 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return '\'' + value.ToString() + '\''; - } + => dialect.ToStringLiteral(value.ToString(), SqlType); // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml // attribute value is irrelevant to the method behavior. diff --git a/src/NHibernate/Type/AbstractDateTimeType.cs b/src/NHibernate/Type/AbstractDateTimeType.cs index 8f95323cb78..07c32a7ba8a 100644 --- a/src/NHibernate/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Type/AbstractDateTimeType.cs @@ -176,7 +176,7 @@ public override object FromStringValue(string xml) public override object DefaultValue => BaseDateValue; /// - public override string ObjectToSQLString(object value, Dialect.Dialect dialect) => - "'" + (DateTime) value + "'"; + public override string ObjectToSQLString(object value, Dialect.Dialect dialect) + => dialect.ToStringLiteral(((DateTime) value).ToString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/AbstractStringType.cs b/src/NHibernate/Type/AbstractStringType.cs index 9d47aaf07ff..72949c1093c 100644 --- a/src/NHibernate/Type/AbstractStringType.cs +++ b/src/NHibernate/Type/AbstractStringType.cs @@ -134,10 +134,9 @@ public object StringToObject(string xml) #region ILiteralType Members + /// public string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + (string)value + "'"; - } + => dialect.ToStringLiteral((string)value, SqlType); #endregion diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index 7c90bd6738a..c780427b2ae 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -54,7 +55,7 @@ public override string Name public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((byte)value).ToString(CultureInfo.InvariantCulture); } // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml diff --git a/src/NHibernate/Type/CharBooleanType.cs b/src/NHibernate/Type/CharBooleanType.cs index 9cde87c6697..c721640ef09 100644 --- a/src/NHibernate/Type/CharBooleanType.cs +++ b/src/NHibernate/Type/CharBooleanType.cs @@ -3,7 +3,6 @@ using System.Data.Common; using NHibernate.Engine; using NHibernate.SqlTypes; -using NHibernate.Util; namespace NHibernate.Type { @@ -57,9 +56,7 @@ private string ToCharacter(object value) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ToCharacter(value) + "'"; - } + => dialect.ToStringLiteral(ToCharacter(value), SqlType); // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml // attribute value is irrelevant to the method behavior. diff --git a/src/NHibernate/Type/DateTimeOffSetType.cs b/src/NHibernate/Type/DateTimeOffSetType.cs index 37837aec289..78a9c80661b 100644 --- a/src/NHibernate/Type/DateTimeOffSetType.cs +++ b/src/NHibernate/Type/DateTimeOffSetType.cs @@ -155,8 +155,6 @@ public override object FromStringValue(string xml) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((DateTimeOffset) value) + "'"; - } + => dialect.ToStringLiteral(((DateTimeOffset) value).ToString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/DateType.cs b/src/NHibernate/Type/DateType.cs index 76d3fbb99e9..1a3bac85c5c 100644 --- a/src/NHibernate/Type/DateType.cs +++ b/src/NHibernate/Type/DateType.cs @@ -93,8 +93,8 @@ public override string ToString(object val) => public override object DefaultValue => customBaseDate; /// - public override string ObjectToSQLString(object value, Dialect.Dialect dialect) => - "\'" + ((DateTime)value).ToShortDateString() + "\'"; + public override string ObjectToSQLString(object value, Dialect.Dialect dialect) + => dialect.ToStringLiteral(((DateTime) value).ToShortDateString(), SqlTypeFactory.GetAnsiString(50)); // Since v5 [Obsolete("Its only parameter, BaseValue, is obsolete.")] diff --git a/src/NHibernate/Type/DecimalType.cs b/src/NHibernate/Type/DecimalType.cs index 158fa028fc7..df6f0b60f4a 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 System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -66,7 +67,7 @@ public override object FromStringValue(string xml) public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((decimal)value).ToString(CultureInfo.InvariantCulture); } // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml diff --git a/src/NHibernate/Type/DoubleType.cs b/src/NHibernate/Type/DoubleType.cs index 4a8cf3406a9..b7df9359bb9 100644 --- a/src/NHibernate/Type/DoubleType.cs +++ b/src/NHibernate/Type/DoubleType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -66,7 +67,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((double)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/EnumCharType.cs b/src/NHibernate/Type/EnumCharType.cs index ece3684ff6f..d73490ff19e 100644 --- a/src/NHibernate/Type/EnumCharType.cs +++ b/src/NHibernate/Type/EnumCharType.cs @@ -171,8 +171,6 @@ public override object FromStringValue(string xml) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return '\'' + GetValue(value).ToString() + '\''; - } + => dialect.ToStringLiteral(GetValue(value).ToString(), SqlType); } } diff --git a/src/NHibernate/Type/GuidType.cs b/src/NHibernate/Type/GuidType.cs index a883f3a6b5a..70d26f1d950 100644 --- a/src/NHibernate/Type/GuidType.cs +++ b/src/NHibernate/Type/GuidType.cs @@ -88,7 +88,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return "'" + value + "'"; + return dialect.ToStringLiteral(value.ToString(), SqlTypeFactory.GetAnsiString(50)); } } } diff --git a/src/NHibernate/Type/Int16Type.cs b/src/NHibernate/Type/Int16Type.cs index f517be93424..af018c60ab0 100644 --- a/src/NHibernate/Type/Int16Type.cs +++ b/src/NHibernate/Type/Int16Type.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -114,7 +115,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((short)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index 9602842ae3b..2ec84eecf19 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -114,7 +115,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((int)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/Int64Type.cs b/src/NHibernate/Type/Int64Type.cs index 5bad9a7513b..64a6cf37a63 100644 --- a/src/NHibernate/Type/Int64Type.cs +++ b/src/NHibernate/Type/Int64Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -114,7 +115,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((long)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/SByteType.cs b/src/NHibernate/Type/SByteType.cs index 55021fb22a6..f3cbefa7503 100644 --- a/src/NHibernate/Type/SByteType.cs +++ b/src/NHibernate/Type/SByteType.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -116,7 +117,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((sbyte)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/SingleType.cs b/src/NHibernate/Type/SingleType.cs index 70ca434e04d..4d299bb1c17 100644 --- a/src/NHibernate/Type/SingleType.cs +++ b/src/NHibernate/Type/SingleType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -91,7 +92,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((float)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/TicksType.cs b/src/NHibernate/Type/TicksType.cs index 4fc18a007cd..bc82d101df8 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 System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -100,7 +101,7 @@ public override object Seed(ISessionImplementor session) /// public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((DateTime)value).Ticks.ToString() + '\''; + return '\'' + ((DateTime)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Type/TimeAsTimeSpanType.cs index e525ecfa555..fd7bd7058c7 100644 --- a/src/NHibernate/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Type/TimeAsTimeSpanType.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -141,7 +142,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((TimeSpan)value).Ticks.ToString() + '\''; + return '\'' + ((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeSpanType.cs b/src/NHibernate/Type/TimeSpanType.cs index 5ca576454b9..1ce300af06b 100644 --- a/src/NHibernate/Type/TimeSpanType.cs +++ b/src/NHibernate/Type/TimeSpanType.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -128,7 +129,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((TimeSpan)value).Ticks.ToString() + '\''; + return '\'' + ((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeType.cs b/src/NHibernate/Type/TimeType.cs index be487f81cff..b808619ae70 100644 --- a/src/NHibernate/Type/TimeType.cs +++ b/src/NHibernate/Type/TimeType.cs @@ -171,8 +171,6 @@ public override object DefaultValue } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((DateTime)value).ToShortTimeString() + "'"; - } + => dialect.ToStringLiteral(((DateTime) value).ToShortTimeString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/UInt16Type.cs b/src/NHibernate/Type/UInt16Type.cs index 10e9d15cd9b..90421392d8f 100644 --- a/src/NHibernate/Type/UInt16Type.cs +++ b/src/NHibernate/Type/UInt16Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -114,7 +115,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((ushort)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UInt32Type.cs b/src/NHibernate/Type/UInt32Type.cs index 0590278ef68..897dca99a19 100644 --- a/src/NHibernate/Type/UInt32Type.cs +++ b/src/NHibernate/Type/UInt32Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -114,7 +115,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((uint)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UInt64Type.cs b/src/NHibernate/Type/UInt64Type.cs index a902b6d46fe..5665a1077d1 100644 --- a/src/NHibernate/Type/UInt64Type.cs +++ b/src/NHibernate/Type/UInt64Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -113,7 +114,7 @@ public override object DefaultValue public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((ulong)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UriType.cs b/src/NHibernate/Type/UriType.cs index 68f319606d3..100c3704a35 100644 --- a/src/NHibernate/Type/UriType.cs +++ b/src/NHibernate/Type/UriType.cs @@ -84,9 +84,7 @@ public override object FromStringValue(string xml) } public string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((Uri)value).OriginalString + "'"; - } + => dialect.ToStringLiteral(((Uri) value).OriginalString, SqlType); /// public override object Assemble(object cached, ISessionImplementor session, object owner) diff --git a/src/NHibernate/nhibernate-configuration.xsd b/src/NHibernate/nhibernate-configuration.xsd index 08d922ad963..123b2c35e60 100644 --- a/src/NHibernate/nhibernate-configuration.xsd +++ b/src/NHibernate/nhibernate-configuration.xsd @@ -176,6 +176,14 @@ + + + + Indicates if the database needs to have backslash escaped in string literals. The default is + dialect dependent. + + + From a998c113e7323432962f47d15209d0eb7de5673a Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 3 Jul 2024 09:03:17 +1000 Subject: [PATCH 109/128] Remove usage of NHIBERNATE_BOT_TOKEN (#3574) --- .github/workflows/GenerateAsyncCode.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/GenerateAsyncCode.yml b/.github/workflows/GenerateAsyncCode.yml index 80a392b858c..38b0c0442de 100644 --- a/.github/workflows/GenerateAsyncCode.yml +++ b/.github/workflows/GenerateAsyncCode.yml @@ -5,7 +5,8 @@ on: paths: - '**.cs' -permissions: {} +permissions: + contents: write jobs: generate-async: @@ -16,7 +17,6 @@ jobs: with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} - token: ${{ secrets.NHIBERNATE_BOT_TOKEN }} - name: Setup .NET uses: actions/setup-dotnet@v4 From ac2ff3a0d0f3ef7385410f1d93f8dde63f2e1475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 4 Jul 2024 13:58:33 +0200 Subject: [PATCH 110/128] Release 5.4.9 (#3576) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 3c2d1bdc620..a04cab397a3 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.4 - 8 + 9 9.0 diff --git a/releasenotes.txt b/releasenotes.txt index 2351054af6c..56edaa06765 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,24 @@ -Build 5.4.8 +Build 5.4.9 +============================= + +Release notes - NHibernate - Version 5.4.9 + +6 issues were resolved in this release, including CVE-2024-39677. + +** Bug + + * #3547 Handle SQL injection vulnerabilities within ObjectToSQLString + +** Task + + * #3576 Release 5.4.9 + * #3558 Migrate AppVeyor & TC builds to PostgreSQL 13 + * #3545 Upgrade Npgsql to a non vulnerable version + * #3544 Upgrade vulnerable test dependencies + * #3517 Obsolete vulnerable literal AddColumn + + +Build 5.4.8 ============================= Release notes - NHibernate - Version 5.4.8 From 39de4d9efca7f653d31f9e04149a5700cfe9e72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sat, 6 Jul 2024 01:44:13 +0200 Subject: [PATCH 111/128] Release 5.5.2 (#3578) --- build-common/NHibernate.props | 2 +- releasenotes.txt | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index bc4739e47f0..0a732b0aafd 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -5,7 +5,7 @@ 5.5 2 - dev + 9.0 $(NhVersion).$(VersionPatch) diff --git a/releasenotes.txt b/releasenotes.txt index 52d539544dd..024a2a306d5 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,4 +1,21 @@ -Build 5.5.1 +Build 5.5.2 +============================= + +Release notes - NHibernate - Version 5.5.2 + +3 issues were resolved in this release, including CVE CVE-2024-39677 through the merge of 5.4.9. + +** Bug + + * #3536 MemberwiseClone should be virtual error in dotnet 9 preview 3 + +** Task + + * #3578 Release 5.5.1 + * #3577 Merge 5.4.9 into 5.5.x + + +Build 5.5.1 ============================= Release notes - NHibernate - Version 5.5.1 From c7b588e3783df86537eb6d007d5ac49af70b6035 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 09:53:15 +1000 Subject: [PATCH 112/128] Update dependency log4net to v2.0.17 (#3580) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index db0ac7e9409..d012f9c1302 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -62,7 +62,7 @@ - + From 9f3000750e04d02d6b565cab2a4b69dd9d9ef4fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:23:30 +1000 Subject: [PATCH 113/128] Update dependency NUnit.Analyzers to v4.2.0 (#3581) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index d012f9c1302..f5fa0f408b7 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -71,7 +71,7 @@ - + From d9c6ca825e812b1cdf2cf76fec55bd6e75a9be58 Mon Sep 17 00:00:00 2001 From: Evgeny Akhtimirov Date: Thu, 25 Jul 2024 01:51:02 +0300 Subject: [PATCH 114/128] Int32Type: avoid unnecessary boxing for common cases (#3513) --- src/NHibernate/Type/Int32Type.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index f5a63bf38a2..914b512c97e 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -31,8 +31,10 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi { try { - return rs[index] switch + var value = rs[index]; + return value switch { + int _ => value, BigInteger bi => (int) bi, var c => Convert.ToInt32(c) }; From 8a1b0848c3a521f1d99d48c1817487b9e514ec51 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 25 Jul 2024 08:52:55 +1000 Subject: [PATCH 115/128] Remove Microsoft.SourceLink.GitHub (#3590) --- src/NHibernate/NHibernate.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index d370a6fae08..e38db30c036 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -38,7 +38,6 @@ - From cc575618643cb54a422564803a3a3e038aef9995 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:54:07 +1000 Subject: [PATCH 116/128] Update dependency NUnit.Console to v3.18.1 (#3593) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Tools/packages.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/packages.csproj b/Tools/packages.csproj index 5ca61c1f8fc..aa216b9b04b 100644 --- a/Tools/packages.csproj +++ b/Tools/packages.csproj @@ -11,7 +11,7 @@ - + From b4f8b013f8848b082a9bd572d4af806db69d3b05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:24:13 +1000 Subject: [PATCH 117/128] Migrate renovate config (#3596) --- .github/renovate.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 595245c44b1..d788bcd927f 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -21,16 +21,16 @@ "groupName": "NUnit" }, { - "matchPackagePrefixes": [ - "Oracle.ManagedDataAccess" - ], - "groupName": "Oracle.ManagedDataAccess" + "groupName": "Oracle.ManagedDataAccess", + "matchPackageNames": [ + "Oracle.ManagedDataAccess{/,}**" + ] }, { - "matchPackagePrefixes": [ - "NHibernate.Caches" - ], - "groupName": "NHibernate.Caches" + "groupName": "NHibernate.Caches", + "matchPackageNames": [ + "NHibernate.Caches{/,}**" + ] } ] } From 26f8d351c9639cb6a9644a61968db868c55efbcd Mon Sep 17 00:00:00 2001 From: Lee Timmins Date: Sun, 1 Sep 2024 18:06:39 +0100 Subject: [PATCH 118/128] Fix empty dynamic components causing a phantom update (#3600) Fix #3421 --- .../Async/NHSpecificTest/GH3421/Fixture.cs | 109 ++++++++++++++++++ .../NHSpecificTest/GH3421/Entity.cs | 21 ++++ .../NHSpecificTest/GH3421/Fixture.cs | 97 ++++++++++++++++ src/NHibernate/Async/Type/ComponentType.cs | 16 --- src/NHibernate/Type/ComponentType.cs | 16 --- 5 files changed, 227 insertions(+), 32 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs new file mode 100644 index 00000000000..ed8822a4311 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// +// 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.Collections.Generic; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlCommand; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + using System.Threading.Tasks; + [TestFixture] + public class ByCodeFixtureAsync : TestCaseMappingByCode + { + private SqlInterceptor _interceptor; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Component(x => x.Attributes, new { + Sku = (string)null + }, dc => { + dc.Property(x => x.Sku); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + base.Configure(configuration); + + _interceptor = new SqlInterceptor(); + + configuration.SetInterceptor(_interceptor); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally", Attributes = new Dictionary() { + { "Sku", "AAA" } + } }; + session.Save(e2); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from Entity").ExecuteUpdate(); + transaction.Commit(); + } + } + + [Test] + public async Task TestFlushDoesNotTriggerAnUpdateAsync() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var foo = await (session.Query().ToListAsync()); + + await (session.FlushAsync()); + + var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList(); + + Assert.That(updateStatements, Has.Count.EqualTo(0)); + } + } + + public class SqlInterceptor : EmptyInterceptor + { + public IList SqlStatements = new List(); + + public override SqlString OnPrepareStatement(SqlString sql) + { + SqlStatements.Add(sql); + + return base.OnPrepareStatement(sql); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs new file mode 100644 index 00000000000..e208abe904c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + + private IDictionary _attributes; + public virtual IDictionary Attributes { + get { + if (_attributes == null) + _attributes = new Dictionary(); + return _attributes; + } + set => _attributes = value; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs new file mode 100644 index 00000000000..4fe7cc67954 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlCommand; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + [TestFixture] + public class ByCodeFixture : TestCaseMappingByCode + { + private SqlInterceptor _interceptor; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Component(x => x.Attributes, new { + Sku = (string)null + }, dc => { + dc.Property(x => x.Sku); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + base.Configure(configuration); + + _interceptor = new SqlInterceptor(); + + configuration.SetInterceptor(_interceptor); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally", Attributes = new Dictionary() { + { "Sku", "AAA" } + } }; + session.Save(e2); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from Entity").ExecuteUpdate(); + transaction.Commit(); + } + } + + [Test] + public void TestFlushDoesNotTriggerAnUpdate() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var foo = session.Query().ToList(); + + session.Flush(); + + var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList(); + + Assert.That(updateStatements, Has.Count.EqualTo(0)); + } + } + + public class SqlInterceptor : EmptyInterceptor + { + public IList SqlStatements = new List(); + + public override SqlString OnPrepareStatement(SqlString sql) + { + SqlStatements.Add(sql); + + return base.OnPrepareStatement(sql); + } + } + } +} diff --git a/src/NHibernate/Async/Type/ComponentType.cs b/src/NHibernate/Async/Type/ComponentType.cs index 999852e447b..6757e22216f 100644 --- a/src/NHibernate/Async/Type/ComponentType.cs +++ b/src/NHibernate/Async/Type/ComponentType.cs @@ -33,14 +33,6 @@ public override async Task IsDirtyAsync(object x, object y, ISessionImplem { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); for (int i = 0; i < xvalues.Length; i++) @@ -60,14 +52,6 @@ public override async Task IsDirtyAsync(object x, object y, bool[] checkab { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); int loc = 0; diff --git a/src/NHibernate/Type/ComponentType.cs b/src/NHibernate/Type/ComponentType.cs index cf9cdbf552b..3c3ffe9d2d8 100644 --- a/src/NHibernate/Type/ComponentType.cs +++ b/src/NHibernate/Type/ComponentType.cs @@ -156,14 +156,6 @@ public override bool IsDirty(object x, object y, ISessionImplementor session) { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); for (int i = 0; i < xvalues.Length; i++) @@ -182,14 +174,6 @@ public override bool IsDirty(object x, object y, bool[] checkable, ISessionImple { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); int loc = 0; From 095e557c044e171eeb87e548eeef7c93088c0cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:17:48 +0200 Subject: [PATCH 119/128] Allow deriving from DynamicMapEntityTuplizer (#3603) fix #3602 --- src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs b/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs index 07abc64fce3..c926bd60d9e 100644 --- a/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs +++ b/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs @@ -13,7 +13,7 @@ public class DynamicMapEntityTuplizer : AbstractEntityTuplizer { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(PocoEntityTuplizer)); - internal DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) + public DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) : base(entityMetamodel, mappingInfo) { // NH different behavior fo NH-1587 From 894529983457c110f2934904f27e2c3e9398c581 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:38:46 +0200 Subject: [PATCH 120/128] Update dependency NUnit3TestAdapter to 4.6.0 (#3594) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../NHibernate.Test.VisualBasic.vbproj | 2 +- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- .../NHibernate.TestDatabaseSetup.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index e720221f895..5ea684f06b2 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -28,7 +28,7 @@ - + diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index f5fa0f408b7..3c540103775 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -72,7 +72,7 @@ - + diff --git a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj index 715af02ffb3..f9a3cb308a7 100644 --- a/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj +++ b/src/NHibernate.TestDatabaseSetup/NHibernate.TestDatabaseSetup.csproj @@ -16,7 +16,7 @@ - + From a591fb5c4d13acf3dc43e2c02ffb92a7c749441d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:36:32 +0100 Subject: [PATCH 121/128] Update dependency gitreleasemanager.tool to 0.18.0 (#3619) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 338a0f24652..ee996697750 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "gitreleasemanager.tool": { - "version": "0.17.0", + "version": "0.18.0", "commands": [ "dotnet-gitreleasemanager" ] From 0c9e4421933b613676913a312926eeb1ee673142 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:10:20 +1000 Subject: [PATCH 122/128] Update dependency log4net to v3 (#3612) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 3c540103775..5bae7bee13b 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -62,7 +62,7 @@ - + From f5a7a1f87760dddd0ffb6fd5771510f8be07f128 Mon Sep 17 00:00:00 2001 From: wvopt Date: Tue, 14 Jan 2025 19:52:25 +0100 Subject: [PATCH 123/128] Fix version update on dirty collection with another property having optimistic-lock false (#3632) Co-authored-by: CSharper2010 --- .../Async/VersionTest/Db/DbVersionFixture.cs | 1 + .../VersionTest/Db/DbVersionFixture.cs | 1 + src/NHibernate.Test/VersionTest/Db/User.cs | 4 ++- .../VersionTest/Db/User.hbm.xml | 5 ++-- .../DefaultFlushEntityEventListener.cs | 30 ++++++++++--------- .../DefaultFlushEntityEventListener.cs | 20 ++++++++----- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs b/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs index fe5a770c4c9..b3ec27add5f 100644 --- a/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs +++ b/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs @@ -52,6 +52,7 @@ public async System.Threading.Tasks.Task CollectionVersionAsync() admin = await (s.GetAsync(admin.Id)); guy.Groups.Add(admin); admin.Users.Add(guy); + guy.NoOptimisticLock = "changed"; await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs b/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs index c5c50b96ab8..7e22a859145 100644 --- a/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs +++ b/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs @@ -42,6 +42,7 @@ public void CollectionVersion() admin = s.Get(admin.Id); guy.Groups.Add(admin); admin.Users.Add(guy); + guy.NoOptimisticLock = "changed"; t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/VersionTest/Db/User.cs b/src/NHibernate.Test/VersionTest/Db/User.cs index 6dc9368c55f..ad0aafb833b 100644 --- a/src/NHibernate.Test/VersionTest/Db/User.cs +++ b/src/NHibernate.Test/VersionTest/Db/User.cs @@ -11,8 +11,10 @@ public class User public virtual string Username { get; set; } + public virtual string NoOptimisticLock { get; set; } + public virtual ISet Groups { get; set; } public virtual ISet Permissions { get; set; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/VersionTest/Db/User.hbm.xml b/src/NHibernate.Test/VersionTest/Db/User.hbm.xml index b809ccc8c72..1dfc4080a07 100644 --- a/src/NHibernate.Test/VersionTest/Db/User.hbm.xml +++ b/src/NHibernate.Test/VersionTest/Db/User.hbm.xml @@ -1,4 +1,4 @@ - +