Skip to content

Commit 455f664

Browse files
fixup! Implement multiple get and put for query cache and query batch
Adjust code according to review
1 parent afe7130 commit 455f664

File tree

5 files changed

+57
-36
lines changed

5 files changed

+57
-36
lines changed

src/NHibernate/Async/Multi/QueryBatch.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ protected async Task ExecuteBatchedAsync(CancellationToken cancellationToken)
150150
}
151151
}
152152

153-
// Query cacheable results must be put in cache before being transformed by ProcessResults.
153+
// Query cacheable results must be cached untransformed: the put does not need to wait for
154+
// the ProcessResults.
154155
await (PutCacheableResultsAsync(cancellationToken)).ConfigureAwait(false);
155156

156157
foreach (var multiSource in _queries)
@@ -228,11 +229,8 @@ private async Task GetCachedResultsAsync(CancellationToken cancellationToken)
228229
private async Task PutCacheableResultsAsync(CancellationToken cancellationToken)
229230
{
230231
cancellationToken.ThrowIfCancellationRequested();
231-
if (!Session.CacheMode.HasFlag(CacheMode.Put))
232-
return;
233-
234232
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
235-
var queriesByCaches = GetQueriesByCaches(ci => ci.IsCacheable && !ci.IsResultFromCache);
233+
var queriesByCaches = GetQueriesByCaches(ci => ci.ResultToCache != null);
236234
foreach (var queriesByCache in queriesByCaches)
237235
{
238236
var queryInfos = queriesByCache.ToArray();
@@ -247,7 +245,7 @@ private async Task PutCacheableResultsAsync(CancellationToken cancellationToken)
247245
keys[i] = queryInfo.CacheKey;
248246
parameters[i] = queryInfo.Parameters;
249247
returnTypes[i] = queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.ResultTypes);
250-
results[i] = queryInfo.Result;
248+
results[i] = queryInfo.ResultToCache;
251249
}
252250

253251
var putted = await (cache.PutManyAsync(keys, parameters, returnTypes, results, Session, cancellationToken)).ConfigureAwait(false);

src/NHibernate/Async/Multi/QueryBatchItemBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public async Task<int> ProcessResultsSetAsync(DbDataReader reader, CancellationT
100100
}
101101

102102
queryInfo.Result = tmpResults;
103+
if (queryInfo.CanPutToCache)
104+
queryInfo.ResultToCache = tmpResults;
103105

104106
await (reader.NextResultAsync(cancellationToken)).ConfigureAwait(false);
105107
}

src/NHibernate/Multi/ICachingInformation.cs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ namespace NHibernate.Multi
1212
public interface ICachingInformation
1313
{
1414
/// <summary>
15-
/// The query parameters.
15+
/// Is the query cacheable?
1616
/// </summary>
17-
QueryParameters Parameters { get; }
17+
bool IsCacheable { get; }
1818

1919
/// <summary>
20-
/// The query result.
20+
/// The query cache key.
2121
/// </summary>
22-
IList Result { get; }
22+
QueryKey CacheKey { get; }
23+
24+
/// <summary>
25+
/// The query parameters.
26+
/// </summary>
27+
QueryParameters Parameters { get; }
2328

2429
/// <summary>
2530
/// The query spaces.
@@ -31,35 +36,25 @@ public interface ICachingInformation
3136
/// </remarks>
3237
ISet<string> QuerySpaces { get; }
3338

34-
/// <summary>
35-
/// Is the query cacheable?
36-
/// </summary>
37-
bool IsCacheable { get; }
38-
3939
/// <summary>
4040
/// Can the query be obtained from cache?
4141
/// </summary>
4242
bool CanGetFromCache { get; }
4343

44-
/// <summary>
45-
/// Indicates if <see cref="Result"/> was obtained from the cache.
46-
/// </summary>
47-
bool IsResultFromCache { get; }
48-
4944
/// <summary>
5045
/// The query result types.
5146
/// </summary>
5247
IType[] ResultTypes { get; }
5348

5449
/// <summary>
55-
/// The query identifier, for statistics purpose.
50+
/// The query result to put in the cache. <see langword="null" /> if no put should be done.
5651
/// </summary>
57-
string QueryIdentifier { get; }
52+
IList ResultToCache { get; }
5853

5954
/// <summary>
60-
/// The query cache key.
55+
/// The query identifier, for statistics purpose.
6156
/// </summary>
62-
QueryKey CacheKey { get; }
57+
string QueryIdentifier { get; }
6358

6459
/// <summary>
6560
/// Set the result retrieved from the cache.

src/NHibernate/Multi/QueryBatch.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ protected void ExecuteBatched()
176176
}
177177
}
178178

179-
// Query cacheable results must be put in cache before being transformed by ProcessResults.
179+
// Query cacheable results must be cached untransformed: the put does not need to wait for
180+
// the ProcessResults.
180181
PutCacheableResults();
181182

182183
foreach (var multiSource in _queries)
@@ -260,11 +261,8 @@ private void CombineQueries(IResultSetsCommand resultSetsCommand)
260261

