diff --git a/src/AsyncGenerator.yml b/src/AsyncGenerator.yml
index 68ae0a1c735..99c765a110c 100644
--- a/src/AsyncGenerator.yml
+++ b/src/AsyncGenerator.yml
@@ -110,6 +110,10 @@
- conversion: Ignore
name: GetEnumerator
containingTypeName: IFutureEnumerable
+# TODO 6.0: Consider if ComputeFlattenedParameters should remain ignored or not
+ - conversion: Ignore
+ name: ComputeFlattenedParameters
+ containingTypeName: SqlQueryImpl
- conversion: ToAsync
name: ExecuteReader
containingTypeName: IBatcher
diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3079/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3079/Fixture.cs
new file mode 100644
index 00000000000..e9980e3a398
--- /dev/null
+++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3079/Fixture.cs
@@ -0,0 +1,246 @@
+//------------------------------------------------------------------------------
+//
+// 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 NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ using System.Threading.Tasks;
+ [TestFixture]
+ public class FixtureAsync : BugTestCase
+ {
+ // Disable second level cache
+ protected override string CacheConcurrencyStrategy => null;
+
+ protected override void OnTearDown()
+ {
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ s.CreateQuery("delete from Employment").ExecuteUpdate();
+
+ s.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+ t.Commit();
+ }
+ }
+
+ protected override void OnSetUp()
+ {
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ var personList = new List();
+ var employerList = new List();
+
+ // Global id to avoid false positive assertion with positional parameter
+ var gId = 1;
+
+ for (var i = 0; i < 3; i++)
+ {
+ var personCpId = new PersonCpId { IdA = gId++, IdB = gId++ };
+ var personObj = new Person
+ { CpId = personCpId, Name = "PERSON_" + personCpId.IdA + "_" + personCpId.IdB };
+ s.Save(personObj);
+ personList.Add(personObj);
+ }
+
+ for (var i = 0; i < 3; i++)
+ {
+ var employerCpId = new EmployerCpId { IdA = gId++, IdB = gId++ };
+ var employerObj = new Employer
+ { CpId = employerCpId, Name = "EMPLOYER_" + employerCpId.IdA + "_" + employerCpId.IdB };
+ s.Save(employerObj);
+ employerList.Add(employerObj);
+ }
+
+ var employmentIds = new[]
+ {
+ gId++,
+ gId++,
+ gId++,
+ gId++,
+ };
+ var employmentNames = new[]
+ {
+ //P1 + E1
+ "EMPLOYMENT_" + employmentIds[0] + "_" +
+ personList[0].CpId.IdA + "_" + personList[0].CpId.IdA + "_" +
+ employerList[0].CpId.IdA + "_" + employerList[0].CpId.IdB,
+ //P1 + E2
+ "EMPLOYMENT_" + employmentIds[1] + "_" +
+ personList[0].CpId.IdA + "_" + personList[0].CpId.IdA + "_" +
+ employerList[1].CpId.IdA + "_" + employerList[1].CpId.IdB,
+ //P2 + E2
+ "EMPLOYMENT_" + employmentIds[2] + "_" +
+ personList[1].CpId.IdA + "_" + personList[1].CpId.IdA + "_" +
+ employerList[1].CpId.IdA + "_" + employerList[1].CpId.IdB,
+ //P2 + E3
+ "EMPLOYMENT_" + employmentIds[2] + "_" +
+ personList[1].CpId.IdA + "_" + personList[1].CpId.IdA + "_" +
+ employerList[2].CpId.IdA + "_" + employerList[2].CpId.IdB
+ };
+ var employmentPersons = new[]
+ {
+ personList[0],
+ personList[0],
+ personList[1],
+ personList[1]
+ };
+ var employmentEmployers = new[]
+ {
+ employerList[0],
+ employerList[1],
+ employerList[1],
+ employerList[2]
+ };
+
+ for (var k = 0; k < employmentIds.Length; k++)
+ {
+ var employmentCpId = new EmploymentCpId
+ {
+ Id = employmentIds[k],
+ PersonObj = employmentPersons[k],
+ EmployerObj = employmentEmployers[k]
+ };
+ var employmentObj = new Employment { CpId = employmentCpId, Name = employmentNames[k] };
+ s.Save(employmentObj);
+ }
+
+ for (var i = 0; i < 3; i++)
+ {
+ var personNoComponentObj = new PersonNoComponent { IdA = gId++, IdB = gId++ };
+ personNoComponentObj.Name = "PERSON_NO_COMPONENT_" + personNoComponentObj.IdA + "_" +
+ personNoComponentObj.IdB;
+ s.Save(personNoComponentObj);
+ }
+
+ t.Commit();
+ }
+ }
+
+ // Test reproducing the problem.
+ [Test]
+ public async Task GetPersonTestAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var person1_2 = await (session.GetAsync(new PersonCpId { IdA = 1, IdB = 2 }));
+ Assert.That(person1_2.Name, Is.EqualTo("PERSON_1_2"));
+ Assert.That(
+ person1_2.EmploymentList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "EMPLOYMENT_13_1_1_7_8", "EMPLOYMENT_14_1_1_9_10" }));
+ }
+ }
+
+ // Test reproducing the problem.
+ [Test]
+ public async Task GetEmployerTestAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var employer7_8 = await (session.GetAsync(new EmployerCpId { IdA = 7, IdB = 8 }));
+ Assert.That(employer7_8.Name, Is.EqualTo("EMPLOYER_7_8"));
+ Assert.That(
+ employer7_8.EmploymentList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "EMPLOYMENT_13_1_1_7_8" }));
+ }
+ }
+
+ [Test]
+ public async Task GetEmploymentTestAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var employment_13_1_2_7_8 =
+ await (session.GetAsync(
+ new EmploymentCpId
+ {
+ Id = 13,
+ PersonObj =
+ new Person
+ {
+ CpId = new PersonCpId { IdA = 1, IdB = 2 }
+ },
+ EmployerObj =
+ new Employer
+ {
+ CpId = new EmployerCpId { IdA = 7, IdB = 8 }
+ }
+ }));
+ Assert.That(employment_13_1_2_7_8.Name, Is.EqualTo("EMPLOYMENT_13_1_1_7_8"));
+ }
+ }
+
+ [Test]
+ public async Task HqlPersonPositionalAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ await (session
+ .GetNamedQuery("personPositional")
+ .SetParameter(0, new PersonCpId { IdA = 1, IdB = 2 })
+ .SetParameter(1, new PersonCpId { IdA = 3, IdB = 4 })
+ .ListAsync());
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_1_2", "PERSON_3_4" }));
+ }
+ }
+
+ [Test]
+ public async Task HqlPersonNamedAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ await (session
+ .GetNamedQuery("personNamed")
+ .SetParameter("id1", new PersonCpId { IdA = 1, IdB = 2 })
+ .SetParameter("id2", new PersonCpId { IdA = 3, IdB = 4 })
+ .ListAsync());
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_1_2", "PERSON_3_4" }));
+ }
+ }
+
+ [Test]
+ public async Task GetPersonNoComponentAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var person17_18 =
+ await (session.GetAsync(new PersonNoComponent { IdA = 17, IdB = 18 }));
+ Assert.That(person17_18.Name, Is.EqualTo("PERSON_NO_COMPONENT_17_18"));
+ }
+ }
+
+ [Test]
+ public async Task SqlPersonNoComponentAsync()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ await (session
+ .GetNamedQuery("personNoComponentSql")
+ .SetParameter(0, new PersonNoComponent { IdA = 17, IdB = 18 })
+ .SetParameter(1, new PersonNoComponent { IdA = 19, IdB = 20 })
+ .ListAsync());
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_NO_COMPONENT_17_18", "PERSON_NO_COMPONENT_19_20" }));
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/Employer.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/Employer.cs
new file mode 100644
index 00000000000..c5fe0ffd9ec
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/Employer.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class Employer
+ {
+ public virtual EmployerCpId CpId { get; set; }
+
+ public virtual string Name { get; set; }
+
+ public virtual ICollection EmploymentList { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/EmployerCpId.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/EmployerCpId.cs
new file mode 100644
index 00000000000..dd8bd8cb69a
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/EmployerCpId.cs
@@ -0,0 +1,22 @@
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class EmployerCpId
+ {
+ public virtual int IdA { get; set; }
+
+ public virtual int IdB { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is EmployerCpId objCpId))
+ return false;
+
+ return IdA == objCpId.IdA && IdB == objCpId.IdB;
+ }
+
+ public override int GetHashCode()
+ {
+ return IdA.GetHashCode() ^ IdB.GetHashCode();
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/Employment.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/Employment.cs
new file mode 100644
index 00000000000..a84fd07cc6c
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/Employment.cs
@@ -0,0 +1,9 @@
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class Employment
+ {
+ public virtual EmploymentCpId CpId { get; set; }
+
+ public virtual string Name { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/EmploymentCpId.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/EmploymentCpId.cs
new file mode 100644
index 00000000000..2207044966a
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/EmploymentCpId.cs
@@ -0,0 +1,25 @@
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class EmploymentCpId
+ {
+ public virtual int Id { get; set; }
+
+ public virtual Person PersonObj { get; set; }
+
+ public virtual Employer EmployerObj { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is EmploymentCpId objCpId))
+ return false;
+
+ return Id == objCpId.Id && PersonObj.CpId == objCpId.PersonObj.CpId &&
+ EmployerObj.CpId == objCpId.EmployerObj.CpId;
+ }
+
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode() ^ PersonObj.CpId.GetHashCode() ^ EmployerObj.CpId.GetHashCode();
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/Fixture.cs
new file mode 100644
index 00000000000..f5a298c6afd
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/Fixture.cs
@@ -0,0 +1,235 @@
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ [TestFixture]
+ public class Fixture : BugTestCase
+ {
+ // Disable second level cache
+ protected override string CacheConcurrencyStrategy => null;
+
+ protected override void OnTearDown()
+ {
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ s.CreateQuery("delete from Employment").ExecuteUpdate();
+
+ s.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+ t.Commit();
+ }
+ }
+
+ protected override void OnSetUp()
+ {
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ var personList = new List();
+ var employerList = new List();
+
+ // Global id to avoid false positive assertion with positional parameter
+ var gId = 1;
+
+ for (var i = 0; i < 3; i++)
+ {
+ var personCpId = new PersonCpId { IdA = gId++, IdB = gId++ };
+ var personObj = new Person
+ { CpId = personCpId, Name = "PERSON_" + personCpId.IdA + "_" + personCpId.IdB };
+ s.Save(personObj);
+ personList.Add(personObj);
+ }
+
+ for (var i = 0; i < 3; i++)
+ {
+ var employerCpId = new EmployerCpId { IdA = gId++, IdB = gId++ };
+ var employerObj = new Employer
+ { CpId = employerCpId, Name = "EMPLOYER_" + employerCpId.IdA + "_" + employerCpId.IdB };
+ s.Save(employerObj);
+ employerList.Add(employerObj);
+ }
+
+ var employmentIds = new[]
+ {
+ gId++,
+ gId++,
+ gId++,
+ gId++,
+ };
+ var employmentNames = new[]
+ {
+ //P1 + E1
+ "EMPLOYMENT_" + employmentIds[0] + "_" +
+ personList[0].CpId.IdA + "_" + personList[0].CpId.IdA + "_" +
+ employerList[0].CpId.IdA + "_" + employerList[0].CpId.IdB,
+ //P1 + E2
+ "EMPLOYMENT_" + employmentIds[1] + "_" +
+ personList[0].CpId.IdA + "_" + personList[0].CpId.IdA + "_" +
+ employerList[1].CpId.IdA + "_" + employerList[1].CpId.IdB,
+ //P2 + E2
+ "EMPLOYMENT_" + employmentIds[2] + "_" +
+ personList[1].CpId.IdA + "_" + personList[1].CpId.IdA + "_" +
+ employerList[1].CpId.IdA + "_" + employerList[1].CpId.IdB,
+ //P2 + E3
+ "EMPLOYMENT_" + employmentIds[2] + "_" +
+ personList[1].CpId.IdA + "_" + personList[1].CpId.IdA + "_" +
+ employerList[2].CpId.IdA + "_" + employerList[2].CpId.IdB
+ };
+ var employmentPersons = new[]
+ {
+ personList[0],
+ personList[0],
+ personList[1],
+ personList[1]
+ };
+ var employmentEmployers = new[]
+ {
+ employerList[0],
+ employerList[1],
+ employerList[1],
+ employerList[2]
+ };
+
+ for (var k = 0; k < employmentIds.Length; k++)
+ {
+ var employmentCpId = new EmploymentCpId
+ {
+ Id = employmentIds[k],
+ PersonObj = employmentPersons[k],
+ EmployerObj = employmentEmployers[k]
+ };
+ var employmentObj = new Employment { CpId = employmentCpId, Name = employmentNames[k] };
+ s.Save(employmentObj);
+ }
+
+ for (var i = 0; i < 3; i++)
+ {
+ var personNoComponentObj = new PersonNoComponent { IdA = gId++, IdB = gId++ };
+ personNoComponentObj.Name = "PERSON_NO_COMPONENT_" + personNoComponentObj.IdA + "_" +
+ personNoComponentObj.IdB;
+ s.Save(personNoComponentObj);
+ }
+
+ t.Commit();
+ }
+ }
+
+ // Test reproducing the problem.
+ [Test]
+ public void GetPersonTest()
+ {
+ using (var session = OpenSession())
+ {
+ var person1_2 = session.Get(new PersonCpId { IdA = 1, IdB = 2 });
+ Assert.That(person1_2.Name, Is.EqualTo("PERSON_1_2"));
+ Assert.That(
+ person1_2.EmploymentList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "EMPLOYMENT_13_1_1_7_8", "EMPLOYMENT_14_1_1_9_10" }));
+ }
+ }
+
+ // Test reproducing the problem.
+ [Test]
+ public void GetEmployerTest()
+ {
+ using (var session = OpenSession())
+ {
+ var employer7_8 = session.Get(new EmployerCpId { IdA = 7, IdB = 8 });
+ Assert.That(employer7_8.Name, Is.EqualTo("EMPLOYER_7_8"));
+ Assert.That(
+ employer7_8.EmploymentList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "EMPLOYMENT_13_1_1_7_8" }));
+ }
+ }
+
+ [Test]
+ public void GetEmploymentTest()
+ {
+ using (var session = OpenSession())
+ {
+ var employment_13_1_2_7_8 =
+ session.Get(
+ new EmploymentCpId
+ {
+ Id = 13,
+ PersonObj =
+ new Person
+ {
+ CpId = new PersonCpId { IdA = 1, IdB = 2 }
+ },
+ EmployerObj =
+ new Employer
+ {
+ CpId = new EmployerCpId { IdA = 7, IdB = 8 }
+ }
+ });
+ Assert.That(employment_13_1_2_7_8.Name, Is.EqualTo("EMPLOYMENT_13_1_1_7_8"));
+ }
+ }
+
+ [Test]
+ public void HqlPersonPositional()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ session
+ .GetNamedQuery("personPositional")
+ .SetParameter(0, new PersonCpId { IdA = 1, IdB = 2 })
+ .SetParameter(1, new PersonCpId { IdA = 3, IdB = 4 })
+ .List();
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_1_2", "PERSON_3_4" }));
+ }
+ }
+
+ [Test]
+ public void HqlPersonNamed()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ session
+ .GetNamedQuery("personNamed")
+ .SetParameter("id1", new PersonCpId { IdA = 1, IdB = 2 })
+ .SetParameter("id2", new PersonCpId { IdA = 3, IdB = 4 })
+ .List();
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_1_2", "PERSON_3_4" }));
+ }
+ }
+
+ [Test]
+ public void GetPersonNoComponent()
+ {
+ using (var session = OpenSession())
+ {
+ var person17_18 =
+ session.Get(new PersonNoComponent { IdA = 17, IdB = 18 });
+ Assert.That(person17_18.Name, Is.EqualTo("PERSON_NO_COMPONENT_17_18"));
+ }
+ }
+
+ [Test]
+ public void SqlPersonNoComponent()
+ {
+ using (var session = OpenSession())
+ {
+ var personList =
+ session
+ .GetNamedQuery("personNoComponentSql")
+ .SetParameter(0, new PersonNoComponent { IdA = 17, IdB = 18 })
+ .SetParameter(1, new PersonNoComponent { IdA = 19, IdB = 20 })
+ .List();
+ Assert.That(
+ personList.Select(e => e.Name),
+ Is.EquivalentTo(new[] { "PERSON_NO_COMPONENT_17_18", "PERSON_NO_COMPONENT_19_20" }));
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH3079/Mappings.hbm.xml
new file mode 100644
index 00000000000..a9b8a606aa3
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/Mappings.hbm.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/Person.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/Person.cs
new file mode 100644
index 00000000000..b058470b237
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/Person.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class Person
+ {
+ public virtual PersonCpId CpId { get; set; }
+
+ public virtual string Name { get; set; }
+
+ public virtual ICollection EmploymentList { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/PersonCpId.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/PersonCpId.cs
new file mode 100644
index 00000000000..51788014334
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/PersonCpId.cs
@@ -0,0 +1,22 @@
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class PersonCpId
+ {
+ public int IdA { get; set; }
+
+ public int IdB { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is PersonCpId objCpId))
+ return false;
+
+ return IdA == objCpId.IdA && IdB == objCpId.IdB;
+ }
+
+ public override int GetHashCode()
+ {
+ return IdA.GetHashCode() ^ IdB.GetHashCode();
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3079/PersonNoComponent.cs b/src/NHibernate.Test/NHSpecificTest/NH3079/PersonNoComponent.cs
new file mode 100644
index 00000000000..7948701375d
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3079/PersonNoComponent.cs
@@ -0,0 +1,24 @@
+namespace NHibernate.Test.NHSpecificTest.NH3079
+{
+ public class PersonNoComponent
+ {
+ public virtual int IdA { get; set; }
+
+ public virtual int IdB { get; set; }
+
+ public virtual string Name { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is PersonNoComponent objNoComponent))
+ return false;
+
+ return IdA == objNoComponent.IdA && IdB == objNoComponent.IdB;
+ }
+
+ public override int GetHashCode()
+ {
+ return IdA.GetHashCode() ^ IdB.GetHashCode();
+ }
+ }
+}
diff --git a/src/NHibernate/Async/Impl/SqlQueryImpl.cs b/src/NHibernate/Async/Impl/SqlQueryImpl.cs
index ec46826430a..f4a0342ce37 100644
--- a/src/NHibernate/Async/Impl/SqlQueryImpl.cs
+++ b/src/NHibernate/Async/Impl/SqlQueryImpl.cs
@@ -11,6 +11,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Linq;
using NHibernate.Engine;
using NHibernate.Engine.Query;
using NHibernate.Engine.Query.Sql;
@@ -98,6 +99,7 @@ public partial class SqlQueryImpl : AbstractQueryImpl, ISQLQuery, ISynchronizabl
Before();
try
{
+ ComputeFlattenedParameters();
return await (Session.ExecuteNativeUpdateAsync(GenerateQuerySpecification(namedParams), GetQueryParameters(namedParams), cancellationToken)).ConfigureAwait(false);
}
finally
diff --git a/src/NHibernate/Impl/AbstractQueryImpl.cs b/src/NHibernate/Impl/AbstractQueryImpl.cs
index ba1e1402854..7b79057165c 100644
--- a/src/NHibernate/Impl/AbstractQueryImpl.cs
+++ b/src/NHibernate/Impl/AbstractQueryImpl.cs
@@ -79,11 +79,11 @@ protected internal virtual void VerifyParameters()
}
///
- /// Perform parameter validation. Used prior to executing the encapsulated query.
+ /// Perform parameters validation. Flatten them if needed. Used prior to executing the encapsulated query.
///
///
- /// if true, the first ? will not be verified since
- /// its needed for e.g. callable statements returning a out parameter
+ /// If true, the first positional parameter will not be verified since
+ /// its needed for e.g. callable statements returning an out parameter.
///
protected internal virtual void VerifyParameters(bool reserveFirstParameter)
{
@@ -95,11 +95,15 @@ protected internal virtual void VerifyParameters(bool reserveFirstParameter)
throw new QueryException("Not all named parameters have been set: " + CollectionPrinter.ToString(missingParams), QueryString);
}
- int positionalValueSpan = 0;
- for (int i = 0; i < values.Count; i++)
+ var positionalValueSpan = 0;
+ // Values and Types may be overriden to yield refined parameters, check them
+ // instead of the fields.
+ var values = Values;
+ var types = Types;
+ for (var i = 0; i < values.Count; i++)
{
- object obj = types[i];
- if (values[i] == UNSET_PARAMETER || obj == UNSET_TYPE)
+ var type = types[i];
+ if (values[i] == UNSET_PARAMETER || type == UNSET_TYPE)
{
if (reserveFirstParameter && i == 0)
{
@@ -763,12 +767,13 @@ protected IDictionary NamedParameterLists
get { return namedParameterLists; }
}
- protected IList Values
+ // TODO 6.0: Change type to IList