diff --git a/src/NHibernate.Test/Async/Linq/ConstantTest.cs b/src/NHibernate.Test/Async/Linq/ConstantTest.cs index 215aa6e8dbd..9c2558a6902 100644 --- a/src/NHibernate.Test/Async/Linq/ConstantTest.cs +++ b/src/NHibernate.Test/Async/Linq/ConstantTest.cs @@ -22,6 +22,7 @@ namespace NHibernate.Test.Linq { using System.Threading.Tasks; + using System.Threading; // Mainly adapted from tests contributed by Nicola Tuveri on NH-2500 (NH-2500.patch file) [TestFixture] public class ConstantTestAsync : LinqTestCase @@ -118,6 +119,29 @@ public async Task ConstantNonCachedInMemberInitExpressionAsync() Assert.That(s2, Has.All.Property("Name").EqualTo("shipper2"), "s2 Names"); } + [Test] + public async Task ConstantNonCachedInMemberInitExpressionWithConditionAsync() + { + var shipper1 = await (GetShipperAsync(1)); + var shipper2 = await (GetShipperAsync(2)); + + Assert.That(shipper1.Number, Is.EqualTo(1)); + Assert.That(shipper2.Number, Is.EqualTo(2)); + } + + private Task GetShipperAsync(int id, CancellationToken cancellationToken = default(CancellationToken)) + { + try + { + return db.Shippers.Where(o => o.ShipperId == id) + .Select(o => new ShipperDto {Number = id, CompanyName = o.CompanyName}).SingleAsync(cancellationToken); + } + catch (System.Exception ex) + { + return Task.FromException(ex); + } + } + [Test] public async Task ConstantInNewArrayExpressionAsync() { diff --git a/src/NHibernate.Test/Linq/ConstantTest.cs b/src/NHibernate.Test/Linq/ConstantTest.cs index f75bf3a9070..74b20f13afb 100644 --- a/src/NHibernate.Test/Linq/ConstantTest.cs +++ b/src/NHibernate.Test/Linq/ConstantTest.cs @@ -120,6 +120,22 @@ public void ConstantNonCachedInMemberInitExpression() Assert.That(s2, Has.All.Property("Name").EqualTo("shipper2"), "s2 Names"); } + [Test] + public void ConstantNonCachedInMemberInitExpressionWithCondition() + { + var shipper1 = GetShipper(1); + var shipper2 = GetShipper(2); + + Assert.That(shipper1.Number, Is.EqualTo(1)); + Assert.That(shipper2.Number, Is.EqualTo(2)); + } + + private ShipperDto GetShipper(int id) + { + return db.Shippers.Where(o => o.ShipperId == id) + .Select(o => new ShipperDto {Number = id, CompanyName = o.CompanyName}).Single(); + } + [Test] public void ConstantInNewArrayExpression() { diff --git a/src/NHibernate/Linq/NhLinqExpression.cs b/src/NHibernate/Linq/NhLinqExpression.cs index 671d949fc02..4c41b4c489c 100644 --- a/src/NHibernate/Linq/NhLinqExpression.cs +++ b/src/NHibernate/Linq/NhLinqExpression.cs @@ -101,7 +101,7 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter ParameterDescriptors = requiredHqlParameters.AsReadOnly(); - CanCachePlan = CanCachePlan && + CanCachePlan = CanCachePlan && visitorParameters.CanCachePlan && // If some constants do not have matching HQL parameters, their values from first query will // be embedded in the plan and reused for subsequent queries: do not cache the plan. !ParameterValuesByName diff --git a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs index 10d7bd07d3c..52bf954101d 100644 --- a/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs +++ b/src/NHibernate/Linq/Visitors/SelectClauseNominator.cs @@ -4,6 +4,7 @@ using NHibernate.Engine; using NHibernate.Linq.Functions; using NHibernate.Linq.Expressions; +using NHibernate.Param; using NHibernate.Util; using Remotion.Linq.Parsing; @@ -17,6 +18,7 @@ class SelectClauseHqlNominator : RelinqExpressionVisitor { private readonly ILinqToHqlGeneratorsRegistry _functionRegistry; private readonly ISessionFactoryImplementor _sessionFactory; + private readonly VisitorParameters _parameters; /// /// The expression parts that can be converted to pure HQL. @@ -38,6 +40,7 @@ public SelectClauseHqlNominator(VisitorParameters parameters) { _functionRegistry = parameters.SessionFactory.Settings.LinqToHqlGeneratorsRegistry; _sessionFactory = parameters.SessionFactory; + _parameters = parameters; } internal Expression Nominate(Expression expression) @@ -152,6 +155,11 @@ private bool CanBeEvaluatedInHqlSelectStatement(Expression expression, bool proj // Constants will only be evaluated in HQL if they're inside a method call if (expression.NodeType == ExpressionType.Constant) { + if (!projectConstantsInHql && _parameters.ConstantToParameterMap.ContainsKey((ConstantExpression)expression)) + { + _parameters.CanCachePlan = false; + } + return projectConstantsInHql; } diff --git a/src/NHibernate/Linq/Visitors/VisitorParameters.cs b/src/NHibernate/Linq/Visitors/VisitorParameters.cs index a4d2a1f2c65..cf53c6ec119 100644 --- a/src/NHibernate/Linq/Visitors/VisitorParameters.cs +++ b/src/NHibernate/Linq/Visitors/VisitorParameters.cs @@ -23,6 +23,8 @@ public class VisitorParameters public QueryMode RootQueryMode { get; } + internal bool CanCachePlan { get; set; } = true; + public VisitorParameters( ISessionFactoryImplementor sessionFactory, IDictionary constantToParameterMap, @@ -39,4 +41,4 @@ public VisitorParameters( RootQueryMode = rootQueryMode; } } -} \ No newline at end of file +}