From 4b63457022d4f27d07f220a9a301f69c40ece551 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Fri, 18 Aug 2023 16:16:44 +0200 Subject: [PATCH 1/4] Reenable use of SelectClauseVisitor for subqueries --- src/NHibernate.Test/Async/Linq/WhereTests.cs | 13 +++++++++++++ src/NHibernate.Test/Linq/WhereTests.cs | 13 +++++++++++++ src/NHibernate/Linq/Visitors/QueryModelVisitor.cs | 6 +----- .../Linq/Visitors/SelectClauseNominator.cs | 4 ++-- src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs | 4 ++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/Async/Linq/WhereTests.cs b/src/NHibernate.Test/Async/Linq/WhereTests.cs index aceda381352..365ad00de7f 100644 --- a/src/NHibernate.Test/Async/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Async/Linq/WhereTests.cs @@ -659,6 +659,19 @@ where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) Assert.That(query.Count, Is.EqualTo(1)); } + [Test] + public async Task TimesheetsWithProjectionInSubqueryAsync() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = await ((from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToListAsync()); + + Assert.That(query.Count, Is.EqualTo(2)); + } + [Test] public async Task ContainsSubqueryWithCoalesceStringEnumSelectAsync() { diff --git a/src/NHibernate.Test/Linq/WhereTests.cs b/src/NHibernate.Test/Linq/WhereTests.cs index 5fffc56c052..90981dbc4d1 100644 --- a/src/NHibernate.Test/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Linq/WhereTests.cs @@ -660,6 +660,19 @@ where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) Assert.That(query.Count, Is.EqualTo(1)); } + [Test] + public void TimesheetsWithProjectionInSubquery() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = (from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToList(); + + Assert.That(query.Count, Is.EqualTo(2)); + } + [Test] public void ContainsSubqueryWithCoalesceStringEnumSelect() { diff --git a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs index c9f2a054bb1..43720cb12fb 100644 --- a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs +++ b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs @@ -476,13 +476,9 @@ public override void VisitSelectClause(SelectClause selectClause, QueryModel que private HqlSelect GetSelectClause(Expression selectClause) { - if (!_root) - return _hqlTree.TreeBuilder.Select( - HqlGeneratorExpressionVisitor.Visit(selectClause, VisitorParameters).AsExpression()); - var visitor = new SelectClauseVisitor(typeof(object[]), VisitorParameters); - visitor.VisitSelector(selectClause); + visitor.VisitSelector(selectClause, !_root); if (visitor.ProjectionExpression != null) { diff --git a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs index 52bf954101d..0ab0dc25e4d 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs @@ -43,13 +43,13 @@ public SelectClauseHqlNominator(VisitorParameters parameters) _parameters = parameters; } - internal Expression Nominate(Expression expression) + internal Expression Nominate(Expression expression, bool isSubQuery = false) { HqlCandidates = new HashSet(); ContainsUntranslatedMethodCalls = false; _canBeCandidate = true; _stateStack = new Stack(); - _stateStack.Push(false); + _stateStack.Push(isSubQuery); return Visit(expression); } diff --git a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs index df1cdfb3daa..e72fdf68c21 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs @@ -34,7 +34,7 @@ public IEnumerable GetHqlNodes() return _hqlTreeNodes; } - public void VisitSelector(Expression expression) + public void VisitSelector(Expression expression, bool isSubQuery = false) { var distinct = expression as NhDistinctExpression; if (distinct != null) @@ -44,7 +44,7 @@ public void VisitSelector(Expression expression) // Find the sub trees that can be expressed purely in HQL var nominator = new SelectClauseHqlNominator(_parameters); - expression = nominator.Nominate(expression); + expression = nominator.Nominate(expression, isSubQuery); _hqlNodes = nominator.HqlCandidates; // Linq2SQL ignores calls to local methods. Linq2EF seems to not support From 4f378ceb61c198e72aae2e9f4150c3cbd16d23a2 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Sun, 20 Aug 2023 12:07:57 +0200 Subject: [PATCH 2/4] Unbreak breaking change --- src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs index e72fdf68c21..88d1b49a43c 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs @@ -33,8 +33,8 @@ public IEnumerable GetHqlNodes() { return _hqlTreeNodes; } - - public void VisitSelector(Expression expression, bool isSubQuery = false) + public void VisitSelector(Expression expression) => VisitSelector(expression, false); + public void VisitSelector(Expression expression, bool isSubQuery) { var distinct = expression as NhDistinctExpression; if (distinct != null) From 56e5d34ffa828ed16db80d4c87d64042c16e36a5 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Sun, 20 Aug 2023 21:20:11 +0200 Subject: [PATCH 3/4] Update src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs index 88d1b49a43c..a5ccb83b1e3 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs @@ -34,6 +34,7 @@ public IEnumerable GetHqlNodes() return _hqlTreeNodes; } public void VisitSelector(Expression expression) => VisitSelector(expression, false); + public void VisitSelector(Expression expression, bool isSubQuery) { var distinct = expression as NhDistinctExpression; From 81788accd4054fd9e01a49db86e0f92e42b07d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 20 Aug 2023 23:27:47 +0200 Subject: [PATCH 4/4] Update src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs --- src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs index a5ccb83b1e3..a5155415dfd 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs @@ -33,6 +33,7 @@ public IEnumerable GetHqlNodes() { return _hqlTreeNodes; } + public void VisitSelector(Expression expression) => VisitSelector(expression, false); public void VisitSelector(Expression expression, bool isSubQuery)