From 4decb54bd7aa8b2ba3c99e1f5b4bf3d81fcad2d7 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 23 Dec 2021 14:06:18 +0200 Subject: [PATCH 1/7] Do not set guessed type as expected parameter type in LINQ --- .../NHSpecificTest/NH3565/FixtureByCode.cs | 121 ++++++++++++++++++ .../NHSpecificTest/NH3565/Entity.cs | 10 ++ .../NHSpecificTest/NH3565/FixtureByCode.cs | 109 ++++++++++++++++ src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs | 29 ++++- src/NHibernate/Linq/DefaultQueryProvider.cs | 6 +- .../Linq/Functions/StringGenerator.cs | 3 +- .../Linq/Visitors/ParameterTypeLocator.cs | 32 +---- 7 files changed, 277 insertions(+), 33 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/NH3565/FixtureByCode.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3565/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3565/FixtureByCode.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3565/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3565/FixtureByCode.cs new file mode 100644 index 00000000000..07047559dcc --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3565/FixtureByCode.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.Data; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.NH3565 +{ + using System.Threading.Tasks; + [TestFixture] + public class ByCodeFixtureAsync : 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.Type(NHibernateUtil.AnsiString); + m.Length(10); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return base.AppliesTo(dialect) + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + && Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)); + } + + 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 void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public async Task ParameterTypeForLikeIsProperlyDetectedAsync() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where NHibernate.Linq.SqlMethods.Like(e.Name, "Bob") + select e; + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + + [KnownBug("Not fixed yet")] + [Test] + public async Task ParameterTypeForContainsIsProperlyDetectedAsync() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where e.Name.Contains("Bob") + select e; + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + + [KnownBug("Not fixed yet")] + [Test] + public async Task ParameterTypeForStartsWithIsProperlyDetectedAsync() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where e.Name.StartsWith("Bob") + select e; + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3565/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3565/Entity.cs new file mode 100644 index 00000000000..4cc0a2c4513 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3565/Entity.cs @@ -0,0 +1,10 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.NH3565 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3565/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/NH3565/FixtureByCode.cs new file mode 100644 index 00000000000..f683293d591 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3565/FixtureByCode.cs @@ -0,0 +1,109 @@ +using System.Data; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3565 +{ + [TestFixture] + public class ByCodeFixture : 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.Type(NHibernateUtil.AnsiString); + m.Length(10); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return base.AppliesTo(dialect) + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + && Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)); + } + + 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 void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public void ParameterTypeForLikeIsProperlyDetected() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where NHibernate.Linq.SqlMethods.Like(e.Name, "Bob") + select e; + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + + [KnownBug("Not fixed yet")] + [Test] + public void ParameterTypeForContainsIsProperlyDetected() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where e.Name.Contains("Bob") + select e; + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + + [KnownBug("Not fixed yet")] + [Test] + public void ParameterTypeForStartsWithIsProperlyDetected() + { + using (var logSpy = new SqlLogSpy()) + using (var session = OpenSession()) + { + var result = from e in session.Query() + where e.Name.StartsWith("Bob") + select e; + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + Assert.That(logSpy.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } + } +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs index c48fd3aa248..93a62499634 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs @@ -29,17 +29,38 @@ public override IType DataType if (ExpectedType != null) return ExpectedType; - foreach (var node in GetResultNodes()) + if (base.DataType != null) + return base.DataType; + + var dataType = GetTypeFromResultNodes(); + + foreach (var node in GetResultNodes().OfType()) { - if (node is ISelectExpression select && !(node is ParameterNode)) - return select.DataType; + if (node.DataType == null && node is IExpectedTypeAwareNode typeAwareNode) + { + typeAwareNode.ExpectedType = dataType; + } } - throw new HibernateException("Unable to determine data type of CASE statement."); + base.DataType = dataType; + return dataType; } set { base.DataType = value; } } + private IType GetTypeFromResultNodes() + { + foreach (var node in GetResultNodes()) + { + if (node is ISelectExpression select && select.DataType != null) + { + return select.DataType; + } + } + + throw new HibernateException("Unable to determine data type of CASE statement."); + } + public IEnumerable GetResultNodes() { for (int i = 0; i < ChildCount; i++) diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index 912b640a951..a3c32091e78 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -265,7 +265,11 @@ private static void SetParameters(IQuery query, IDictionary constantExpressions, ConstantTypeLocatorVisitor visitor, NamedParameter namedParameter, - out bool tryProcessInHql) + out bool isGuessedType) { - tryProcessInHql = false; + isGuessedType = false; // All constant expressions have the same type/value var constantExpression = constantExpressions.First(); var constantType = constantExpression.Type.UnwrapIfNullable(); @@ -159,10 +159,7 @@ private static IType GetParameterType( return candidateType; } - if (visitor.NotGuessableConstants.Contains(constantExpression) && constantExpression.Value != null) - { - tryProcessInHql = true; - } + isGuessedType = true; // No related MemberExpressions was found, guess the type by value or its type when null. // When a numeric parameter is compared to different columns with different types (e.g. Where(o => o.Single >= singleParam || o.Double <= singleParam)) @@ -174,13 +171,10 @@ private static IType GetParameterType( private class ConstantTypeLocatorVisitor : RelinqExpressionVisitor { - private bool _hqlGenerator; private readonly bool _removeMappedAsCalls; private readonly System.Type _targetType; private readonly IDictionary _parameters; private readonly ISessionFactoryImplementor _sessionFactory; - private readonly ILinqToHqlGeneratorsRegistry _functionRegistry; - public readonly HashSet NotGuessableConstants = new HashSet(); public readonly Dictionary ConstantExpressions = new Dictionary(); public readonly Dictionary> ParameterConstants = @@ -198,7 +192,6 @@ public ConstantTypeLocatorVisitor( _targetType = targetType; _sessionFactory = sessionFactory; _parameters = parameters; - _functionRegistry = sessionFactory.Settings.LinqToHqlGeneratorsRegistry; } protected override Expression VisitBinary(BinaryExpression node) @@ -269,16 +262,6 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return node; } - // For hql method generators we do not want to guess the parameter type here, let hql logic figure it out. - if (_functionRegistry.TryGetGenerator(node.Method, out _)) - { - var origHqlGenerator = _hqlGenerator; - _hqlGenerator = true; - var expression = base.VisitMethodCall(node); - _hqlGenerator = origHqlGenerator; - return expression; - } - return base.VisitMethodCall(node); } @@ -289,11 +272,6 @@ protected override Expression VisitConstant(ConstantExpression node) return node; } - if (_hqlGenerator) - { - NotGuessableConstants.Add(node); - } - RelatedExpressions.Add(node, new HashSet()); ConstantExpressions.Add(node, null); if (!ParameterConstants.TryGetValue(param, out var set)) From bf03f5a2078e43ce3632dc625ea684d39e960958 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 23 Dec 2021 17:38:50 +0200 Subject: [PATCH 2/7] Avoid double param type guessing and better NULL parameter handling --- src/NHibernate/IQuery.cs | 13 +++++ src/NHibernate/Impl/AbstractQueryImpl.cs | 60 ++++++++++----------- src/NHibernate/Linq/DefaultQueryProvider.cs | 25 +++++++++ 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/src/NHibernate/IQuery.cs b/src/NHibernate/IQuery.cs index 4a8d062415a..a223c42c93f 100644 --- a/src/NHibernate/IQuery.cs +++ b/src/NHibernate/IQuery.cs @@ -6,6 +6,19 @@ namespace NHibernate { + // 6.0 TODO add to IQuery + internal interface IQueryNextVer : IQuery + { + /// + /// Bind a value to a named query parameter + /// + /// The name of the parameter + /// The possibly null parameter value + /// The NHibernate . + /// If true supplied type is used only if parameter metadata is missing + IQuery SetParameter(string name, object val, IType type, bool preferMetadataType); + } + /// /// An object-oriented representation of a NHibernate query. /// diff --git a/src/NHibernate/Impl/AbstractQueryImpl.cs b/src/NHibernate/Impl/AbstractQueryImpl.cs index ba46b665466..294fe22b515 100644 --- a/src/NHibernate/Impl/AbstractQueryImpl.cs +++ b/src/NHibernate/Impl/AbstractQueryImpl.cs @@ -19,7 +19,7 @@ namespace NHibernate.Impl /// /// Abstract implementation of the IQuery interface. /// - public abstract partial class AbstractQueryImpl : IQuery + public abstract partial class AbstractQueryImpl : IQuery, IQueryNextVer { private readonly string queryString; protected readonly ISessionImplementor session; @@ -242,17 +242,33 @@ public IQuery SetParameter(int position, object val, IType type) public IQuery SetParameter(string name, object val, IType type) { - if (!parameterMetadata.NamedParameterNames.Contains(name)) - { - if (shouldIgnoredUnknownNamedParameters)//just ignore it - return this; - throw new ArgumentException("Parameter " + name + " does not exist as a named parameter in [" + QueryString + "]"); - } - else - { - namedParameters[name] = new TypedValue(type, val, false); + return SetParameter(name, val, type, false); + } + + //TODO 6.0: Add to IQuery interface + public IQuery SetParameter(string name, object val, IType type, bool preferMetadataType) + { + if (CheckParameterIgnored(name)) return this; + + if (type == null || preferMetadataType) + { + type = parameterMetadata.GetNamedParameterExpectedType(name) ?? type ?? ParameterHelper.GuessType(val, session.Factory); } + + namedParameters[name] = new TypedValue(type, val, false); + return this; + } + + private bool CheckParameterIgnored(string name) + { + if (parameterMetadata.NamedParameterNames.Contains(name)) + return false; + + if (shouldIgnoredUnknownNamedParameters) //just ignore it + return true; + + throw new ArgumentException("Parameter " + name + " does not exist as a named parameter in [" + QueryString + "]"); } public IQuery SetParameter(int position, T val) @@ -289,29 +305,7 @@ public IQuery SetParameter(string name, T val) public IQuery SetParameter(string name, object val) { - if (!parameterMetadata.NamedParameterNames.Contains(name)) - { - if (shouldIgnoredUnknownNamedParameters)//just ignore it - return this; - } - - if (val == null) - { - IType type = parameterMetadata.GetNamedParameterExpectedType(name); - if (type == null) - { - throw new ArgumentNullException("val", - "A type specific Set(name, val) should be called because the Type can not be guessed from a null value."); - } - - SetParameter(name, val, type); - } - else - { - SetParameter(name, val, DetermineType(name, val)); - } - - return this; + return SetParameter(name, val, null, true); } public IQuery SetParameter(int position, object val) diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index a3c32091e78..42adaa7e843 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -253,8 +253,14 @@ protected virtual object ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery #pragma warning restore 618 } + //TODO 6.0: Remove private static void SetParameters(IQuery query, IDictionary parameters) { + if (query is IQueryNextVer impl) + { + SetParameters(impl, parameters); + return; + } foreach (var parameterName in query.NamedParameters) { // The parameter type will be taken from the parameter metadata @@ -274,6 +280,25 @@ private static void SetParameters(IQuery query, IDictionary parameters) + private static void SetParameters(IQueryNextVer query, IDictionary parameters) + { + foreach (var parameterName in query.NamedParameters) + { + // The parameter type will be taken from the parameter metadata + var parameter = parameters[parameterName]; + if (parameter.IsCollection) + { + query.SetParameterList(parameter.Name, (IEnumerable) parameter.Value); + } + else + { + query.SetParameter(parameter.Name, parameter.Value, parameter.Type, parameter.IsGuessedType); + } + } + } + public virtual void SetResultTransformerAndAdditionalCriteria(IQuery query, NhLinqExpression nhExpression, IDictionary> parameters) { if (nhExpression.ExpressionToHqlTranslationResults != null) From b6b78caa5638a862792cd4946037d76ed617433b Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 24 Dec 2021 15:01:22 +0200 Subject: [PATCH 3/7] async regen --- src/NHibernate/Async/IQuery.cs | 1 + src/NHibernate/Async/Impl/AbstractQueryImpl.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NHibernate/Async/IQuery.cs b/src/NHibernate/Async/IQuery.cs index 31912e9ae7d..076d73e9a2b 100644 --- a/src/NHibernate/Async/IQuery.cs +++ b/src/NHibernate/Async/IQuery.cs @@ -18,6 +18,7 @@ namespace NHibernate { using System.Threading.Tasks; using System.Threading; + public partial interface IQuery { diff --git a/src/NHibernate/Async/Impl/AbstractQueryImpl.cs b/src/NHibernate/Async/Impl/AbstractQueryImpl.cs index 24588054de3..321cb6c9477 100644 --- a/src/NHibernate/Async/Impl/AbstractQueryImpl.cs +++ b/src/NHibernate/Async/Impl/AbstractQueryImpl.cs @@ -26,7 +26,7 @@ namespace NHibernate.Impl { - public abstract partial class AbstractQueryImpl : IQuery + public abstract partial class AbstractQueryImpl : IQuery, IQueryNextVer { #region Execution methods From 4813b407f51a5d3bf7bf8b2c01a4b951f31c5955 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 11 Aug 2022 19:06:41 +0300 Subject: [PATCH 4/7] Minimize changes --- src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs | 29 +++---------------- .../Linq/Functions/StringGenerator.cs | 3 +- .../Linq/Visitors/ParameterTypeLocator.cs | 11 ++++--- 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs index 93a62499634..c48fd3aa248 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/CaseNode.cs @@ -29,38 +29,17 @@ public override IType DataType if (ExpectedType != null) return ExpectedType; - if (base.DataType != null) - return base.DataType; - - var dataType = GetTypeFromResultNodes(); - - foreach (var node in GetResultNodes().OfType()) + foreach (var node in GetResultNodes()) { - if (node.DataType == null && node is IExpectedTypeAwareNode typeAwareNode) - { - typeAwareNode.ExpectedType = dataType; - } + if (node is ISelectExpression select && !(node is ParameterNode)) + return select.DataType; } - base.DataType = dataType; - return dataType; + throw new HibernateException("Unable to determine data type of CASE statement."); } set { base.DataType = value; } } - private IType GetTypeFromResultNodes() - { - foreach (var node in GetResultNodes()) - { - if (node is ISelectExpression select && select.DataType != null) - { - return select.DataType; - } - } - - throw new HibernateException("Unable to determine data type of CASE statement."); - } - public IEnumerable GetResultNodes() { for (int i = 0; i < ChildCount; i++) diff --git a/src/NHibernate/Linq/Functions/StringGenerator.cs b/src/NHibernate/Linq/Functions/StringGenerator.cs index 82b073c07fc..7bf9c78ebce 100644 --- a/src/NHibernate/Linq/Functions/StringGenerator.cs +++ b/src/NHibernate/Linq/Functions/StringGenerator.cs @@ -217,8 +217,7 @@ public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, { var expression = visitor.Visit(targetObject).AsExpression(); var index = treeBuilder.Add(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Constant(1)); - - return treeBuilder.TransparentCast(treeBuilder.MethodCall("substring", expression, index, treeBuilder.Constant(1)), typeof(char)); + return treeBuilder.MethodCall("substring", expression, index, treeBuilder.Constant(1)); } } diff --git a/src/NHibernate/Linq/Visitors/ParameterTypeLocator.cs b/src/NHibernate/Linq/Visitors/ParameterTypeLocator.cs index de566f81e6e..496ac526e8e 100644 --- a/src/NHibernate/Linq/Visitors/ParameterTypeLocator.cs +++ b/src/NHibernate/Linq/Visitors/ParameterTypeLocator.cs @@ -93,8 +93,8 @@ internal static void SetParameterTypes( continue; } - namedParameter.Type = GetParameterType(sessionFactory, constantExpressions, visitor, namedParameter, out var isGuessedType); - namedParameter.IsGuessedType = isGuessedType; + namedParameter.Type = GetParameterType(sessionFactory, constantExpressions, visitor, namedParameter, out var tryProcessInHql); + namedParameter.IsGuessedType = tryProcessInHql; } } @@ -147,9 +147,9 @@ private static IType GetParameterType( HashSet constantExpressions, ConstantTypeLocatorVisitor visitor, NamedParameter namedParameter, - out bool isGuessedType) + out bool tryProcessInHql) { - isGuessedType = false; + tryProcessInHql = false; // All constant expressions have the same type/value var constantExpression = constantExpressions.First(); var constantType = constantExpression.Type.UnwrapIfNullable(); @@ -161,8 +161,7 @@ private static IType GetParameterType( // Leave hql logic to determine the type except when the value is a char. Hql logic detects a char as a string, which causes an exception // when trying to set a string db parameter with a char value. - isGuessedType = !(constantExpression.Value is char); - + tryProcessInHql = !(constantExpression.Value is char); // No related MemberExpressions was found, guess the type by value or its type when null. // When a numeric parameter is compared to different columns with different types (e.g. Where(o => o.Single >= singleParam || o.Double <= singleParam)) // do not change the parameter type, but instead cast the parameter when comparing with different column types. From 59a532bd73724410eb4a40f6020368055e3850ee Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 25 Aug 2022 23:19:52 +1200 Subject: [PATCH 5/7] Replace IQueryNextVer with an extension method --- .../Async/Impl/AbstractQueryImpl.cs | 2 +- src/NHibernate/IQuery.cs | 23 +++++++++++++-- src/NHibernate/Impl/AbstractQueryImpl.cs | 2 +- src/NHibernate/Linq/DefaultQueryProvider.cs | 29 ------------------- 4 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/NHibernate/Async/Impl/AbstractQueryImpl.cs b/src/NHibernate/Async/Impl/AbstractQueryImpl.cs index 321cb6c9477..24588054de3 100644 --- a/src/NHibernate/Async/Impl/AbstractQueryImpl.cs +++ b/src/NHibernate/Async/Impl/AbstractQueryImpl.cs @@ -26,7 +26,7 @@ namespace NHibernate.Impl { - public abstract partial class AbstractQueryImpl : IQuery, IQueryNextVer + public abstract partial class AbstractQueryImpl : IQuery { #region Execution methods diff --git a/src/NHibernate/IQuery.cs b/src/NHibernate/IQuery.cs index a223c42c93f..f6afc6dafa1 100644 --- a/src/NHibernate/IQuery.cs +++ b/src/NHibernate/IQuery.cs @@ -3,20 +3,36 @@ using NHibernate.Transform; using NHibernate.Type; using System.Collections.Generic; +using NHibernate.Impl; namespace NHibernate { - // 6.0 TODO add to IQuery - internal interface IQueryNextVer : IQuery + // 6.0 TODO remove + internal static class QueryExtensions { /// /// Bind a value to a named query parameter /// + /// The query /// The name of the parameter /// The possibly null parameter value /// The NHibernate . /// If true supplied type is used only if parameter metadata is missing - IQuery SetParameter(string name, object val, IType type, bool preferMetadataType); + public static void SetParameter(this IQuery query, string name, object val, IType type, bool preferMetadataType) + { + if (query is AbstractQueryImpl impl) + { + impl.SetParameter(name, val, type, preferMetadataType); + } + else + { + //Let HQL try to process guessed types (hql doesn't support type guessing for NULL) + if (type != null && (preferMetadataType == false || val == null)) + query.SetParameter(name, val, type); + else + query.SetParameter(name, val); + } + } } /// @@ -677,4 +693,5 @@ public partial interface IQuery /// IFutureValue FutureValue(); } + } diff --git a/src/NHibernate/Impl/AbstractQueryImpl.cs b/src/NHibernate/Impl/AbstractQueryImpl.cs index 294fe22b515..79b7c721d6b 100644 --- a/src/NHibernate/Impl/AbstractQueryImpl.cs +++ b/src/NHibernate/Impl/AbstractQueryImpl.cs @@ -19,7 +19,7 @@ namespace NHibernate.Impl /// /// Abstract implementation of the IQuery interface. /// - public abstract partial class AbstractQueryImpl : IQuery, IQueryNextVer + public abstract partial class AbstractQueryImpl : IQuery { private readonly string queryString; protected readonly ISessionImplementor session; diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index 42adaa7e843..cb1e84c41a6 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -253,36 +253,7 @@ protected virtual object ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery #pragma warning restore 618 } - //TODO 6.0: Remove private static void SetParameters(IQuery query, IDictionary parameters) - { - if (query is IQueryNextVer impl) - { - SetParameters(impl, parameters); - return; - } - foreach (var parameterName in query.NamedParameters) - { - // The parameter type will be taken from the parameter metadata - var parameter = parameters[parameterName]; - if (parameter.IsCollection) - { - query.SetParameterList(parameter.Name, (IEnumerable) parameter.Value); - } - else - { - //Let HQL try to process guessed types (hql doesn't support type guessing for NULL) - if (parameter.Type != null && (parameter.IsGuessedType == false || parameter.Value == null)) - query.SetParameter(parameter.Name, parameter.Value, parameter.Type); - else - query.SetParameter(parameter.Name, parameter.Value); - } - } - } - - //TODO 6.0: Replace with - //private static void SetParameters(IQuery query, IDictionary parameters) - private static void SetParameters(IQueryNextVer query, IDictionary parameters) { foreach (var parameterName in query.NamedParameters) { From b0486ae06fc867e097fdac68ca02e4c216919d09 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 25 Aug 2022 23:21:52 +1200 Subject: [PATCH 6/7] Code cleanup --- src/NHibernate/IQuery.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NHibernate/IQuery.cs b/src/NHibernate/IQuery.cs index f6afc6dafa1..72e03de07e0 100644 --- a/src/NHibernate/IQuery.cs +++ b/src/NHibernate/IQuery.cs @@ -693,5 +693,4 @@ public partial interface IQuery /// IFutureValue FutureValue(); } - } From fcb6ec3d1159418ba8fb9025499301a2f1215601 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 25 Aug 2022 11:25:09 +0000 Subject: [PATCH 7/7] Generate async files --- src/NHibernate/Async/IQuery.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate/Async/IQuery.cs b/src/NHibernate/Async/IQuery.cs index 076d73e9a2b..74f06cb2eae 100644 --- a/src/NHibernate/Async/IQuery.cs +++ b/src/NHibernate/Async/IQuery.cs @@ -13,6 +13,7 @@ using NHibernate.Transform; using NHibernate.Type; using System.Collections.Generic; +using NHibernate.Impl; namespace NHibernate {