Skip to content

Commit 98de5ae

Browse files
maca88fredericDelaporte
authored andcommitted
Fix parameter caching for Linq provider
1 parent 7360394 commit 98de5ae

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed

src/NHibernate.Test/Async/Linq/ConstantTest.cs

+24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
namespace NHibernate.Test.Linq
2323
{
2424
using System.Threading.Tasks;
25+
using System.Threading;
2526
// Mainly adapted from tests contributed by Nicola Tuveri on NH-2500 (NH-2500.patch file)
2627
[TestFixture]
2728
public class ConstantTestAsync : LinqTestCase
@@ -118,6 +119,29 @@ public async Task ConstantNonCachedInMemberInitExpressionAsync()
118119
Assert.That(s2, Has.All.Property("Name").EqualTo("shipper2"), "s2 Names");
119120
}
120121

122+
[Test]
123+
public async Task ConstantNonCachedInMemberInitExpressionWithConditionAsync()
124+
{
125+
var shipper1 = await (GetShipperAsync(1));
126+
var shipper2 = await (GetShipperAsync(2));
127+
128+
Assert.That(shipper1.Number, Is.EqualTo(1));
129+
Assert.That(shipper2.Number, Is.EqualTo(2));
130+
}
131+
132+
private Task<ShipperDto> GetShipperAsync(int id, CancellationToken cancellationToken = default(CancellationToken))
133+
{
134+
try
135+
{
136+
return db.Shippers.Where(o => o.ShipperId == id)
137+
.Select(o => new ShipperDto {Number = id, CompanyName = o.CompanyName}).SingleAsync(cancellationToken);
138+
}
139+
catch (System.Exception ex)
140+
{
141+
return Task.FromException<ShipperDto>(ex);
142+
}
143+
}
144+
121145
[Test]
122146
public async Task ConstantInNewArrayExpressionAsync()
123147
{

src/NHibernate.Test/Linq/ConstantTest.cs

+16
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,22 @@ public void ConstantNonCachedInMemberInitExpression()
120120
Assert.That(s2, Has.All.Property("Name").EqualTo("shipper2"), "s2 Names");
121121
}
122122

123+
[Test]
124+
public void ConstantNonCachedInMemberInitExpressionWithCondition()
125+
{
126+
var shipper1 = GetShipper(1);
127+
var shipper2 = GetShipper(2);
128+
129+
Assert.That(shipper1.Number, Is.EqualTo(1));
130+
Assert.That(shipper2.Number, Is.EqualTo(2));
131+
}
132+
133+
private ShipperDto GetShipper(int id)
134+
{
135+
return db.Shippers.Where(o => o.ShipperId == id)
136+
.Select(o => new ShipperDto {Number = id, CompanyName = o.CompanyName}).Single();
137+
}
138+
123139
[Test]
124140
public void ConstantInNewArrayExpression()
125141
{

src/NHibernate/Linq/NhLinqExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter
101101

102102
ParameterDescriptors = requiredHqlParameters.AsReadOnly();
103103

104-
CanCachePlan = CanCachePlan &&
104+
CanCachePlan = CanCachePlan && visitorParameters.CanCachePlan &&
105105
// If some constants do not have matching HQL parameters, their values from first query will
106106
// be embedded in the plan and reused for subsequent queries: do not cache the plan.
107107
!ParameterValuesByName

src/NHibernate/Linq/Visitors/SelectClauseNominator.cs

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using NHibernate.Engine;
55
using NHibernate.Linq.Functions;
66
using NHibernate.Linq.Expressions;
7+
using NHibernate.Param;
78
using NHibernate.Util;
89
using Remotion.Linq.Parsing;
910

@@ -17,6 +18,7 @@ class SelectClauseHqlNominator : RelinqExpressionVisitor
1718
{
1819
private readonly ILinqToHqlGeneratorsRegistry _functionRegistry;
1920
private readonly ISessionFactoryImplementor _sessionFactory;
21+
private readonly VisitorParameters _parameters;
2022

2123
/// <summary>
2224
/// The expression parts that can be converted to pure HQL.
@@ -38,6 +40,7 @@ public SelectClauseHqlNominator(VisitorParameters parameters)
3840
{
3941
_functionRegistry = parameters.SessionFactory.Settings.LinqToHqlGeneratorsRegistry;
4042
_sessionFactory = parameters.SessionFactory;
43+
_parameters = parameters;
4144
}
4245

4346
internal Expression Nominate(Expression expression)
@@ -152,6 +155,11 @@ private bool CanBeEvaluatedInHqlSelectStatement(Expression expression, bool proj
152155
// Constants will only be evaluated in HQL if they're inside a method call
153156
if (expression.NodeType == ExpressionType.Constant)
154157
{
158+
if (!projectConstantsInHql && _parameters.ConstantToParameterMap.ContainsKey((ConstantExpression)expression))
159+
{
160+
_parameters.CanCachePlan = false;
161+
}
162+
155163
return projectConstantsInHql;
156164
}
157165

src/NHibernate/Linq/Visitors/VisitorParameters.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public class VisitorParameters
2323

2424
public QueryMode RootQueryMode { get; }
2525

26+
internal bool CanCachePlan { get; set; } = true;
27+
2628
public VisitorParameters(
2729
ISessionFactoryImplementor sessionFactory,
2830
IDictionary<ConstantExpression, NamedParameter> constantToParameterMap,
@@ -39,4 +41,4 @@ public VisitorParameters(
3941
RootQueryMode = rootQueryMode;
4042
}
4143
}
42-
}
44+
}

0 commit comments

Comments
 (0)