261262
private void PutCacheableResults()
262263
{
263-
if (!Session.CacheMode.HasFlag(CacheMode.Put))
264-
return;
265-
266264
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
267-
var queriesByCaches = GetQueriesByCaches(ci => ci.IsCacheable && !ci.IsResultFromCache);
265+
var queriesByCaches = GetQueriesByCaches(ci => ci.ResultToCache != null);
268266
foreach (var queriesByCache in queriesByCaches)
269267
{
270268
var queryInfos = queriesByCache.ToArray();
@@ -279,7 +277,7 @@ private void PutCacheableResults()
279277
keys[i] = queryInfo.CacheKey;
280278
parameters[i] = queryInfo.Parameters;
281279
returnTypes[i] = queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.ResultTypes);
282-
results[i] = queryInfo.Result;
280+
results[i] = queryInfo.ResultToCache;
283281
}
284282

285283
var putted = cache.PutMany(keys, parameters, returnTypes, results, Session);

src/NHibernate/Multi/QueryBatchItemBase.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,50 @@ protected class QueryInfo : ICachingInformation
2727
/// The query loader.
2828
/// </summary>
2929
public Loader.Loader Loader { get; set; }
30+
31+
/// <summary>
32+
/// The query result.
33+
/// </summary>
34+
public IList Result { get; set; }
35+
3036
/// <inheritdoc />
3137
public QueryParameters Parameters { get; }
32-
/// <inheritdoc />
33-
public IList Result { get; set; }
38+
3439
/// <inheritdoc />
3540
public ISet<string> QuerySpaces { get; }
3641

3742
//Cache related properties:
43+
3844
/// <inheritdoc />
3945
public bool IsCacheable { get; }
46+
4047
/// <inheritdoc />
4148
public QueryKey CacheKey { get;}
49+
4250
/// <inheritdoc />
4351
public bool CanGetFromCache { get; }
52+
4453
// Do not store but forward instead: Loader.ResultTypes can be null initially (if AutoDiscoverTypes
4554
// is enabled).
4655
/// <inheritdoc />
4756
public IType[] ResultTypes => Loader.ResultTypes;
57+
4858
/// <inheritdoc />
4959
public string QueryIdentifier => Loader.QueryIdentifier;
60+
5061
/// <inheritdoc />
62+
public IList ResultToCache { get; set; }
63+
64+
/// <summary>
65+
/// Indicates if the query result was obtained from the cache.
66+
/// </summary>
5167
public bool IsResultFromCache { get; private set; }
68+
69+
/// <summary>
70+
/// Should a result retrieved from database be cached?
71+
/// </summary>
72+
public bool CanPutToCache { get; }
73+
5274
/// <summary>
5375
/// The cache batcher to use for entities and collections puts.
5476
/// </summary>
@@ -75,6 +97,7 @@ public QueryInfo(
7597

7698
CacheKey = Loader.GenerateQueryKey(session, Parameters);
7799
CanGetFromCache = Loader.CanGetFromCache(session, Parameters);
100+
CanPutToCache = session.CacheMode.HasFlag(CacheMode.Put);
78101
}
79102

80103
/// <inheritdoc />
@@ -213,6 +236,8 @@ public int ProcessResultsSet(DbDataReader reader)
213236
}
214237

215238
queryInfo.Result = tmpResults;
239+
if (queryInfo.CanPutToCache)
240+
queryInfo.ResultToCache = tmpResults;
216241

217242
reader.NextResult();
218243
}
@@ -237,8 +262,7 @@ public void ProcessResults()
237262

238263
if (queryInfo.IsCacheable)
239264
{
240-
// This transformation must be done after result has been put in cache (if it was
241-
// to be put). So the batcher must handle cache puts before calling ProcessResults.
265+
// This transformation must not be applied to ResultToCache.
242266
queryInfo.Result =
243267
queryInfo.Loader.TransformCacheableResults(
244268
queryInfo.Parameters, queryInfo.CacheKey.ResultTransformer, queryInfo.Result);
@@ -261,7 +285,7 @@ protected List<T> GetTypedResults<T>()
261285
ThrowIfNotInitialized();
262286
if (_queryInfos.Any(qi => qi.Result == null))
263287
{
264-
throw new InvalidOperationException("Batch is not executed yet. You must call IQueryBatch.Execute() before accessing results.");
288+
throw new InvalidOperationException("Some query results are missing, batch is likely not fully executed yet.");
265289
}
266290
var results = new List<T>(_queryInfos.Sum(qi => qi.Result.Count));
267291
foreach (var queryInfo in _queryInfos)
@@ -302,7 +326,11 @@ private void InitializeEntitiesAndCollections(DbDataReader reader, List<object>[
302326
private void ThrowIfNotInitialized()
303327
{
304328
if (_queryInfos == null)
305-
throw new InvalidOperationException("The query item has not been initialized.");
329+
throw new InvalidOperationException(
330+
"The query item has not been initialized. A query item must belong to a batch " +
331+
$"({nameof(IQueryBatch)}) and the batch must be executed ({nameof(IQueryBatch)}." +
332+
$"{nameof(IQueryBatch.Execute)} or {nameof(IQueryBatch)}.{nameof(IQueryBatch.GetResult)}) " +
333+
"before retrieving the item result.");
306334
}
307335
}
308336
}

0 commit comments

Comments
 (0)