diff --git a/src/NHibernate.Test/Async/Linq/ParameterTests.cs b/src/NHibernate.Test/Async/Linq/ParameterTests.cs index 0956fdfe92b..b64e2ef99f4 100644 --- a/src/NHibernate.Test/Async/Linq/ParameterTests.cs +++ b/src/NHibernate.Test/Async/Linq/ParameterTests.cs @@ -125,6 +125,23 @@ public async Task UsingValueTypeParameterTwiceAsync() 1)); } + [Test] + public async Task UsingParameterInEvaluatableExpressionAsync() + { + var value = "test"; + await (db.Orders.Where(o => string.Format("{0}", value) != o.ShippedTo).ToListAsync()); + await (db.Orders.Where(o => $"{value}_" != o.ShippedTo).ToListAsync()); + await (db.Orders.Where(o => string.Copy(value) != o.ShippedTo).ToListAsync()); + + var guid = Guid.Parse("2D7E6EB3-BD08-4A40-A4E7-5150F7895821"); + await (db.Orders.Where(o => o.ShippedTo.Contains($"VALUE {guid}")).ToListAsync()); + + var names = new[] {"name"}; + await (db.Users.Where(x => names.Length == 0 || names.Contains(x.Name)).ToListAsync()); + names = new string[] { }; + await (db.Users.Where(x => names.Length == 0 || names.Contains(x.Name)).ToListAsync()); + } + [Test] public async Task UsingNegateValueTypeParameterTwiceAsync() { diff --git a/src/NHibernate.Test/Linq/ParameterTests.cs b/src/NHibernate.Test/Linq/ParameterTests.cs index cab27fe9dd5..c406ea68929 100644 --- a/src/NHibernate.Test/Linq/ParameterTests.cs +++ b/src/NHibernate.Test/Linq/ParameterTests.cs @@ -113,6 +113,23 @@ public void UsingValueTypeParameterTwice() 1); } + [Test] + public void UsingParameterInEvaluatableExpression() + { + var value = "test"; + db.Orders.Where(o => string.Format("{0}", value) != o.ShippedTo).ToList(); + db.Orders.Where(o => $"{value}_" != o.ShippedTo).ToList(); + db.Orders.Where(o => string.Copy(value) != o.ShippedTo).ToList(); + + var guid = Guid.Parse("2D7E6EB3-BD08-4A40-A4E7-5150F7895821"); + db.Orders.Where(o => o.ShippedTo.Contains($"VALUE {guid}")).ToList(); + + var names = new[] {"name"}; + db.Users.Where(x => names.Length == 0 || names.Contains(x.Name)).ToList(); + names = new string[] { }; + db.Users.Where(x => names.Length == 0 || names.Contains(x.Name)).ToList(); + } + [Test] public void ValidateMixingTwoParametersCacheKeys() { diff --git a/src/NHibernate/Linq/Visitors/NhPartialEvaluatingExpressionVisitor.cs b/src/NHibernate/Linq/Visitors/NhPartialEvaluatingExpressionVisitor.cs index 45ac8ffcca5..9ee40092e6b 100644 --- a/src/NHibernate/Linq/Visitors/NhPartialEvaluatingExpressionVisitor.cs +++ b/src/NHibernate/Linq/Visitors/NhPartialEvaluatingExpressionVisitor.cs @@ -77,7 +77,12 @@ public override Expression Visit(Expression expression) if (expression == null) return null; - if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression)) + if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression) || + #region NH additions + // Variables should be evaluated only when they are part of an evaluatable expression (e.g. o => string.Format("...", variable)) + expression is UnaryExpression unaryExpression && + ExpressionsHelper.IsVariable(unaryExpression.Operand, out _, out _)) + #endregion return base.Visit(expression); Expression evaluatedExpression; @@ -211,11 +216,6 @@ public override bool IsEvaluatableConstant(ConstantExpression node) return base.IsEvaluatableConstant(node); } - public override bool IsEvaluatableUnary(UnaryExpression node) - { - return !ExpressionsHelper.IsVariable(node.Operand, out _, out _); - } - public override bool IsEvaluatableMember(MemberExpression node) { if (node == null)