diff --git a/doc/reference/modules/performance.xml b/doc/reference/modules/performance.xml index 2a1aa29a721..1cd041b08af 100644 --- a/doc/reference/modules/performance.xml +++ b/doc/reference/modules/performance.xml @@ -1216,131 +1216,194 @@ sessionFactory.EvictCollection("Eg.Cat.Kittens");]]> - Multi Query - + Query batch + - This functionality allows you to execute several HQL queries in one round-trip + This functionality allows you to execute several queries in one round-trip against the database server. A simple use case is executing a paged query while - also getting the total count of results, in a single round-trip. Here is a simple + also getting the total count of results, in a single round-trip. Here is an example: + + ( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50).SetFirstResult(10)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50)); +IList items = queries.GetResult(0); +long count = queries.GetResult(1).Single();]]> + + + The results are got by index, ordered according to the order of queries + added to the query batch. Instead of relying on this ordering, a key can be + associated with each query for later retrieval: + + + ().Where(i => i.Id > 50)) + .Add("count", s.Query().Where(i => i.Id > 50), q => q.Count()); +var count = queries.GetResult("count").Single(); +var items = queries.GetResult("list");]]> + + + The namespace NHibernate.Multi has to be imported since most query + batch methods are extension methods. + + + + Criteria queries are also supported by the query batch: + - ?") - .SetInt32(0, 50).SetFirstResult(10)) - .Add(s.CreateQuery("select count(*) from Item i where i.Id > ?") - .SetInt32(0, 50)); -IList results = multiQuery.List(); -IList items = (IList)results[0]; -long count = (long)((IList)results[1])[0];]]> + ( + s.CreateCriteria(typeof(Item)) + .Add(Expression.Gt("Id", 50)) + .SetFirstResult(10)) + .Add( + s.CreateCriteria(typeof(Item)) + .Add(Expression.Gt("Id", 50)) + .SetProject(Projections.RowCount())); +var items = queries.GetResult(0); +var count = queries.GetResult(1).Single();]]> - The result is a list of query results, ordered according to the order of queries - added to the multi query. Named parameters can be set on the multi query, and are - shared among all the queries contained in the multi query, like this: + You can add ICriteria or DetachedCriteria to the query batch. + In fact, using DetachedCriteria in this fashion has some interesting implications. + (customersCriteria) + .Add(DetachedCriteria.For() + .Add(Subqueries.PropertyIn("id", + CriteriaTransformer.Clone(customersCriteria) + .SetProjection(Projections.Id()) + ))); - :id") - .SetFirstResult(10)) - .Add("select count(*) from Item i where i.Id > :id") - .SetInt32("id", 50) - .List(); -IList items = (IList)results[0]; -long count = (long)((IList)results[1])[0];]]> +IList customers = queries.GetResult(0); +IList policies = queries.GetResult(1);]]> - Positional parameters are not supported on the multi query, only on the individual - queries. + We get a query that represents the customers we can access, and then we can utilize this + query further in order to perform additional logic (getting the policies of the customers we are + associated with), all in a single database round-trip. - As shown above, if you do not need to configure the query separately, you can simply - pass the HQL directly to the IMultiQuery.Add() method. + The query batch also supports QueryOver and sql queries. All kind of queries can be mixed in the + same batch. + ().Where(i => i.Category == "Food")) + .Add("sqlCount", + s.CreateSQLQuery("select count(*) as itemCount from Item i where i.Category = :cat") + .AddScalar("itemCount", NHibernateUtil.Int64) + .SetString("cat", "Food")); +var count = queries.GetResult("sqlCount").Single(); +var items = queries.GetResult("queryOverList");]]> + + + Second level cache is supported by the query batch. Queries flagged as cacheable will be retrieved + from the cache if already cached, otherwise their results will be put in the cache. + + + () + .Where(i => i.Id > 50) + .WithOptions(o => o.SetCacheable(true))) + .Add("count", + s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50) + .SetCacheable(true)); +var count = queries.GetResult("count").Single(); +var items = queries.GetResult("list");]]> + Multi query is executed by concatenating the queries and sending the query to the database as a single string. This means that the database should support returning several result sets - in a single query. At the moment this functionality is only enabled for Microsoft SQL Server and SQLite. + in a single query. Otherwise each query will be individually executed instead. + + + + The first GetResult call triggers execution of the whole query batch, which + then stores all results. Later calls only retrieve the stored results. A query batch can be + re-executed by calling its Execute method. Once executed, no new query can be + added to the batch. - Note that the database server is likely to impose a limit on the maximum number of parameters - in a query, in which case the limit applies to the multi query as a whole. Queries using + Note that the database server is likely to enforce a limit on the maximum number of parameters + in a query, in which case the limit applies to the query batch as a whole. Queries using in with a large number of arguments passed as parameters may easily exceed this limit. For example, SQL Server has a limit of 2,100 parameters per round-trip, and will throw an exception executing this query: - - + + ( + s.CreateQuery("from Employee e where e.Id in :empIds") + .SetParameterList("empIds", allEmployeesId) + .SetFirstResult(10)) + .Add( + s.CreateQuery("select count(*) from Employee e where e.Id in :empIds") + .SetParameterList("empIds", allEmployeesId)); +queries.Execute(); // will throw an exception from SQL Server]]> - An interesting usage of this feature is to load several collections of an object in one + An interesting usage of the query batch is to load several collections of an object in one round-trip, without an expensive cartesian product (blog * users * posts). - ();]]> + (0).FirstOrDefault();]]> - - - - Multi Criteria - - This is the counter-part to Multi Query, and allows you to perform several criteria queries - in a single round trip. A simple use case is executing a paged query while - also getting the total count of results, in a single round-trip. Here is a simple - example: + You can also add queries as future queries to a query batch: - - - - The result is a list of query results, ordered according to the order of queries - added to the multi criteria. - + - You can add ICriteria or DetachedCriteria to the Multi Criteria query. - In fact, using DetachedCriteria in this fashion has some interesting implications. - - () - .Add(Subqueries.PropertyIn("id", - CriteriaTransformer.Clone(customersCriteria) - .SetProjection(Projections.Id()) - ))) - .List(); +... -ICollection customers = CollectionHelper.ToArray(results[0]); -ICollection policies = CollectionHelper.ToArray(results[1]);]]> +var queries = s.CreateQueryBatch(); +var list = queries.AddAsFuture(s.Query().Where(i => i.Id > 50))); +var countValue = queries.AddAsFutureValue( + s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50)); +var count = countValue.Value; +var items = list.GetEnumerable();]]> - As you see, we get a query that represents the customers we can access, and then we can utilize this query further in order to - perform additional logic (getting the policies of the customers we are associated with), all in a single database round-trip. + Futures built from a query batch are executed together the first time the result of one of + them is accessed. They are independent of futures obtained directly from the queries. + diff --git a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs index 06b04fc0deb..017634dc4f5 100644 --- a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs @@ -16,6 +16,7 @@ using NUnit.Framework; using NHibernate.Criterion; +using NHibernate.Multi; namespace NHibernate.Test.Criteria.Lambda { @@ -352,7 +353,7 @@ public async Task FunctionsOrderAsync() } } - [Test] + [Test, Obsolete] public async Task MultiCriteriaAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -408,6 +409,58 @@ public async Task MultiCriteriaAsync() } } + [Test] + public async Task MultiQueryAsync() + { + await (SetupPagingDataAsync()); + + using (var s = OpenSession()) + { + var query = + s.QueryOver() + .JoinQueryOver(p => p.Children) + .OrderBy(c => c.Age).Desc + .Skip(2) + .Take(1); + + var multiQuery = + s.CreateQueryBatch() + .Add("page", query) + .Add("count", query.ToRowCountQuery()); + + var pageResults = await (multiQuery.GetResultAsync("page", CancellationToken.None)); + var countResults = await (multiQuery.GetResultAsync("count", CancellationToken.None)); + + Assert.That(pageResults.Count, Is.EqualTo(1)); + Assert.That(pageResults[0].Name, Is.EqualTo("Name 3")); + Assert.That(countResults.Count, Is.EqualTo(1)); + Assert.That(countResults[0], Is.EqualTo(4)); + } + + using (var s = OpenSession()) + { + var query = + QueryOver.Of() + .JoinQueryOver(p => p.Children) + .OrderBy(c => c.Age).Desc + .Skip(2) + .Take(1); + + var multiCriteria = + s.CreateQueryBatch() + .Add("page", query) + .Add("count", query.ToRowCountQuery()); + + var pageResults = await (multiCriteria.GetResultAsync("page", CancellationToken.None)); + var countResults = await (multiCriteria.GetResultAsync("count", CancellationToken.None)); + + Assert.That(pageResults.Count, Is.EqualTo(1)); + Assert.That(pageResults[0].Name, Is.EqualTo("Name 3")); + Assert.That(countResults.Count, Is.EqualTo(1)); + Assert.That(countResults[0], Is.EqualTo(4)); + } + } + private async Task SetupPagingDataAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (ISession s = OpenSession()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/DataReaderWrapperTest/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/DataReaderWrapperTest/Fixture.cs index 0ef21cbc6f9..6178bdea7c2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/DataReaderWrapperTest/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/DataReaderWrapperTest/Fixture.cs @@ -8,17 +8,20 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.DataReaderWrapperTest { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { private const int id = 1333; - + protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) { return factory.ConnectionProvider.Driver.SupportsMultipleQueries; @@ -45,7 +48,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public async Task CanUseDatareadersGetValueAsync() { using (var s = OpenSession()) @@ -58,5 +61,19 @@ public async Task CanUseDatareadersGetValueAsync() Assert.That(res.Count, Is.EqualTo(1)); } } + + [Test] + public async Task CanUseDatareadersGetValueWithQueryBatchAsync() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var crit = s.CreateCriteria(typeof (TheEntity)); + var multi = s.CreateQueryBatch(); + multi.Add(crit); + var res = await (multi.GetResultAsync(0, CancellationToken.None)); + Assert.That(res.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs index 0dbec500db2..9919113e183 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs @@ -8,14 +8,14 @@ //------------------------------------------------------------------------------ -using System.Collections; -using System.Collections.Generic; -using NHibernate.Driver; +using System; using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.NH1253 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -81,7 +81,7 @@ public async Task TestParametersWithTrailingNumbersMultipleInListAsync() } } - [Test] + [Test, Obsolete] public async Task MultiQuerySingleInListAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -101,5 +101,28 @@ public async Task MultiQuerySingleInListAsync() await (tx.CommitAsync()); } } + + [Test] + public async Task QueryBatchSingleInListAsync() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + var q1 = s + .CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .SetParameterList("param11", new[] {"Model1", "Model2"}) + .SetParameterList("param1", new[] {"Make1", "Make2"}); + var q2 = s + .CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .SetParameterList("param11", new[] {"Model1", "Model2"}) + .SetParameterList("param1", new[] {"Make1", "Make2"}); + await (s.CreateQueryBatch() + .Add(q1) + .Add(q2) + .ExecuteAsync(CancellationToken.None)); + + await (tx.CommitAsync()); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1508/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1508/Fixture.cs index 920db7f3fae..bd1b7cb21a5 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1508/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1508/Fixture.cs @@ -8,11 +8,14 @@ //------------------------------------------------------------------------------ +using System; using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.NH1508 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -54,7 +57,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public async Task DoesntThrowExceptionWhenHqlQueryIsGivenAsync() { using (var session = OpenSession()) @@ -67,5 +70,19 @@ public async Task DoesntThrowExceptionWhenHqlQueryIsGivenAsync() await (q.ListAsync()); } } + + [Test] + public async Task DoesntThrowExceptionWhenHqlQueryIsGivenToQueryBatchAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var sqlQuery = session.CreateQuery("from Document"); + var q = session + .CreateQueryBatch() + .Add(sqlQuery); + await (q.ExecuteAsync(CancellationToken.None)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1609/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1609/Fixture.cs index f64a4444dbd..0ef9c665113 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1609/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1609/Fixture.cs @@ -8,9 +8,10 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using NHibernate.Criterion; -using NHibernate.Driver; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH1609 @@ -25,7 +26,7 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) return factory.ConnectionProvider.Driver.SupportsMultipleQueries; } - [Test] + [Test, Obsolete] public async Task TestAsync() { using (var session = Sfi.OpenSession()) @@ -59,6 +60,38 @@ public async Task TestAsync() } } + [Test] + public async Task TestWithQueryBatchAsync() + { + using (var session = Sfi.OpenSession()) + using (session.BeginTransaction()) + { + var a1 = await (CreateEntityAAsync(session)); + var a2 = await (CreateEntityAAsync(session)); + var c = await (CreateEntityCAsync(session)); + var b = await (CreateEntityBAsync(session, a1, c)); + + // make sure the created entities are no longer in the session + session.Clear(); + + var multi = session.CreateQueryBatch(); + + // the first query is a simple select by id on EntityA + multi.Add(session.CreateCriteria(typeof (EntityA)).Add(Restrictions.Eq("Id", a1.Id))); + // the second query is also a simple select by id on EntityB + multi.Add(session.CreateCriteria(typeof (EntityA)).Add(Restrictions.Eq("Id", a2.Id))); + // the final query selects the first element (using SetFirstResult and SetMaxResults) for each EntityB where B.A.Id = a1.Id and B.C.Id = c.Id + // the problem is that the paged query uses parameters @p0 and @p1 instead of @p2 and @p3 + multi.Add( + session.CreateCriteria(typeof (EntityB)).Add(Restrictions.Eq("A.Id", a1.Id)).Add(Restrictions.Eq("C.Id", c.Id)). + SetFirstResult(0).SetMaxResults(1)); + + Assert.That(await (multi.GetResultAsync(0, CancellationToken.None)), Has.Count.EqualTo(1)); + Assert.That(await (multi.GetResultAsync(1, CancellationToken.None)), Has.Count.EqualTo(1)); + Assert.That(await (multi.GetResultAsync(2, CancellationToken.None)), Has.Count.EqualTo(1)); + } + } + private async Task CreateEntityAAsync(ISession session, CancellationToken cancellationToken = default(CancellationToken)) { var a = new EntityA(); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1836/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1836/Fixture.cs index 5380c9ee98b..5bd5c737d32 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1836/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1836/Fixture.cs @@ -8,13 +8,17 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; +using System.Linq; +using NHibernate.Multi; using NHibernate.Transform; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH1836 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -35,7 +39,7 @@ protected override void OnSetUp() } } - [Test] + [Test, Obsolete] public void AliasToBeanTransformerShouldApplyCorrectlyToMultiQueryAsync() { using (var s = OpenSession()) @@ -53,6 +57,25 @@ public void AliasToBeanTransformerShouldApplyCorrectlyToMultiQueryAsync() } } + [Test] + public async Task AliasToBeanTransformerShouldApplyCorrectlyToQueryBatchAsync() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var multiQuery = s + .CreateQueryBatch() + .Add(s + .CreateQuery("select entity.Id as EntityId from Entity entity") + .SetResultTransformer(Transformers.AliasToBean(typeof(EntityDTO)))); + + Assert.That(multiQuery.Execute, Throws.Nothing); + var results = await (multiQuery.GetResultAsync(0, CancellationToken.None)); + Assert.That(results.First(), Is.TypeOf().And.Property("EntityId").EqualTo(1)); + await (t.CommitAsync()); + } + } + protected override void OnTearDown() { base.OnTearDown(); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1869/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1869/Fixture.cs index 0137e1fcc94..99e5824c791 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1869/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1869/Fixture.cs @@ -8,8 +8,9 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; -using NHibernate.Driver; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH1869 @@ -38,7 +39,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public async Task TestAsync() { using (var session = Sfi.OpenSession()) @@ -57,7 +58,7 @@ public async Task TestAsync() using (var session = Sfi.OpenSession()) { - //If uncomment the line below the test will pass + //If querying twice the test will pass //GetResult(session); var result = await (GetResultAsync(session)); Assert.That(result, Has.Count.EqualTo(2)); @@ -66,6 +67,7 @@ public async Task TestAsync() } } + [Obsolete] private Task GetResultAsync(ISession session, CancellationToken cancellationToken = default(CancellationToken)) { try @@ -77,10 +79,48 @@ public async Task TestAsync() multi.Add(query1).Add(query2); return multi.ListAsync(cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } } + + [Test] + public async Task TestWithQueryBatchAsync() + { + using (var session = Sfi.OpenSession()) + using (var transaction = session.BeginTransaction()) + { + _keyword = new Keyword(); + await (session.SaveAsync(_keyword)); + + var nodeKeyword = new NodeKeyword + { + NodeId = 1, + Keyword = _keyword + }; + await (session.SaveAsync(nodeKeyword)); + + await (transaction.CommitAsync()); + } + + using (var session = Sfi.OpenSession()) + { + var result = await (GetResultWithQueryBatchAsync(session)); + Assert.That(await (result.GetResultAsync(0, CancellationToken.None)), Has.Count.EqualTo(1)); + Assert.That(await (result.GetResultAsync(1, CancellationToken.None)), Has.Count.EqualTo(1)); + } + } + + private async Task GetResultWithQueryBatchAsync(ISession session, CancellationToken cancellationToken = default(CancellationToken)) + { + var query1 = session.CreateQuery("from NodeKeyword nk"); + var query2 = session.CreateQuery("from NodeKeyword nk"); + + var multi = session.CreateQueryBatch(); + multi.Add(query1).Add(query2); + await (multi.ExecuteAsync(cancellationToken)); + return multi; + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index 332bf71a088..549d14f3d6f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -11,15 +11,16 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Text; +using System.Linq; using NHibernate.Criterion; using NHibernate.Dialect; -using NHibernate.Tool.hbm2ddl; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2195 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class SQLiteMultiCriteriaTestAsync : BugTestCase { @@ -97,7 +98,7 @@ public async Task SingleCriteriaQueriesWithStringsShouldExecuteCorrectlyAsync() } } - [Test] + [Test, Obsolete] public async Task MultiCriteriaQueriesWithIntsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -126,7 +127,7 @@ public async Task MultiCriteriaQueriesWithIntsShouldExecuteCorrectlyAsync() } } - [Test] + [Test, Obsolete] public async Task MultiCriteriaQueriesWithStringsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -155,5 +156,55 @@ public async Task MultiCriteriaQueriesWithStringsShouldExecuteCorrectlyAsync() Assert.AreEqual(1, list.Count); } } + + [Test] + public async Task QueryBatchWithIntsShouldExecuteCorrectlyAsync() + { + // Test querying IntData + using (var session = OpenSession()) + { + var criteriaWithPagination = session.CreateCriteria(); + criteriaWithPagination.Add(Restrictions.Le("IntData", 2)); + var criteriaWithRowCount = CriteriaTransformer.Clone(criteriaWithPagination); + criteriaWithPagination.SetFirstResult(0).SetMaxResults(1); + criteriaWithRowCount.SetProjection(Projections.RowCountInt64()); + + var multi = session.CreateQueryBatch(); + multi.Add(criteriaWithPagination); + multi.Add(criteriaWithRowCount); + + var numResults = (await (multi.GetResultAsync(1, CancellationToken.None))).Single(); + var list = await (multi.GetResultAsync(0, CancellationToken.None)); + + Assert.That(numResults, Is.EqualTo(2)); + Assert.That(list.Count, Is.EqualTo(1)); + Assert.That(await (criteriaWithRowCount.UniqueResultAsync()), Is.EqualTo(2)); + } + } + + [Test] + public async Task QueryBatchWithStringsShouldExecuteCorrectlyAsync() + { + // Test querying StringData + using (var session = OpenSession()) + { + var criteriaWithPagination = session.CreateCriteria(); + criteriaWithPagination.Add(Restrictions.Like("StringData", "%Doe%")); + var criteriaWithRowCount = CriteriaTransformer.Clone(criteriaWithPagination); + criteriaWithPagination.SetFirstResult(0).SetMaxResults(1); + criteriaWithRowCount.SetProjection(Projections.RowCountInt64()); + + var multi = session.CreateQueryBatch(); + multi.Add(criteriaWithPagination); + multi.Add(criteriaWithRowCount); + + var numResults = (await (multi.GetResultAsync(1, CancellationToken.None))).Single(); + var list = await (multi.GetResultAsync(0, CancellationToken.None)); + + Assert.That(numResults, Is.EqualTo(2)); + Assert.That(list.Count, Is.EqualTo(1)); + Assert.That(await (criteriaWithRowCount.UniqueResultAsync()), Is.EqualTo(2)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2201/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2201/Fixture.cs index 793f910f486..c8d31458508 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2201/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2201/Fixture.cs @@ -10,11 +10,13 @@ using System; using System.Collections.Generic; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2201 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -45,7 +47,7 @@ protected override void OnSetUp() } } - [Test] + [Test, Obsolete] public async Task CanUseMutliCriteriaAndFetchSelectAsync() { using (var s = OpenSession()) @@ -65,5 +67,23 @@ public async Task CanUseMutliCriteriaAndFetchSelectAsync() Console.WriteLine("*** end"); } } + + [Test] + public async Task CanUseQueryBatchAndFetchSelectAsync() + { + using (var s = OpenSession()) + { + var multi = + s.CreateQueryBatch() + .Add(s.CreateCriteria()) + .Add(s.CreateCriteria()); + + var result1 = await (multi.GetResultAsync(0, CancellationToken.None)); + var result2 = await (multi.GetResultAsync(1, CancellationToken.None)); + + Assert.That(result1.Count, Is.EqualTo(2)); + Assert.That(result2.Count, Is.EqualTo(2)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2959/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2959/Fixture.cs index 463b6bd0447..68829391305 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2959/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2959/Fixture.cs @@ -8,11 +8,14 @@ //------------------------------------------------------------------------------ +using System; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2959 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -48,7 +51,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public async Task CanUsePolymorphicCriteriaInMultiCriteriaAsync() { using (ISession session = OpenSession()) @@ -63,7 +66,7 @@ public async Task CanUsePolymorphicCriteriaInMultiCriteriaAsync() } } - [Test] + [Test, Obsolete] public async Task CanUsePolymorphicQueryInMultiQueryAsync() { using (ISession session = OpenSession()) @@ -77,5 +80,33 @@ public async Task CanUsePolymorphicQueryInMultiQueryAsync() Assert.That(results[0], Has.Count.EqualTo(2)); } } + + [Test] + public async Task CanUsePolymorphicCriteriaInQueryBatchAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var results = await (session.CreateQueryBatch() + .Add(session.CreateCriteria(typeof(BaseEntity))) + .GetResultAsync(0, CancellationToken.None)); + + Assert.That(results, Has.Count.EqualTo(2)); + } + } + + [Test] + public async Task CanUsePolymorphicQueryInQueryBatchAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var results = await (session.CreateQueryBatch() + .Add(session.CreateQuery("from " + typeof(BaseEntity).FullName)) + .GetResultAsync(0, CancellationToken.None)); + + Assert.That(results, Has.Count.EqualTo(2)); + } + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index fc8c339848e..0875183d026 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -8,14 +8,17 @@ //------------------------------------------------------------------------------ +using System; using NHibernate.Cfg; using NHibernate.Driver; using NHibernate.Engine; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.SqlConverterAndMultiQuery { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { @@ -47,7 +50,7 @@ public void NormalHqlShouldThrowUserExceptionAsync() } } - [Test] + [Test, Obsolete] public void MultiHqlShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -64,6 +67,19 @@ public void MultiHqlShouldThrowUserExceptionAsync() } } + [Test] + public void QueryBatchShouldThrowUserExceptionAsync() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var multi = s.CreateQueryBatch(); + multi.Add(s.CreateQuery(hqlQuery)); + s.Connection.Close(); + Assert.ThrowsAsync(() => multi.ExecuteAsync(CancellationToken.None)); + } + } + [Test] public void NormalCriteriaShouldThrowUserExceptionAsync() { @@ -76,7 +92,7 @@ public void NormalCriteriaShouldThrowUserExceptionAsync() } } - [Test] + [Test, Obsolete] public void MultiCriteriaShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; @@ -92,5 +108,18 @@ public void MultiCriteriaShouldThrowUserExceptionAsync() Assert.ThrowsAsync(() => multi.ListAsync()); } } + + [Test] + public void CriteriaQueryBatchShouldThrowUserExceptionAsync() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var multi = s.CreateQueryBatch(); + multi.Add(s.CreateCriteria(typeof(ClassA))); + s.Connection.Close(); + Assert.ThrowsAsync(() => multi.ExecuteAsync(CancellationToken.None)); + } + } } } diff --git a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs index b252f0c06b9..6a0526e1272 100644 --- a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs @@ -8,12 +8,14 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cfg; using NHibernate.Criterion; using NHibernate.Dialect; using NHibernate.Driver; +using NHibernate.Multi; using NHibernate.Util; using NUnit.Framework; using Environment = NHibernate.Cfg.Environment; @@ -21,6 +23,7 @@ namespace NHibernate.Test.Pagination { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class CustomDialectFixtureAsync : TestCase { @@ -109,7 +112,7 @@ public async Task LimitFirstAsync() } } - [Test] + [Test, Obsolete] public async Task LimitFirstMultiCriteriaAsync() { using (ISession s = OpenSession()) @@ -133,5 +136,30 @@ public async Task LimitFirstMultiCriteriaAsync() Assert.That(points[1].X, Is.EqualTo(8d)); } } + + [Test] + public async Task LimitFirstQueryBatchAsync() + { + using (var s = OpenSession()) + { + CustomDialect.ForcedSupportsVariableLimit = true; + CustomDialect.ForcedBindLimitParameterFirst = true; + + var query = + s.CreateQueryBatch() + .Add( + s.CreateCriteria() + .Add(Restrictions.Gt("X", 5.1d)) + .AddOrder(Order.Asc("X")) + .SetFirstResult(1) + .SetMaxResults(2)); + + var points = await (query.GetResultAsync(0, CancellationToken.None)); + + Assert.That(points.Count, Is.EqualTo(2)); + Assert.That(points[0].X, Is.EqualTo(7d)); + Assert.That(points[1].X, Is.EqualTo(8d)); + } + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs index 8e4a638691e..16026d41f87 100644 --- a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs @@ -21,7 +21,7 @@ namespace NHibernate.Test.QueryTest { using System.Threading.Tasks; using System.Threading; - [TestFixture] + [TestFixture, Obsolete] public class MultiCriteriaFixtureAsync : TestCase { protected override string MappingsAssembly diff --git a/src/NHibernate.Test/Async/QueryTest/MultipleMixedQueriesFixture.cs b/src/NHibernate.Test/Async/QueryTest/MultipleMixedQueriesFixture.cs index 967c15f25ae..5fc7d5f721a 100644 --- a/src/NHibernate.Test/Async/QueryTest/MultipleMixedQueriesFixture.cs +++ b/src/NHibernate.Test/Async/QueryTest/MultipleMixedQueriesFixture.cs @@ -11,7 +11,6 @@ using System; using System.Collections; using System.Collections.Generic; -using NHibernate.Driver; using NHibernate.Test.SecondLevelCacheTests; using NUnit.Framework; @@ -19,7 +18,7 @@ namespace NHibernate.Test.QueryTest { using System.Threading.Tasks; using System.Threading; - [TestFixture] + [TestFixture, Obsolete] public class MultipleMixedQueriesFixtureAsync : TestCase { protected override string MappingsAssembly diff --git a/src/NHibernate.Test/Async/QueryTest/MultipleQueriesFixture.cs b/src/NHibernate.Test/Async/QueryTest/MultipleQueriesFixture.cs index 7961618cf52..688bce5dc72 100644 --- a/src/NHibernate.Test/Async/QueryTest/MultipleQueriesFixture.cs +++ b/src/NHibernate.Test/Async/QueryTest/MultipleQueriesFixture.cs @@ -21,7 +21,7 @@ namespace NHibernate.Test.QueryTest { using System.Threading.Tasks; using System.Threading; - [TestFixture] + [TestFixture, Obsolete] public class MultipleQueriesFixtureAsync : TestCase { protected override string MappingsAssembly @@ -474,4 +474,4 @@ public async Task CanGetResultsInAGenericListClassAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/QueryTest/QueryBatchFixture.cs b/src/NHibernate.Test/Async/QueryTest/QueryBatchFixture.cs new file mode 100644 index 00000000000..6f42383623c --- /dev/null +++ b/src/NHibernate.Test/Async/QueryTest/QueryBatchFixture.cs @@ -0,0 +1,938 @@ +//------------------------------------------------------------------------------ +// +// 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.Criterion; +using NHibernate.Multi; +using NHibernate.Test.SecondLevelCacheTests; +using NUnit.Framework; +using Environment = NHibernate.Cfg.Environment; + +namespace NHibernate.Test.QueryTest +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class QueryBatchFixtureAsync : TestCase + { + // This fixture aggregates most of the tests from MultiCriteriaFixture, MultipleMixedQueriesFixture and + // MultipleQueriesFixture, rewritten for using QueryBatch instead of obsoleted MultiCriteria/MultiQuery. + + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { "SecondLevelCacheTest.Item.hbm.xml" }; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.GenerateStatistics, "true"); + } + + protected override void OnSetUp() + { + Sfi.Statistics.Clear(); + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + session.Flush(); + transaction.Commit(); + } + } + + #region Criteria + + [Test] + public async Task CanExecuteMultipleCriteriaQueriesInSingleRoundTrip_InTransactionAsync() + { + using (var s = OpenSession()) + { + var item = new Item + { + Id = 1, + Name = "foo" + }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + using (var transaction = s.BeginTransaction()) + { + var getItems = s.CreateCriteria(typeof(Item)); + var countItems = s.CreateCriteria(typeof(Item)) + .SetProjection(Projections.RowCount()); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + Assert.That(fromDb.Name, Is.EqualTo("foo")); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1)); + + await (transaction.CommitAsync()); + } + } + + [Test] + public async Task CanExecuteMultipleCriteriaQueriesInSingleRoundTripAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateCriteria(typeof(Item)); + var countItems = s.CreateCriteria(typeof(Item)) + .SetProjection(Projections.RowCount()); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1)); + } + } + + [Test] + public async Task CanUseSecondLevelCacheWithPositionalParametersAndCriteriaAsync() + { + await (Sfi.QueryCache.ClearAsync(CancellationToken.None)); + + await (CreateItemsAsync()); + + Sfi.Statistics.Clear(); + + await (DoMultiCriteriaAndAssertAsync()); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public async Task CanGetMultiCriteriaFromSecondLevelCacheAsync() + { + await (CreateItemsAsync()); + //set the query in the cache + await (DoMultiCriteriaAndAssertAsync()); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + await (DoMultiCriteriaAndAssertAsync()); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public async Task CanUpdateStatisticsWhenGetMultiCriteriaFromSecondLevelCacheAsync() + { + await (CreateItemsAsync()); + + await (DoMultiCriteriaAndAssertAsync()); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(0)); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + + await (DoMultiCriteriaAndAssertAsync()); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public async Task TwoMultiCriteriaWithDifferentPagingGetDifferentResultsWhenUsingCachedQueriesAsync() + { + await (CreateItemsAsync()); + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(10).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99)); + } + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(20).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + [Test] + public async Task CanUseWithParameterizedCriteriaAndLimitAsync() + { + await (CreateItemsAsync()); + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + + var queries = s.CreateQueryBatch() + .Add( + CriteriaTransformer.Clone(criteria) + .SetFirstResult(10)) + .Add( + CriteriaTransformer.Clone(criteria) + .SetProjection(Projections.RowCount())); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + [Test] + public async Task CanUseCriteriaWithParameterListAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add( + Restrictions.In( + "id", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria)) + .Add( + CriteriaTransformer.Clone(criteria) + .SetProjection(Projections.RowCount())); + + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1)); + } + } + + [Test] + public async Task CanAddCriteriaWithKeyAndRetrieveResultsWithKeyAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = session.CreateCriteria(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var secondCriteria = session.CreateCriteria(typeof(Item)); + + multiCriteria.Add("firstCriteria", firstCriteria); + multiCriteria.Add("secondCriteria", secondCriteria); + + var secondResult = await (multiCriteria.GetResultAsync("secondCriteria", CancellationToken.None)); + var firstResult = await (multiCriteria.GetResultAsync("firstCriteria", CancellationToken.None)); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public async Task CanAddDetachedCriteriaWithKeyAndRetrieveResultsWithKeyAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = DetachedCriteria.For(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var secondCriteria = DetachedCriteria.For(typeof(Item)); + + multiCriteria.Add("firstCriteria", firstCriteria); + multiCriteria.Add("secondCriteria", secondCriteria); + + var secondResult = await (multiCriteria.GetResultAsync("secondCriteria", CancellationToken.None)); + var firstResult = await (multiCriteria.GetResultAsync("firstCriteria", CancellationToken.None)); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public async Task ExecutingCriteriaThroughTransformsResultsAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var criteria = session.CreateCriteria(typeof(Item)) + .SetResultTransformer(transformer); + var multiCriteria = session.CreateQueryBatch() + .Add(criteria); + await (multiCriteria.GetResultAsync(0, CancellationToken.None)); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + [Test] + public async Task UsingManyParametersAndQueries_DoesNotCauseParameterNameCollisionsAsync() + { + //GH-1357 + using (var s = OpenSession()) + { + var item = new Item { Id = 15 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var multi = s.CreateQueryBatch(); + + for (var i = 0; i < 12; i++) + { + var criteria = s.CreateCriteria(typeof(Item)); + for (var j = 0; j < 12; j++) + { + criteria = criteria.Add(Restrictions.Gt("id", j)); + } + + // Parameter combining was used for cacheable queries, with previous implementation (multi-criteria) + // Query batch does not do that, but still keeping the test. + criteria.SetCacheable(true); + + multi.Add(criteria); + } + + for (var i = 0; i < 12; i++) + { + Assert.That((await (multi.GetResultAsync(i, CancellationToken.None))).Count, Is.EqualTo(1)); + } + } + } + + //NH-2428 - Session.MultiCriteria and FlushMode.Auto inside transaction (GH865) + [Test] + public async Task MultiCriteriaAutoFlushAsync() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + s.FlushMode = FlushMode.Auto; + var p1 = new Item + { + Name = "Person name", + Id = 15 + }; + await (s.SaveAsync(p1)); + await (s.FlushAsync()); + + await (s.DeleteAsync(p1)); + var multi = s.CreateQueryBatch(); + multi.Add(s.QueryOver().ToRowCountQuery()); + var count = (await (multi.GetResultAsync(0, CancellationToken.None))).Single(); + await (tx.CommitAsync()); + + Assert.That(count, Is.EqualTo(0), "Session wasn't auto flushed."); + } + } + + private async Task DoMultiCriteriaAndAssertAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(10).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = await (queries.GetResultAsync(0, cancellationToken)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (queries.GetResultAsync(1, cancellationToken))).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + #endregion + + #region HQL + + [Test] + public async Task CanGetMultiHqlFromSecondLevelCacheAsync() + { + await (CreateItemsAsync()); + //set the query in the cache + await (DoMultiHqlAndAssertAsync()); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + await (DoMultiHqlAndAssertAsync()); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public async Task TwoMultiHqlWithDifferentPagingGetDifferentResultsWhenUsingCachedQueriesAsync() + { + await (CreateItemsAsync()); + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = await (multiQuery.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (multiQuery.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(20) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = await (multiQuery.GetResultAsync(0, CancellationToken.None)); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = (await (multiQuery.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public async Task CanUseSecondLevelCacheWithPositionalParametersAndHqlAsync() + { + + await (Sfi.QueryCache.ClearAsync(CancellationToken.None)); + + await (CreateItemsAsync()); + + Sfi.Statistics.Clear(); + + await (DoMultiHqlAndAssertAsync()); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public async Task CanUseHqlWithParameterizedQueriesAndLimitAsync() + { + await (CreateItemsAsync()); + + using (var s = OpenSession()) + { + var getItems = s.CreateQuery("from Item i where i.Id > :id") + .SetInt32("id", 50) + .SetFirstResult(10); + var countItems = s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public async Task CanUseSetParameterListWithHqlAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var queries = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })) + .Add( + s.CreateQuery("select count(*) from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.First().Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public async Task CanExecuteMultiplyHqlInSingleRoundTripAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateQuery("from Item"); + var countItems = s.CreateQuery("select count(*) from Item"); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public async Task CanAddHqlWithKeyAndRetrieveResultsWithKeyAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var multiQuery = session.CreateQueryBatch(); + + var firstQuery = session.CreateQuery("from Item i where i.Id < :id") + .SetInt32("id", 50); + + var secondQuery = session.CreateQuery("from Item"); + + multiQuery.Add("first", firstQuery).Add("second", secondQuery); + + var secondResult = await (multiQuery.GetResultAsync("second", CancellationToken.None)); + var firstResult = await (multiQuery.GetResultAsync("first", CancellationToken.None)); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public async Task ExecutingHqlThroughMultiQueryTransformsResultsAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var criteria = session.CreateQuery("from Item") + .SetResultTransformer(transformer); + await (session.CreateQueryBatch() + .Add(criteria) + .GetResultAsync(0, CancellationToken.None)); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + private async Task DoMultiHqlAndAssertAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = await (multiQuery.GetResultAsync(0, cancellationToken)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (multiQuery.GetResultAsync(1, cancellationToken))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + #endregion + + #region Mixed + + [Test] + public void NH_1085_WillGiveReasonableErrorIfBadParameterNameAsync() + { + using (var s = Sfi.OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id in (:ids)") + .AddEntity(typeof(Item))) + .Add(s.CreateQuery("from Item i where i.Id in (:ids2)")); + var e = Assert.ThrowsAsync(() => multiQuery.ExecuteAsync(CancellationToken.None)); + Assert.That( + e.Message, + Is.EqualTo( + "Not all named parameters have been set: ['ids'] [select * from ITEM where Id in (:ids)]")); + } + } + + [Test] + public async Task CanGetMultiQueryFromSecondLevelCacheAsync() + { + await (CreateItemsAsync()); + //set the query in the cache + await (DoMultiQueryAndAssertAsync()); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + await (DoMultiQueryAndAssertAsync()); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public async Task CanSpecifyParameterOnMultiQueryWhenItIsNotUsedInAllQueriesAsync() + { + using (var s = OpenSession()) + { + await (s.CreateQueryBatch() + .Add(s.CreateQuery("from Item")) + .Add( + s.CreateSQLQuery("select * from ITEM where Id = :id or Id = :id2") + .AddEntity(typeof(Item)) + .SetParameter("id", 5) + .SetInt32("id2", 5)) + .Add( + s.CreateQuery("from Item i where i.Id = :id2") + .SetInt32("id2", 5)) + .ExecuteAsync(CancellationToken.None)); + } + } + + [Test] + public async Task TwoMultiQueriesWithDifferentPagingGetDifferentResultsWhenUsingCachedQueriesAsync() + { + await (CreateItemsAsync()); + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateSQLQuery("select count(*) as itemCount from ITEM where Id > ?") + .AddScalar("itemCount", NHibernateUtil.Int64) + .SetInt32(0, 50) + .SetCacheable(true)); + + var items = await (multiQuery.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (multiQuery.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(20) + .SetCacheable(true)) + .Add( + s.CreateSQLQuery("select count(*) as itemCount from ITEM where Id > ?") + .AddScalar("itemCount", NHibernateUtil.Int64) + .SetInt32(0, 50) + .SetCacheable(true)); + var items = await (multiQuery.GetResultAsync(0, CancellationToken.None)); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = (await (multiQuery.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public async Task CanUseSecondLevelCacheWithPositionalParametersAsync() + { + + await (Sfi.QueryCache.ClearAsync(CancellationToken.None)); + + await (CreateItemsAsync()); + + Sfi.Statistics.Clear(); + + await (DoMultiQueryAndAssertAsync()); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public async Task CanUseWithParameterizedQueriesAndLimitAsync() + { + await (CreateItemsAsync()); + + using (var s = OpenSession()) + { + var getItems = s.CreateSQLQuery("select * from ITEM where Id > :id") + .AddEntity(typeof(Item)) + .SetFirstResult(10) + .SetInt32("id", 50); + var countItems = s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public async Task CanUseSetParameterListAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var queries = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id in (:items)") + .AddEntity(typeof(Item)) + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })) + .Add(s.CreateQuery("select count(*) from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public async Task CanExecuteMultiplyQueriesInSingleRoundTripAsync() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + await (s.SaveAsync(item)); + await (s.FlushAsync()); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateSQLQuery("select * from ITEM").AddEntity(typeof(Item)); + var countItems = s.CreateQuery("select count(*) from Item"); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = await (queries.GetResultAsync(0, CancellationToken.None)); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = (await (queries.GetResultAsync(1, CancellationToken.None))).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public async Task CanAddIQueryWithKeyAndRetrieveResultsWithKeyAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var multiQuery = session.CreateQueryBatch(); + + var firstQuery = session.CreateSQLQuery("select * from ITEM where Id < :id") + .AddEntity(typeof(Item)) + .SetInt32("id", 50); + + var secondQuery = session.CreateQuery("from Item"); + + multiQuery.Add("first", firstQuery).Add("second", secondQuery); + + var secondResult = await (multiQuery.GetResultAsync("second", CancellationToken.None)); + var firstResult = await (multiQuery.GetResultAsync("first", CancellationToken.None)); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public async Task ExecutingQueryThroughMultiQueryTransformsResultsAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var query = session.CreateSQLQuery("select * from ITEM") + .AddEntity(typeof(Item)) + .SetResultTransformer(transformer); + await (session.CreateQueryBatch() + .Add(query) + .GetResultAsync(0, CancellationToken.None)); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + [Test] + public async Task CannotRetrieveResultWithUnknownKeyAsync() + { + await (CreateItemsAsync()); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = session.CreateCriteria(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + multiCriteria.Add("firstCriteria", firstCriteria); + + Assert.That( + () => multiCriteria.GetResultAsync("unknownKey", CancellationToken.None), + Throws.InstanceOf()); + } + } + + private async Task DoMultiQueryAndAssertAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id > ?") + .AddEntity(typeof(Item)) + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = await (multiQuery.GetResultAsync(0, cancellationToken)); + Assert.That(items.Count, Is.EqualTo(89)); + var count = (await (multiQuery.GetResultAsync(1, cancellationToken))).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + #endregion + + private async Task CreateItemsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < 150; i++) + { + var item = new Item { Id = i }; + await (s.SaveAsync(item, cancellationToken)); + } + + await (t.CommitAsync(cancellationToken)); + } + } + } +} diff --git a/src/NHibernate.Test/Async/Stats/StatsFixture.cs b/src/NHibernate.Test/Async/Stats/StatsFixture.cs index 957a26d0e3b..f36c5cb7cd8 100644 --- a/src/NHibernate.Test/Async/Stats/StatsFixture.cs +++ b/src/NHibernate.Test/Async/Stats/StatsFixture.cs @@ -11,6 +11,7 @@ using System.Collections; using System.Collections.Generic; using NHibernate.Criterion; +using NHibernate.Multi; using NHibernate.Stat; using NUnit.Framework; @@ -253,6 +254,7 @@ public async Task IncrementQueryExecutionCount_WhenExplicitQueryIsExecutedAsync( var driver = Sfi.ConnectionProvider.Driver; if (driver.SupportsMultipleQueries) { +#pragma warning disable 618 using (var s = OpenSession()) { var r = await (s.CreateMultiQuery().Add("from Country").Add("from Continent").ListAsync()); @@ -265,6 +267,27 @@ public async Task IncrementQueryExecutionCount_WhenExplicitQueryIsExecutedAsync( var r = await (s.CreateMultiCriteria().Add(DetachedCriteria.For()).Add(DetachedCriteria.For()).ListAsync()); } Assert.AreEqual(1, stats.QueryExecutionCount); +#pragma warning restore 618 + + stats.Clear(); + using (var s = OpenSession()) + { + await (s.CreateQueryBatch() + .Add(s.CreateQuery("from Country")) + .Add(s.CreateQuery("from Continent")) + .ExecuteAsync(CancellationToken.None)); + } + Assert.That(stats.QueryExecutionCount, Is.EqualTo(1)); + + stats.Clear(); + using (var s = OpenSession()) + { + await (s.CreateQueryBatch() + .Add(DetachedCriteria.For()) + .Add(DetachedCriteria.For()) + .ExecuteAsync(CancellationToken.None)); + } + Assert.That(stats.QueryExecutionCount, Is.EqualTo(1)); } using (ISession s = OpenSession()) diff --git a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs index 186ec0ef6f6..0b3f46ba784 100644 --- a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using NHibernate.Criterion; +using NHibernate.Multi; namespace NHibernate.Test.Criteria.Lambda { @@ -340,7 +341,7 @@ public void FunctionsOrder() } } - [Test] + [Test, Obsolete] public void MultiCriteria() { var driver = Sfi.ConnectionProvider.Driver; @@ -396,6 +397,58 @@ public void MultiCriteria() } } + [Test] + public void MultiQuery() + { + SetupPagingData(); + + using (var s = OpenSession()) + { + var query = + s.QueryOver() + .JoinQueryOver(p => p.Children) + .OrderBy(c => c.Age).Desc + .Skip(2) + .Take(1); + + var multiQuery = + s.CreateQueryBatch() + .Add("page", query) + .Add("count", query.ToRowCountQuery()); + + var pageResults = multiQuery.GetResult("page"); + var countResults = multiQuery.GetResult("count"); + + Assert.That(pageResults.Count, Is.EqualTo(1)); + Assert.That(pageResults[0].Name, Is.EqualTo("Name 3")); + Assert.That(countResults.Count, Is.EqualTo(1)); + Assert.That(countResults[0], Is.EqualTo(4)); + } + + using (var s = OpenSession()) + { + var query = + QueryOver.Of() + .JoinQueryOver(p => p.Children) + .OrderBy(c => c.Age).Desc + .Skip(2) + .Take(1); + + var multiCriteria = + s.CreateQueryBatch() + .Add("page", query) + .Add("count", query.ToRowCountQuery()); + + var pageResults = multiCriteria.GetResult("page"); + var countResults = multiCriteria.GetResult("count"); + + Assert.That(pageResults.Count, Is.EqualTo(1)); + Assert.That(pageResults[0].Name, Is.EqualTo("Name 3")); + Assert.That(countResults.Count, Is.EqualTo(1)); + Assert.That(countResults[0], Is.EqualTo(4)); + } + } + private void SetupPagingData() { using (ISession s = OpenSession()) diff --git a/src/NHibernate.Test/NHSpecificTest/DataReaderWrapperTest/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/DataReaderWrapperTest/Fixture.cs index b2a8f86cea3..81793888316 100644 --- a/src/NHibernate.Test/NHSpecificTest/DataReaderWrapperTest/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/DataReaderWrapperTest/Fixture.cs @@ -1,5 +1,7 @@ +using System; using System.Collections; using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.DataReaderWrapperTest { @@ -7,7 +9,7 @@ namespace NHibernate.Test.NHSpecificTest.DataReaderWrapperTest public class Fixture : BugTestCase { private const int id = 1333; - + protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) { return factory.ConnectionProvider.Driver.SupportsMultipleQueries; @@ -34,7 +36,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public void CanUseDatareadersGetValue() { using (var s = OpenSession()) @@ -47,5 +49,19 @@ public void CanUseDatareadersGetValue() Assert.That(res.Count, Is.EqualTo(1)); } } + + [Test] + public void CanUseDatareadersGetValueWithQueryBatch() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var crit = s.CreateCriteria(typeof (TheEntity)); + var multi = s.CreateQueryBatch(); + multi.Add(crit); + var res = multi.GetResult(0); + Assert.That(res.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs index cd45fe824b2..04479bee70f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs @@ -1,7 +1,6 @@ -using System.Collections; -using System.Collections.Generic; -using NHibernate.Driver; +using System; using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.NH1253 { @@ -70,7 +69,7 @@ public void TestParametersWithTrailingNumbersMultipleInList() } } - [Test] + [Test, Obsolete] public void MultiQuerySingleInList() { var driver = Sfi.ConnectionProvider.Driver; @@ -90,5 +89,28 @@ public void MultiQuerySingleInList() tx.Commit(); } } + + [Test] + public void QueryBatchSingleInList() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + var q1 = s + .CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .SetParameterList("param11", new[] {"Model1", "Model2"}) + .SetParameterList("param1", new[] {"Make1", "Make2"}); + var q2 = s + .CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .SetParameterList("param11", new[] {"Model1", "Model2"}) + .SetParameterList("param1", new[] {"Make1", "Make2"}); + s.CreateQueryBatch() + .Add(q1) + .Add(q2) + .Execute(); + + tx.Commit(); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1508/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1508/Fixture.cs index eed86726fa3..302f6e57063 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1508/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1508/Fixture.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System; +using NUnit.Framework; +using NHibernate.Multi; namespace NHibernate.Test.NHSpecificTest.NH1508 { @@ -43,7 +45,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public void DoesntThrowExceptionWhenHqlQueryIsGiven() { using (var session = OpenSession()) @@ -58,6 +60,20 @@ public void DoesntThrowExceptionWhenHqlQueryIsGiven() } [Test] + public void DoesntThrowExceptionWhenHqlQueryIsGivenToQueryBatch() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var sqlQuery = session.CreateQuery("from Document"); + var q = session + .CreateQueryBatch() + .Add(sqlQuery); + q.Execute(); + } + } + + [Test, Obsolete] public void DoesntThrowsExceptionWhenSqlQueryIsGiven() { using (var session = OpenSession()) @@ -70,6 +86,19 @@ public void DoesntThrowsExceptionWhenSqlQueryIsGiven() } [Test] + public void DoesntThrowsExceptionWhenSqlQueryIsGivenToQueryBatch() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var sqlQuery = session.CreateSQLQuery("select * from Document"); + var multiquery = session.CreateQueryBatch(); + Assert.That(() => multiquery.Add(sqlQuery), Throws.Nothing); + Assert.That(multiquery.Execute, Throws.Nothing); + } + } + + [Test, Obsolete] public void DoesntThrowsExceptionWhenNamedSqlQueryIsGiven() { using (var session = OpenSession()) @@ -80,5 +109,19 @@ public void DoesntThrowsExceptionWhenNamedSqlQueryIsGiven() Assert.That(() => multiquery.AddNamedQuery("SampleSqlQuery"), Throws.Nothing); } } + + [Test] + public void DoesntThrowsExceptionWhenNamedSqlQueryIsGivenToQueryBatch() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + + var multiquery = session.CreateQueryBatch(); + var q = session.GetNamedQuery("SampleSqlQuery"); + Assert.That(() => multiquery.Add(q), Throws.Nothing); + Assert.That(multiquery.Execute, Throws.Nothing); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1609/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1609/Fixture.cs index 6b8141f40db..495378815fc 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1609/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1609/Fixture.cs @@ -1,6 +1,7 @@ +using System; using System.Collections; using NHibernate.Criterion; -using NHibernate.Driver; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH1609 @@ -13,7 +14,7 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) return factory.ConnectionProvider.Driver.SupportsMultipleQueries; } - [Test] + [Test, Obsolete] public void Test() { using (var session = Sfi.OpenSession()) @@ -47,6 +48,38 @@ public void Test() } } + [Test] + public void TestWithQueryBatch() + { + using (var session = Sfi.OpenSession()) + using (session.BeginTransaction()) + { + var a1 = CreateEntityA(session); + var a2 = CreateEntityA(session); + var c = CreateEntityC(session); + var b = CreateEntityB(session, a1, c); + + // make sure the created entities are no longer in the session + session.Clear(); + + var multi = session.CreateQueryBatch(); + + // the first query is a simple select by id on EntityA + multi.Add(session.CreateCriteria(typeof (EntityA)).Add(Restrictions.Eq("Id", a1.Id))); + // the second query is also a simple select by id on EntityB + multi.Add(session.CreateCriteria(typeof (EntityA)).Add(Restrictions.Eq("Id", a2.Id))); + // the final query selects the first element (using SetFirstResult and SetMaxResults) for each EntityB where B.A.Id = a1.Id and B.C.Id = c.Id + // the problem is that the paged query uses parameters @p0 and @p1 instead of @p2 and @p3 + multi.Add( + session.CreateCriteria(typeof (EntityB)).Add(Restrictions.Eq("A.Id", a1.Id)).Add(Restrictions.Eq("C.Id", c.Id)). + SetFirstResult(0).SetMaxResults(1)); + + Assert.That(multi.GetResult(0), Has.Count.EqualTo(1)); + Assert.That(multi.GetResult(1), Has.Count.EqualTo(1)); + Assert.That(multi.GetResult(2), Has.Count.EqualTo(1)); + } + } + private EntityA CreateEntityA(ISession session) { var a = new EntityA(); diff --git a/src/NHibernate.Test/NHSpecificTest/NH1836/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1836/Fixture.cs index a8e191523d1..c48aa42efc3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1836/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1836/Fixture.cs @@ -1,4 +1,7 @@ +using System; using System.Collections; +using System.Linq; +using NHibernate.Multi; using NHibernate.Transform; using NUnit.Framework; @@ -24,7 +27,7 @@ protected override void OnSetUp() } } - [Test] + [Test, Obsolete] public void AliasToBeanTransformerShouldApplyCorrectlyToMultiQuery() { using (var s = OpenSession()) @@ -42,6 +45,25 @@ public void AliasToBeanTransformerShouldApplyCorrectlyToMultiQuery() } } + [Test] + public void AliasToBeanTransformerShouldApplyCorrectlyToQueryBatch() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var multiQuery = s + .CreateQueryBatch() + .Add(s + .CreateQuery("select entity.Id as EntityId from Entity entity") + .SetResultTransformer(Transformers.AliasToBean(typeof(EntityDTO)))); + + Assert.That(multiQuery.Execute, Throws.Nothing); + var results = multiQuery.GetResult(0); + Assert.That(results.First(), Is.TypeOf().And.Property("EntityId").EqualTo(1)); + t.Commit(); + } + } + protected override void OnTearDown() { base.OnTearDown(); diff --git a/src/NHibernate.Test/NHSpecificTest/NH1869/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1869/Fixture.cs index db540190871..2645aee0785 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1869/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1869/Fixture.cs @@ -1,5 +1,6 @@ +using System; using System.Collections; -using NHibernate.Driver; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH1869 @@ -26,7 +27,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public void Test() { using (var session = Sfi.OpenSession()) @@ -45,7 +46,7 @@ public void Test() using (var session = Sfi.OpenSession()) { - //If uncomment the line below the test will pass + //If querying twice the test will pass //GetResult(session); var result = GetResult(session); Assert.That(result, Has.Count.EqualTo(2)); @@ -54,6 +55,7 @@ public void Test() } } + [Obsolete] private IList GetResult(ISession session) { var query1 = session.CreateQuery("from NodeKeyword nk"); @@ -63,5 +65,43 @@ private IList GetResult(ISession session) multi.Add(query1).Add(query2); return multi.List(); } + + [Test] + public void TestWithQueryBatch() + { + using (var session = Sfi.OpenSession()) + using (var transaction = session.BeginTransaction()) + { + _keyword = new Keyword(); + session.Save(_keyword); + + var nodeKeyword = new NodeKeyword + { + NodeId = 1, + Keyword = _keyword + }; + session.Save(nodeKeyword); + + transaction.Commit(); + } + + using (var session = Sfi.OpenSession()) + { + var result = GetResultWithQueryBatch(session); + Assert.That(result.GetResult(0), Has.Count.EqualTo(1)); + Assert.That(result.GetResult(1), Has.Count.EqualTo(1)); + } + } + + private IQueryBatch GetResultWithQueryBatch(ISession session) + { + var query1 = session.CreateQuery("from NodeKeyword nk"); + var query2 = session.CreateQuery("from NodeKeyword nk"); + + var multi = session.CreateQueryBatch(); + multi.Add(query1).Add(query2); + multi.Execute(); + return multi; + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index 8e953579395..b8441edf39a 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -1,10 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Text; +using System.Linq; using NHibernate.Criterion; using NHibernate.Dialect; -using NHibernate.Tool.hbm2ddl; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2195 @@ -86,7 +86,7 @@ public void SingleCriteriaQueriesWithStringsShouldExecuteCorrectly() } } - [Test] + [Test, Obsolete] public void MultiCriteriaQueriesWithIntsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; @@ -115,7 +115,7 @@ public void MultiCriteriaQueriesWithIntsShouldExecuteCorrectly() } } - [Test] + [Test, Obsolete] public void MultiCriteriaQueriesWithStringsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; @@ -144,5 +144,55 @@ public void MultiCriteriaQueriesWithStringsShouldExecuteCorrectly() Assert.AreEqual(1, list.Count); } } + + [Test] + public void QueryBatchWithIntsShouldExecuteCorrectly() + { + // Test querying IntData + using (var session = OpenSession()) + { + var criteriaWithPagination = session.CreateCriteria(); + criteriaWithPagination.Add(Restrictions.Le("IntData", 2)); + var criteriaWithRowCount = CriteriaTransformer.Clone(criteriaWithPagination); + criteriaWithPagination.SetFirstResult(0).SetMaxResults(1); + criteriaWithRowCount.SetProjection(Projections.RowCountInt64()); + + var multi = session.CreateQueryBatch(); + multi.Add(criteriaWithPagination); + multi.Add(criteriaWithRowCount); + + var numResults = multi.GetResult(1).Single(); + var list = multi.GetResult(0); + + Assert.That(numResults, Is.EqualTo(2)); + Assert.That(list.Count, Is.EqualTo(1)); + Assert.That(criteriaWithRowCount.UniqueResult(), Is.EqualTo(2)); + } + } + + [Test] + public void QueryBatchWithStringsShouldExecuteCorrectly() + { + // Test querying StringData + using (var session = OpenSession()) + { + var criteriaWithPagination = session.CreateCriteria(); + criteriaWithPagination.Add(Restrictions.Like("StringData", "%Doe%")); + var criteriaWithRowCount = CriteriaTransformer.Clone(criteriaWithPagination); + criteriaWithPagination.SetFirstResult(0).SetMaxResults(1); + criteriaWithRowCount.SetProjection(Projections.RowCountInt64()); + + var multi = session.CreateQueryBatch(); + multi.Add(criteriaWithPagination); + multi.Add(criteriaWithRowCount); + + var numResults = multi.GetResult(1).Single(); + var list = multi.GetResult(0); + + Assert.That(numResults, Is.EqualTo(2)); + Assert.That(list.Count, Is.EqualTo(1)); + Assert.That(criteriaWithRowCount.UniqueResult(), Is.EqualTo(2)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2201/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2201/Fixture.cs index 30a8c6dbf14..a3c7fd9293d 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2201/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2201/Fixture.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2201 @@ -34,7 +35,7 @@ protected override void OnSetUp() } } - [Test] + [Test, Obsolete] public void CanUseMutliCriteriaAndFetchSelect() { using (var s = OpenSession()) @@ -54,5 +55,23 @@ public void CanUseMutliCriteriaAndFetchSelect() Console.WriteLine("*** end"); } } + + [Test] + public void CanUseQueryBatchAndFetchSelect() + { + using (var s = OpenSession()) + { + var multi = + s.CreateQueryBatch() + .Add(s.CreateCriteria()) + .Add(s.CreateCriteria()); + + var result1 = multi.GetResult(0); + var result2 = multi.GetResult(1); + + Assert.That(result1.Count, Is.EqualTo(2)); + Assert.That(result2.Count, Is.EqualTo(2)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2959/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2959/Fixture.cs index 59122107e56..279e4f99c62 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2959/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2959/Fixture.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System; +using NHibernate.Multi; +using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH2959 { @@ -37,7 +39,7 @@ protected override void OnTearDown() } } - [Test] + [Test, Obsolete] public void CanUsePolymorphicCriteriaInMultiCriteria() { using (ISession session = OpenSession()) @@ -52,7 +54,7 @@ public void CanUsePolymorphicCriteriaInMultiCriteria() } } - [Test] + [Test, Obsolete] public void CanUsePolymorphicQueryInMultiQuery() { using (ISession session = OpenSession()) @@ -66,5 +68,33 @@ public void CanUsePolymorphicQueryInMultiQuery() Assert.That(results[0], Has.Count.EqualTo(2)); } } + + [Test] + public void CanUsePolymorphicCriteriaInQueryBatch() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var results = session.CreateQueryBatch() + .Add(session.CreateCriteria(typeof(BaseEntity))) + .GetResult(0); + + Assert.That(results, Has.Count.EqualTo(2)); + } + } + + [Test] + public void CanUsePolymorphicQueryInQueryBatch() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var results = session.CreateQueryBatch() + .Add(session.CreateQuery("from " + typeof(BaseEntity).FullName)) + .GetResult(0); + + Assert.That(results, Has.Count.EqualTo(2)); + } + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index 5d822391ca9..7c170ebf0c6 100644 --- a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -1,6 +1,8 @@ +using System; using NHibernate.Cfg; using NHibernate.Driver; using NHibernate.Engine; +using NHibernate.Multi; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.SqlConverterAndMultiQuery @@ -36,7 +38,7 @@ public void NormalHqlShouldThrowUserException() } } - [Test] + [Test, Obsolete] public void MultiHqlShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; @@ -53,6 +55,19 @@ public void MultiHqlShouldThrowUserException() } } + [Test] + public void QueryBatchShouldThrowUserException() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var multi = s.CreateQueryBatch(); + multi.Add(s.CreateQuery(hqlQuery)); + s.Connection.Close(); + Assert.Throws(multi.Execute); + } + } + [Test] public void NormalCriteriaShouldThrowUserException() { @@ -65,7 +80,7 @@ public void NormalCriteriaShouldThrowUserException() } } - [Test] + [Test, Obsolete] public void MultiCriteriaShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; @@ -81,5 +96,18 @@ public void MultiCriteriaShouldThrowUserException() Assert.Throws(() => multi.List()); } } + + [Test] + public void CriteriaQueryBatchShouldThrowUserException() + { + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + var multi = s.CreateQueryBatch(); + multi.Add(s.CreateCriteria(typeof(ClassA))); + s.Connection.Close(); + Assert.Throws(multi.Execute); + } + } } } diff --git a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs index 80dd95ebc78..aedcceba788 100644 --- a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs @@ -1,9 +1,11 @@ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cfg; using NHibernate.Criterion; using NHibernate.Dialect; using NHibernate.Driver; +using NHibernate.Multi; using NHibernate.Util; using NUnit.Framework; using Environment = NHibernate.Cfg.Environment; @@ -98,7 +100,7 @@ public void LimitFirst() } } - [Test] + [Test, Obsolete] public void LimitFirstMultiCriteria() { using (ISession s = OpenSession()) @@ -122,5 +124,30 @@ public void LimitFirstMultiCriteria() Assert.That(points[1].X, Is.EqualTo(8d)); } } + + [Test] + public void LimitFirstQueryBatch() + { + using (var s = OpenSession()) + { + CustomDialect.ForcedSupportsVariableLimit = true; + CustomDialect.ForcedBindLimitParameterFirst = true; + + var query = + s.CreateQueryBatch() + .Add( + s.CreateCriteria() + .Add(Restrictions.Gt("X", 5.1d)) + .AddOrder(Order.Asc("X")) + .SetFirstResult(1) + .SetMaxResults(2)); + + var points = query.GetResult(0); + + Assert.That(points.Count, Is.EqualTo(2)); + Assert.That(points[0].X, Is.EqualTo(7d)); + Assert.That(points[1].X, Is.EqualTo(8d)); + } + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs index 646e9d90253..a2bfc7887c0 100644 --- a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs @@ -9,7 +9,7 @@ namespace NHibernate.Test.QueryTest { - [TestFixture] + [TestFixture, Obsolete] public class MultiCriteriaFixture : TestCase { protected override string MappingsAssembly diff --git a/src/NHibernate.Test/QueryTest/MultipleMixedQueriesFixture.cs b/src/NHibernate.Test/QueryTest/MultipleMixedQueriesFixture.cs index 90f98dabfd3..561d679a0a7 100644 --- a/src/NHibernate.Test/QueryTest/MultipleMixedQueriesFixture.cs +++ b/src/NHibernate.Test/QueryTest/MultipleMixedQueriesFixture.cs @@ -1,13 +1,12 @@ using System; using System.Collections; using System.Collections.Generic; -using NHibernate.Driver; using NHibernate.Test.SecondLevelCacheTests; using NUnit.Framework; namespace NHibernate.Test.QueryTest { - [TestFixture] + [TestFixture, Obsolete] public class MultipleMixedQueriesFixture : TestCase { protected override string MappingsAssembly diff --git a/src/NHibernate.Test/QueryTest/MultipleQueriesFixture.cs b/src/NHibernate.Test/QueryTest/MultipleQueriesFixture.cs index c1d755be8f8..6c4bd1063b6 100644 --- a/src/NHibernate.Test/QueryTest/MultipleQueriesFixture.cs +++ b/src/NHibernate.Test/QueryTest/MultipleQueriesFixture.cs @@ -9,7 +9,7 @@ namespace NHibernate.Test.QueryTest { - [TestFixture] + [TestFixture, Obsolete] public class MultipleQueriesFixture : TestCase { protected override string MappingsAssembly @@ -487,4 +487,4 @@ public void CanGetResultsInAGenericListClass() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/QueryTest/QueryBatchFixture.cs b/src/NHibernate.Test/QueryTest/QueryBatchFixture.cs new file mode 100644 index 00000000000..29a901c452f --- /dev/null +++ b/src/NHibernate.Test/QueryTest/QueryBatchFixture.cs @@ -0,0 +1,985 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NHibernate.Multi; +using NHibernate.Test.SecondLevelCacheTests; +using NUnit.Framework; +using Environment = NHibernate.Cfg.Environment; + +namespace NHibernate.Test.QueryTest +{ + [TestFixture] + public class QueryBatchFixture : TestCase + { + // This fixture aggregates most of the tests from MultiCriteriaFixture, MultipleMixedQueriesFixture and + // MultipleQueriesFixture, rewritten for using QueryBatch instead of obsoleted MultiCriteria/MultiQuery. + + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { "SecondLevelCacheTest.Item.hbm.xml" }; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.GenerateStatistics, "true"); + } + + protected override void OnSetUp() + { + Sfi.Statistics.Clear(); + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + session.Flush(); + transaction.Commit(); + } + } + + #region Criteria + + [Test] + public void CanExecuteMultipleCriteriaQueriesInSingleRoundTrip_InTransaction() + { + using (var s = OpenSession()) + { + var item = new Item + { + Id = 1, + Name = "foo" + }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + using (var transaction = s.BeginTransaction()) + { + var getItems = s.CreateCriteria(typeof(Item)); + var countItems = s.CreateCriteria(typeof(Item)) + .SetProjection(Projections.RowCount()); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + Assert.That(fromDb.Name, Is.EqualTo("foo")); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1)); + + transaction.Commit(); + } + } + + [Test] + public void CanExecuteMultipleCriteriaQueriesInSingleRoundTrip() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateCriteria(typeof(Item)); + var countItems = s.CreateCriteria(typeof(Item)) + .SetProjection(Projections.RowCount()); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1)); + } + } + + [Test] + public void CanUseSecondLevelCacheWithPositionalParametersAndCriteria() + { + Sfi.QueryCache.Clear(); + + CreateItems(); + + Sfi.Statistics.Clear(); + + DoMultiCriteriaAndAssert(); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public void CanGetMultiCriteriaFromSecondLevelCache() + { + CreateItems(); + //set the query in the cache + DoMultiCriteriaAndAssert(); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + DoMultiCriteriaAndAssert(); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public void CanUpdateStatisticsWhenGetMultiCriteriaFromSecondLevelCache() + { + CreateItems(); + + DoMultiCriteriaAndAssert(); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(0)); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + + DoMultiCriteriaAndAssert(); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(2)); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public void TwoMultiCriteriaWithDifferentPagingGetDifferentResultsWhenUsingCachedQueries() + { + CreateItems(); + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(10).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = queries.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99)); + } + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(20).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = queries.GetResult(0); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + [Test] + public void CanUseWithParameterizedCriteriaAndLimit() + { + CreateItems(); + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + + var queries = s.CreateQueryBatch() + .Add( + CriteriaTransformer.Clone(criteria) + .SetFirstResult(10)) + .Add( + CriteriaTransformer.Clone(criteria) + .SetProjection(Projections.RowCount())); + var items = queries.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + [Test] + public void CanUseCriteriaWithParameterList() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add( + Restrictions.In( + "id", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria)) + .Add( + CriteriaTransformer.Clone(criteria) + .SetProjection(Projections.RowCount())); + + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1)); + } + } + + [Test] + public void CanAddCriteriaWithKeyAndRetrieveResultsWithKey() + { + CreateItems(); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = session.CreateCriteria(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var secondCriteria = session.CreateCriteria(typeof(Item)); + + multiCriteria.Add("firstCriteria", firstCriteria); + multiCriteria.Add("secondCriteria", secondCriteria); + + var secondResult = multiCriteria.GetResult("secondCriteria"); + var firstResult = multiCriteria.GetResult("firstCriteria"); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public void CanAddDetachedCriteriaWithKeyAndRetrieveResultsWithKey() + { + CreateItems(); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = DetachedCriteria.For(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var secondCriteria = DetachedCriteria.For(typeof(Item)); + + multiCriteria.Add("firstCriteria", firstCriteria); + multiCriteria.Add("secondCriteria", secondCriteria); + + var secondResult = multiCriteria.GetResult("secondCriteria"); + var firstResult = multiCriteria.GetResult("firstCriteria"); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public void CannotAddCriteriaWithKeyThatAlreadyExists() + { + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = session.CreateCriteria(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var secondCriteria = session.CreateCriteria(typeof(Item)); + + multiCriteria.Add("commonKey", firstCriteria); + Assert.That( + () => multiCriteria.Add("commonKey", secondCriteria), + Throws.ArgumentException); + } + } + + [Test] + public void ExecutingCriteriaThroughTransformsResults() + { + CreateItems(); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var criteria = session.CreateCriteria(typeof(Item)) + .SetResultTransformer(transformer); + var multiCriteria = session.CreateQueryBatch() + .Add(criteria); + multiCriteria.GetResult(0); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + [Test] + public void UsingManyParametersAndQueries_DoesNotCauseParameterNameCollisions() + { + //GH-1357 + using (var s = OpenSession()) + { + var item = new Item { Id = 15 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var multi = s.CreateQueryBatch(); + + for (var i = 0; i < 12; i++) + { + var criteria = s.CreateCriteria(typeof(Item)); + for (var j = 0; j < 12; j++) + { + criteria = criteria.Add(Restrictions.Gt("id", j)); + } + + // Parameter combining was used for cacheable queries, with previous implementation (multi-criteria) + // Query batch does not do that, but still keeping the test. + criteria.SetCacheable(true); + + multi.Add(criteria); + } + + for (var i = 0; i < 12; i++) + { + Assert.That(multi.GetResult(i).Count, Is.EqualTo(1)); + } + } + } + + //NH-2428 - Session.MultiCriteria and FlushMode.Auto inside transaction (GH865) + [Test] + public void MultiCriteriaAutoFlush() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + s.FlushMode = FlushMode.Auto; + var p1 = new Item + { + Name = "Person name", + Id = 15 + }; + s.Save(p1); + s.Flush(); + + s.Delete(p1); + var multi = s.CreateQueryBatch(); + multi.Add(s.QueryOver().ToRowCountQuery()); + var count = multi.GetResult(0).Single(); + tx.Commit(); + + Assert.That(count, Is.EqualTo(0), "Session wasn't auto flushed."); + } + } + + private void DoMultiCriteriaAndAssert() + { + using (var s = OpenSession()) + { + var criteria = s.CreateCriteria(typeof(Item)) + .Add(Restrictions.Gt("id", 50)); + var queries = s.CreateQueryBatch() + .Add(CriteriaTransformer.Clone(criteria).SetFirstResult(10).SetCacheable(true)) + .Add( + CriteriaTransformer + .Clone(criteria).SetProjection(Projections.RowCount()).SetCacheable(true)); + var items = queries.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99)); + } + } + + #endregion + + #region HQL + + [Test] + public void CanGetMultiHqlFromSecondLevelCache() + { + CreateItems(); + //set the query in the cache + DoMultiHqlAndAssert(); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + DoMultiHqlAndAssert(); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public void TwoMultiHqlWithDifferentPagingGetDifferentResultsWhenUsingCachedQueries() + { + CreateItems(); + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = multiQuery.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(20) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = multiQuery.GetResult(0); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public void CanUseSecondLevelCacheWithPositionalParametersAndHql() + { + + Sfi.QueryCache.Clear(); + + CreateItems(); + + Sfi.Statistics.Clear(); + + DoMultiHqlAndAssert(); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public void CanUseHqlWithParameterizedQueriesAndLimit() + { + CreateItems(); + + using (var s = OpenSession()) + { + var getItems = s.CreateQuery("from Item i where i.Id > :id") + .SetInt32("id", 50) + .SetFirstResult(10); + var countItems = s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public void CanUseSetParameterListWithHql() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var queries = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })) + .Add( + s.CreateQuery("select count(*) from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + + var items = queries.GetResult(0); + Assert.That(items.First().Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public void CanExecuteMultiplyHqlInSingleRoundTrip() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateQuery("from Item"); + var countItems = s.CreateQuery("select count(*) from Item"); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public void CanAddHqlWithKeyAndRetrieveResultsWithKey() + { + CreateItems(); + + using (var session = OpenSession()) + { + var multiQuery = session.CreateQueryBatch(); + + var firstQuery = session.CreateQuery("from Item i where i.Id < :id") + .SetInt32("id", 50); + + var secondQuery = session.CreateQuery("from Item"); + + multiQuery.Add("first", firstQuery).Add("second", secondQuery); + + var secondResult = multiQuery.GetResult("second"); + var firstResult = multiQuery.GetResult("first"); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public void CannotAddHqlWithKeyThatAlreadyExists() + { + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstQuery = session.CreateQuery("from Item i where i.Id < :id") + .SetInt32("id", 50); + + var secondQuery = session.CreateQuery("from Item"); + + multiCriteria.Add("commonKey", firstQuery); + + Assert.That( + () => multiCriteria.Add("commonKey", secondQuery), + Throws.ArgumentException); + } + } + + [Test] + public void ExecutingHqlThroughMultiQueryTransformsResults() + { + CreateItems(); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var criteria = session.CreateQuery("from Item") + .SetResultTransformer(transformer); + session.CreateQueryBatch() + .Add(criteria) + .GetResult(0); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + private void DoMultiHqlAndAssert() + { + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = multiQuery.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + #endregion + + #region Mixed + + [Test] + public void NH_1085_WillGiveReasonableErrorIfBadParameterName() + { + using (var s = Sfi.OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id in (:ids)") + .AddEntity(typeof(Item))) + .Add(s.CreateQuery("from Item i where i.Id in (:ids2)")); + var e = Assert.Throws(multiQuery.Execute); + Assert.That( + e.Message, + Is.EqualTo( + "Not all named parameters have been set: ['ids'] [select * from ITEM where Id in (:ids)]")); + } + } + + [Test] + public void CanGetMultiQueryFromSecondLevelCache() + { + CreateItems(); + //set the query in the cache + DoMultiQueryAndAssert(); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Cache puts"); + + Sfi.Statistics.Clear(); + DoMultiQueryAndAssert(); + Assert.That(Sfi.Statistics.PrepareStatementCount, Is.EqualTo(0), "Prepared statements"); + Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Cache misses"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Cache hits"); + } + + [Test] + public void CanSpecifyParameterOnMultiQueryWhenItIsNotUsedInAllQueries() + { + using (var s = OpenSession()) + { + s.CreateQueryBatch() + .Add(s.CreateQuery("from Item")) + .Add( + s.CreateSQLQuery("select * from ITEM where Id = :id or Id = :id2") + .AddEntity(typeof(Item)) + .SetParameter("id", 5) + .SetInt32("id2", 5)) + .Add( + s.CreateQuery("from Item i where i.Id = :id2") + .SetInt32("id2", 5)) + .Execute(); + } + } + + [Test] + public void TwoMultiQueriesWithDifferentPagingGetDifferentResultsWhenUsingCachedQueries() + { + CreateItems(); + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateSQLQuery("select count(*) as itemCount from ITEM where Id > ?") + .AddScalar("itemCount", NHibernateUtil.Int64) + .SetInt32(0, 50) + .SetCacheable(true)); + + var items = multiQuery.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateQuery("from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetFirstResult(20) + .SetCacheable(true)) + .Add( + s.CreateSQLQuery("select count(*) as itemCount from ITEM where Id > ?") + .AddScalar("itemCount", NHibernateUtil.Int64) + .SetInt32(0, 50) + .SetCacheable(true)); + var items = multiQuery.GetResult(0); + Assert.That( + items.Count, + Is.EqualTo(79), + "Should have gotten different result here, because the paging is different"); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public void CanUseSecondLevelCacheWithPositionalParameters() + { + + Sfi.QueryCache.Clear(); + + CreateItems(); + + Sfi.Statistics.Clear(); + + DoMultiQueryAndAssert(); + + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2)); + } + + [Test] + public void CanUseWithParameterizedQueriesAndLimit() + { + CreateItems(); + + using (var s = OpenSession()) + { + var getItems = s.CreateSQLQuery("select * from ITEM where Id > :id") + .AddEntity(typeof(Item)) + .SetFirstResult(10) + .SetInt32("id", 50); + var countItems = s.CreateQuery("select count(*) from Item i where i.Id > :id") + .SetInt32("id", 50); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + [Test] + public void CanUseSetParameterList() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var queries = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id in (:items)") + .AddEntity(typeof(Item)) + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })) + .Add(s.CreateQuery("select count(*) from Item i where i.id in (:items)") + .SetParameterList( + "items", + new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); + + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public void CanExecuteMultiplyQueriesInSingleRoundTrip() + { + using (var s = OpenSession()) + { + var item = new Item { Id = 1 }; + s.Save(item); + s.Flush(); + } + + using (var s = OpenSession()) + { + var getItems = s.CreateSQLQuery("select * from ITEM").AddEntity(typeof(Item)); + var countItems = s.CreateQuery("select count(*) from Item"); + + var queries = s.CreateQueryBatch() + .Add(getItems) + .Add(countItems); + var items = queries.GetResult(0); + var fromDb = items.First(); + Assert.That(fromDb.Id, Is.EqualTo(1)); + + var count = queries.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(1L)); + } + } + + [Test] + public void CanAddIQueryWithKeyAndRetrieveResultsWithKey() + { + CreateItems(); + + using (var session = OpenSession()) + { + var multiQuery = session.CreateQueryBatch(); + + var firstQuery = session.CreateSQLQuery("select * from ITEM where Id < :id") + .AddEntity(typeof(Item)) + .SetInt32("id", 50); + + var secondQuery = session.CreateQuery("from Item"); + + multiQuery.Add("first", firstQuery).Add("second", secondQuery); + + var secondResult = multiQuery.GetResult("second"); + var firstResult = multiQuery.GetResult("first"); + + Assert.That(secondResult.Count, Is.GreaterThan(firstResult.Count)); + } + } + + [Test] + public void ExecutingQueryThroughMultiQueryTransformsResults() + { + CreateItems(); + + using (var session = OpenSession()) + { + var transformer = new ResultTransformerStub(); + var query = session.CreateSQLQuery("select * from ITEM") + .AddEntity(typeof(Item)) + .SetResultTransformer(transformer); + session.CreateQueryBatch() + .Add(query) + .GetResult(0); + + Assert.That(transformer.WasTransformTupleCalled, Is.True, "Transform Tuple was not called"); + Assert.That(transformer.WasTransformListCalled, Is.True, "Transform List was not called"); + } + } + + [Test] + public void CannotAddMixedQueryWithKeyThatAlreadyExists() + { + using (var session = OpenSession()) + { + var queries = session.CreateQueryBatch(); + + var criteria = DetachedCriteria.For(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + var query = session.Query(); + + queries.Add("commonKey", criteria); + + Assert.That( + () => queries.Add("commonKey", query), + Throws.ArgumentException); + } + } + + [Test] + public void CannotRetrieveResultWithUnknownKey() + { + CreateItems(); + + using (var session = OpenSession()) + { + var multiCriteria = session.CreateQueryBatch(); + + var firstCriteria = session.CreateCriteria(typeof(Item)) + .Add(Restrictions.Lt("id", 50)); + + multiCriteria.Add("firstCriteria", firstCriteria); + + Assert.That( + () => multiCriteria.GetResult("unknownKey"), + Throws.InstanceOf()); + } + } + + private void DoMultiQueryAndAssert() + { + using (var s = OpenSession()) + { + var multiQuery = s.CreateQueryBatch() + .Add( + s.CreateSQLQuery("select * from ITEM where Id > ?") + .AddEntity(typeof(Item)) + .SetInt32(0, 50) + .SetFirstResult(10) + .SetCacheable(true)) + .Add( + s.CreateQuery("select count(*) from Item i where i.Id > ?") + .SetInt32(0, 50) + .SetCacheable(true)); + var items = multiQuery.GetResult(0); + Assert.That(items.Count, Is.EqualTo(89)); + var count = multiQuery.GetResult(1).Single(); + Assert.That(count, Is.EqualTo(99L)); + } + } + + #endregion + + private void CreateItems() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < 150; i++) + { + var item = new Item { Id = i }; + s.Save(item); + } + + t.Commit(); + } + } + } +} diff --git a/src/NHibernate.Test/Stats/StatsFixture.cs b/src/NHibernate.Test/Stats/StatsFixture.cs index 148523d57ea..98beb3c37a3 100644 --- a/src/NHibernate.Test/Stats/StatsFixture.cs +++ b/src/NHibernate.Test/Stats/StatsFixture.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using NHibernate.Criterion; +using NHibernate.Multi; using NHibernate.Stat; using NUnit.Framework; @@ -241,6 +242,7 @@ public void IncrementQueryExecutionCount_WhenExplicitQueryIsExecuted() var driver = Sfi.ConnectionProvider.Driver; if (driver.SupportsMultipleQueries) { +#pragma warning disable 618 using (var s = OpenSession()) { var r = s.CreateMultiQuery().Add("from Country").Add("from Continent").List(); @@ -253,6 +255,27 @@ public void IncrementQueryExecutionCount_WhenExplicitQueryIsExecuted() var r = s.CreateMultiCriteria().Add(DetachedCriteria.For()).Add(DetachedCriteria.For()).List(); } Assert.AreEqual(1, stats.QueryExecutionCount); +#pragma warning restore 618 + + stats.Clear(); + using (var s = OpenSession()) + { + s.CreateQueryBatch() + .Add(s.CreateQuery("from Country")) + .Add(s.CreateQuery("from Continent")) + .Execute(); + } + Assert.That(stats.QueryExecutionCount, Is.EqualTo(1)); + + stats.Clear(); + using (var s = OpenSession()) + { + s.CreateQueryBatch() + .Add(DetachedCriteria.For()) + .Add(DetachedCriteria.For()) + .Execute(); + } + Assert.That(stats.QueryExecutionCount, Is.EqualTo(1)); } using (ISession s = OpenSession()) diff --git a/src/NHibernate/Async/Impl/MultipleQueriesCacheAssembler.cs b/src/NHibernate/Async/Impl/MultipleQueriesCacheAssembler.cs index 051862dacc2..5be1c4709ff 100644 --- a/src/NHibernate/Async/Impl/MultipleQueriesCacheAssembler.cs +++ b/src/NHibernate/Async/Impl/MultipleQueriesCacheAssembler.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cache; @@ -86,7 +87,7 @@ public Task BeforeAssembleAsync(object cached, ISessionImplementor session, Canc BeforeAssemble(cached, session); return Task.CompletedTask; } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } diff --git a/src/NHibernate/IMultiCriteria.cs b/src/NHibernate/IMultiCriteria.cs index 958e9d56bcd..1beb117eb8e 100644 --- a/src/NHibernate/IMultiCriteria.cs +++ b/src/NHibernate/IMultiCriteria.cs @@ -9,6 +9,8 @@ namespace NHibernate /// /// Combines several queries into a single DB call /// + // Since v5.2 + [Obsolete("Use Multi.IQueryBatch instead, obtainable with ISession.CreateQueryBatch.")] public partial interface IMultiCriteria { /// @@ -157,9 +159,10 @@ public partial interface IMultiCriteria object GetResult(string key); } + // Since v5.2 + [Obsolete("Use Multi.IQueryBatch instead, obtainable with ISession.CreateQueryBatch.")] public static class MultiCriteriaExtensions { - //6.0 TODO: Convert to interface method /// /// Set a timeout for the underlying ADO.NET query. /// diff --git a/src/NHibernate/IMultiQuery.cs b/src/NHibernate/IMultiQuery.cs index ca75dd45527..0cc6b693b33 100644 --- a/src/NHibernate/IMultiQuery.cs +++ b/src/NHibernate/IMultiQuery.cs @@ -8,6 +8,8 @@ namespace NHibernate /// /// Combines several queries into a single database call /// + // Since v5.2 + [Obsolete("Use Multi.IQueryBatch instead, obtainable with ISession.CreateQueryBatch.")] public partial interface IMultiQuery { /// diff --git a/src/NHibernate/ISession.cs b/src/NHibernate/ISession.cs index fb0bf975010..bcaf6e5a502 100644 --- a/src/NHibernate/ISession.cs +++ b/src/NHibernate/ISession.cs @@ -30,9 +30,10 @@ public static ISharedStatelessSessionBuilder StatelessSessionWithOptions(this IS } /// - /// Creates a for the session. + /// Creates a for the session. Batch extension methods are available in the + /// NHibernate.Multi namespace. /// - /// The session + /// The session. /// A query batch. public static IQueryBatch CreateQueryBatch(this ISession session) { @@ -976,6 +977,8 @@ public partial interface ISession : IDisposable /// a list of all the results of all the queries. /// Note that each query result is itself usually a list. /// + // Since v5.2 + [Obsolete("Use ISession.CreateQueryBatch instead.")] IMultiQuery CreateMultiQuery(); /// @@ -1002,6 +1005,8 @@ public partial interface ISession : IDisposable /// of all the criterias. /// /// + // Since v5.2 + [Obsolete("Use ISession.CreateQueryBatch instead.")] IMultiCriteria CreateMultiCriteria(); /// Get the statistics for this session. diff --git a/src/NHibernate/Impl/MultiCriteriaImpl.cs b/src/NHibernate/Impl/MultiCriteriaImpl.cs index 3c289010fbf..98f87bd9bb5 100644 --- a/src/NHibernate/Impl/MultiCriteriaImpl.cs +++ b/src/NHibernate/Impl/MultiCriteriaImpl.cs @@ -16,6 +16,8 @@ namespace NHibernate.Impl { + // Since v5.2 + [Obsolete("Use Multi.IQueryBatch instead, obtainable with ISession.CreateQueryBatch.")] public partial class MultiCriteriaImpl : IMultiCriteria { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(MultiCriteriaImpl)); diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index 67410ee220e..278c2822ff0 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -18,6 +18,8 @@ namespace NHibernate.Impl { + // Since v5.2 + [Obsolete("Use Multi.QueryBatch instead, obtainable with ISession.CreateQueryBatch.")] public partial class MultiQueryImpl : IMultiQuery { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(MultiQueryImpl)); diff --git a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs index 51503c508e8..28601edf013 100644 --- a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs +++ b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cache; @@ -6,6 +7,7 @@ namespace NHibernate.Impl { + [Obsolete("This class has no more usage and will be removed in a future version")] internal partial class MultipleQueriesCacheAssembler : ICacheAssembler { private readonly IList assemblersList; diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index fd55e78f419..3e999ddd9df 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -1954,6 +1954,8 @@ private string[] ParseFilterParameterName(string filterParameterName) return new[] { filterName, parameterName }; } + // Since v5.2 + [Obsolete("Use ISession.CreateQueryBatch instead.")] public IMultiQuery CreateMultiQuery() { using (BeginProcess()) @@ -1962,6 +1964,8 @@ public IMultiQuery CreateMultiQuery() } } + // Since v5.2 + [Obsolete("Use ISession.CreateQueryBatch instead.")] public IMultiCriteria CreateMultiCriteria() { using (BeginProcess())