Skip to content

Commit 2662dc3

Browse files
committed
Cache Dml queries
1 parent a41010f commit 2662dc3

File tree

3 files changed

+69
-5
lines changed

3 files changed

+69
-5
lines changed

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
using System.Reflection;
1414
using NHibernate.DomainModel.Northwind.Entities;
1515
using NHibernate.Engine.Query;
16+
using NHibernate.Linq;
1617
using NHibernate.Linq.Visitors;
1718
using NHibernate.Util;
1819
using NUnit.Framework;
19-
using NHibernate.Linq;
2020

2121
namespace NHibernate.Test.Linq
2222
{
@@ -237,6 +237,36 @@ public async Task PlansAreCachedAsync()
237237
}
238238
}
239239

240+
[Test]
241+
public async Task DmlPlansAreCachedAsync()
242+
{
243+
var queryPlanCacheType = typeof(QueryPlanCache);
244+
245+
var cache = (SoftLimitMRUCache)
246+
queryPlanCacheType
247+
.GetField("planCache", BindingFlags.Instance | BindingFlags.NonPublic)
248+
.GetValue(Sfi.QueryPlanCache);
249+
cache.Clear();
250+
251+
await (db.Customers.Where(c => c.CustomerId == "ALFKI").UpdateAsync(x => new Customer {CompanyName = x.CompanyName}));
252+
Assert.That(
253+
cache,
254+
Has.Count.EqualTo(1),
255+
"First query plan should be cached.");
256+
257+
using (var spy = new LogSpy(queryPlanCacheType))
258+
{
259+
// Should hit plan cache.
260+
await (db.Customers.Where(c => c.CustomerId == "ALFKI").UpdateAsync(x => new Customer {CompanyName = x.CompanyName}));
261+
Assert.That(cache, Has.Count.EqualTo(1), "Second query should not cause a plan to be cache.");
262+
Assert.That(
263+
spy.GetWholeLog(),
264+
Does
265+
.Contain("located HQL query plan in cache")
266+
.And.Not.Contain("unable to locate HQL query plan in cache"));
267+
}
268+
}
269+
240270
[Test]
241271
public async Task PlansWithNonParameterizedConstantsAreNotCachedAsync()
242272
{

src/NHibernate.Test/Linq/ConstantTest.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Reflection;
44
using NHibernate.DomainModel.Northwind.Entities;
55
using NHibernate.Engine.Query;
6+
using NHibernate.Linq;
67
using NHibernate.Linq.Visitors;
78
using NHibernate.Util;
89
using NUnit.Framework;
@@ -257,6 +258,36 @@ public void PlansAreCached()
257258
}
258259
}
259260

261+
[Test]
262+
public void DmlPlansAreCached()
263+
{
264+
var queryPlanCacheType = typeof(QueryPlanCache);
265+
266+
var cache = (SoftLimitMRUCache)
267+
queryPlanCacheType
268+
.GetField("planCache", BindingFlags.Instance | BindingFlags.NonPublic)
269+
.GetValue(Sfi.QueryPlanCache);
270+
cache.Clear();
271+
272+
db.Customers.Where(c => c.CustomerId == "ALFKI").Update(x => new Customer {CompanyName = x.CompanyName});
273+
Assert.That(
274+
cache,
275+
Has.Count.EqualTo(1),
276+
"First query plan should be cached.");
277+
278+
using (var spy = new LogSpy(queryPlanCacheType))
279+
{
280+
// Should hit plan cache.
281+
db.Customers.Where(c => c.CustomerId == "ALFKI").Update(x => new Customer {CompanyName = x.CompanyName});
282+
Assert.That(cache, Has.Count.EqualTo(1), "Second query should not cause a plan to be cache.");
283+
Assert.That(
284+
spy.GetWholeLog(),
285+
Does
286+
.Contain("located HQL query plan in cache")
287+
.And.Not.Contain("unable to locate HQL query plan in cache"));
288+
}
289+
}
290+
260291
[Test]
261292
public void PlansWithNonParameterizedConstantsAreNotCached()
262293
{

src/NHibernate/Linq/NhLinqExpression.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,16 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter
8888

8989
ParameterDescriptors = requiredHqlParameters.AsReadOnly();
9090

91-
CanCachePlan = CanCachePlan &&
92-
// If some constants do not have matching HQL parameters, their values from first query will
93-
// be embedded in the plan and reused for subsequent queries: do not cache the plan.
94-
!ParameterValuesByName
91+
if (QueryMode == QueryMode.Select && CanCachePlan)
92+
{
93+
CanCachePlan =
94+
// If some constants do not have matching HQL parameters, their values from first query will
95+
// be embedded in the plan and reused for subsequent queries: do not cache the plan.
96+
!ParameterValuesByName
9597
.Keys
9698
.Except(requiredHqlParameters.Select(p => p.Name))
9799
.Any();
100+
}
98101

99102
// The ast node may be altered by caller, duplicate it for preserving the original one.
100103
return DuplicateTree(ExpressionToHqlTranslationResults.Statement.AstNode);

0 commit comments

Comments
 (0)