diff --git a/src/NHibernate.Test/Async/Linq/WhereSubqueryTests.cs b/src/NHibernate.Test/Async/Linq/WhereSubqueryTests.cs index 2e67bea1c82..fcd730b4314 100644 --- a/src/NHibernate.Test/Async/Linq/WhereSubqueryTests.cs +++ b/src/NHibernate.Test/Async/Linq/WhereSubqueryTests.cs @@ -11,9 +11,10 @@ using System; using System.Linq; using System.Linq.Expressions; +using NHibernate.Dialect; using NHibernate.DomainModel.Northwind.Entities; -using NUnit.Framework; using NHibernate.Linq; +using NUnit.Framework; namespace NHibernate.Test.Linq { @@ -465,6 +466,27 @@ where subquery.Any(x => x.OrderId == order.OrderId) Assert.That(query.Count, Is.EqualTo(61)); } + [Test(Description = "GH2479")] + public async Task OrdersWithSubquery11Async() + { + if (Dialect is MySQLDialect) + Assert.Ignore("MySQL does not support LIMIT in subqueries."); + if (Dialect is MsSqlCeDialect) + Assert.Ignore("MS SQL CE does not support sorting on a subquery."); + + var ordersQuery = db.Orders + .OrderByDescending(x => x.OrderLines.Count).ThenBy(x => x.OrderId) + .Take(2); + + var orderLineQuery = ordersQuery.SelectMany(x => x.OrderLines); + var productsNotInLargestOrders = await (db.Products + .Where(x => orderLineQuery.All(p => p.Product != x)) + .OrderBy(x => x.ProductId) + .ToListAsync()); + + Assert.That(productsNotInLargestOrders.Count, Is.EqualTo(49), nameof(productsNotInLargestOrders)); + } + [Test(Description = "NH-2654")] public async Task CategoriesWithDiscountedProductsAsync() { diff --git a/src/NHibernate.Test/Linq/WhereSubqueryTests.cs b/src/NHibernate.Test/Linq/WhereSubqueryTests.cs index f272d438707..9f951546406 100644 --- a/src/NHibernate.Test/Linq/WhereSubqueryTests.cs +++ b/src/NHibernate.Test/Linq/WhereSubqueryTests.cs @@ -1,7 +1,9 @@ using System; using System.Linq; using System.Linq.Expressions; +using NHibernate.Dialect; using NHibernate.DomainModel.Northwind.Entities; +using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.Linq @@ -509,6 +511,74 @@ where subquery.Any(x => x.OrderId == order.OrderId) Assert.That(query.Count, Is.EqualTo(61)); } + [Test(Description = "GH2479")] + public void OrdersWithSubquery9() + { + if (Dialect is MySQLDialect) + Assert.Ignore("MySQL does not support LIMIT in subqueries."); + + var ordersQuery = db.Orders + .Where(x => x.Employee.EmployeeId > 5) + .OrderBy(x => x.OrderId) + .Take(2); + + var orderLinesFuture = db.OrderLines + .Where(x => ordersQuery.Any(o => o == x.Order)) + .OrderBy(x => x.Id) + .ToFuture(); + + var orders = ordersQuery.ToFuture().ToList(); + var orderLines = orderLinesFuture.ToList(); + + Assert.That(orders.Count, Is.EqualTo(2), nameof(orders)); + Assert.That(orderLines.Count, Is.EqualTo(6), nameof(orderLines)); + } + + [Test(Description = "GH2479")] + public void OrdersWithSubquery10() + { + if (Dialect is MySQLDialect) + Assert.Ignore("MySQL does not support LIMIT in subqueries."); + + var ordersQuery = db.Orders + .Where(x => x.Employee.EmployeeId > 5) + .OrderBy(x => x.OrderId) + .Take(2); + + var productsQuery = ordersQuery.SelectMany(x => x.OrderLines).Select(x => x.Product); + var productsFuture = db.Products + .Where(x => productsQuery.Contains(x)) + .OrderBy(x => x.ProductId) + .ToFuture(); + + var orders = ordersQuery.ToFuture().ToList(); + var products = productsFuture.ToList(); + + Assert.That(orders.Count, Is.EqualTo(2), nameof(orders)); + Assert.That(products.Count, Is.EqualTo(6), nameof(products)); + } + + [Test(Description = "GH2479")] + public void OrdersWithSubquery11() + { + if (Dialect is MySQLDialect) + Assert.Ignore("MySQL does not support LIMIT in subqueries."); + if (Dialect is MsSqlCeDialect) + Assert.Ignore("MS SQL CE does not support sorting on a subquery."); + + var ordersQuery = db.Orders + .OrderByDescending(x => x.OrderLines.Count).ThenBy(x => x.OrderId) + .Take(2); + + var orderLineQuery = ordersQuery.SelectMany(x => x.OrderLines); + var productsNotInLargestOrders = db.Products + .Where(x => orderLineQuery.All(p => p.Product != x)) + .OrderBy(x => x.ProductId) + .ToList(); + + Assert.That(productsNotInLargestOrders.Count, Is.EqualTo(49), nameof(productsNotInLargestOrders)); + } + [Test(Description = "NH-2654")] public void CategoriesWithDiscountedProducts() { diff --git a/src/NHibernate/Linq/GroupBy/PagingRewriter.cs b/src/NHibernate/Linq/GroupBy/PagingRewriter.cs index 922f1790a10..690330eade0 100644 --- a/src/NHibernate/Linq/GroupBy/PagingRewriter.cs +++ b/src/NHibernate/Linq/GroupBy/PagingRewriter.cs @@ -28,7 +28,7 @@ public static void ReWrite(QueryModel queryModel) private static void FlattenSubQuery(SubQueryExpression subQueryExpression, QueryModel queryModel) { - // we can not flattern subquery if outer query has body clauses. + // we can not flatten subquery if outer query has body clauses. var subQueryModel = subQueryExpression.QueryModel; var subQueryMainFromClause = subQueryModel.MainFromClause; if (queryModel.BodyClauses.Count == 0) @@ -53,7 +53,8 @@ private static void FlattenSubQuery(SubQueryExpression subQueryExpression, Query var where = new WhereClause(new SubQueryExpression(newSubQueryModel)); queryModel.BodyClauses.Add(where); - if (!queryModel.BodyClauses.OfType().Any()) + if (!queryModel.BodyClauses.OfType().Any() && + !(queryModel.ResultOperators.Count == 1 && queryModel.ResultOperators.All(x => x is AnyResultOperator || x is ContainsResultOperator || x is AllResultOperator))) { var orderByClauses = subQueryModel.BodyClauses.OfType(); foreach (var orderByClause in orderByClauses)