Skip to content

Commit 8eabc3c

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

File tree

5 files changed

+56
-32
lines changed

5 files changed

+56
-32
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: 14 additions & 14 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,18 +36,13 @@ 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

4444
/// <summary>
45-
/// Indicates if <see cref="Result"/> was obtained from the cache.
45+
/// Indicates if the query result was obtained from the cache.
4646
/// </summary>
4747
bool IsResultFromCache { get; }
4848

@@ -52,14 +52,14 @@ public interface ICachingInformation
5252
IType[] ResultTypes { get; }
5353

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

5959
/// <summary>
60-
/// The query cache key.
60+
/// The query identifier, for statistics purpose.
6161
/// </summary>
62-
QueryKey CacheKey { get; }
62+
string QueryIdentifier { get; }
6363

6464
/// <summary>
6565
/// 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: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,48 @@ 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 />
5162
public bool IsResultFromCache { get; private set; }
63+
64+
/// <inheritdoc />
65+
public IList ResultToCache { get; set; }
66+
67+
/// <summary>
68+
/// Should a result retrieved from database be cached?
69+
/// </summary>
70+
public bool CanPutToCache { get; }
71+
5272
/// <summary>
5373
/// The cache batcher to use for entities and collections puts.
5474
/// </summary>
@@ -75,6 +95,7 @@ public QueryInfo(
7595

7696
CacheKey = Loader.GenerateQueryKey(session, Parameters);
7797
CanGetFromCache = Loader.CanGetFromCache(session, Parameters);
98+
CanPutToCache = session.CacheMode.HasFlag(CacheMode.Put);
7899
}
79100

80101
/// <inheritdoc />
@@ -213,6 +234,8 @@ public int ProcessResultsSet(DbDataReader reader)
213234
}
214235

215236
queryInfo.Result = tmpResults;
237+
if (queryInfo.CanPutToCache)
238+
queryInfo.ResultToCache = tmpResults;
216239

217240
reader.NextResult();
218241
}
@@ -237,8 +260,7 @@ public void ProcessResults()
237260

238261
if (queryInfo.IsCacheable)
239262
{
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.
263+
// This transformation must not be applied to ResultToCache.
242264
queryInfo.Result =
243265
queryInfo.Loader.TransformCacheableResults(
244266
queryInfo.Parameters, queryInfo.CacheKey.ResultTransformer, queryInfo.Result);
@@ -261,7 +283,7 @@ protected List<T> GetTypedResults<T>()
261283
ThrowIfNotInitialized();
262284
if (_queryInfos.Any(qi => qi.Result == null))
263285
{
264-
throw new InvalidOperationException("Batch is not executed yet. You must call IQueryBatch.Execute() before accessing results.");
286+
throw new InvalidOperationException("Some query results are missing, batch is likely not fully executed yet.");
265287
}
266288
var results = new List<T>(_queryInfos.Sum(qi => qi.Result.Count));
267289
foreach (var queryInfo in _queryInfos)
@@ -302,7 +324,11 @@ private void InitializeEntitiesAndCollections(DbDataReader reader, List<object>[
302324
private void ThrowIfNotInitialized()
303325
{
304326
if (_queryInfos == null)
305-
throw new InvalidOperationException("The query item has not been initialized.");
327+
throw new InvalidOperationException(
328+
"The query item has not been initialized. A query item must belong to a batch " +
329+
$"({nameof(IQueryBatch)}) and the batch must be executed ({nameof(IQueryBatch)}." +
330+
$"{nameof(IQueryBatch.Execute)} or {nameof(IQueryBatch)}.{nameof(IQueryBatch.GetResult)}) " +
331+
"before retrieving the item result.");
306332
}
307333
}
308334
}

0 commit comments

Comments
 (0)