Skip to content

Commit 0cba4e0

Browse files
NH-4077 - Do not trigger flush during auto-flush either.
1 parent 8604a4c commit 0cba4e0

File tree

10 files changed

+272
-225
lines changed

10 files changed

+272
-225
lines changed

src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ public async Task AutoflushInPostInsertListener_CausesDuplicateInserts_WithPrima
4040
}
4141
}
4242

43+
[Test]
44+
public async Task Autoflush_MayTriggerAdditionalAutoFlushFromEventsAsync()
45+
{
46+
using (var session = OpenSession())
47+
using (var transaction = session.BeginTransaction())
48+
{
49+
// using FlushMode.Commit prevents the issue; using the default FlushMode.Auto breaks.
50+
//session.FlushMode = FlushMode.Commit;
51+
await (session.SaveAsync(new Entity { Code = "one" }));
52+
await (session.SaveAsync(new Entity { Code = "two" }));
53+
54+
// Querying the entity triggers an auto-flush
55+
var count = await (session.CreateQuery("select count(o) from Entity o").UniqueResultAsync<long>());
56+
Assert.That(count, Is.GreaterThan(0));
57+
await (transaction.CommitAsync());
58+
await (session.FlushAsync());
59+
}
60+
}
61+
4362
protected override HbmMapping GetMappings()
4463
{
4564
var mapper = new ModelMapper();

src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ public void AutoflushInPostInsertListener_CausesDuplicateInserts_WithPrimaryKeyV
2828
}
2929
}
3030

31+
[Test]
32+
public void Autoflush_MayTriggerAdditionalAutoFlushFromEvents()
33+
{
34+
using (var session = OpenSession())
35+
using (var transaction = session.BeginTransaction())
36+
{
37+
// using FlushMode.Commit prevents the issue; using the default FlushMode.Auto breaks.
38+
//session.FlushMode = FlushMode.Commit;
39+
session.Save(new Entity { Code = "one" });
40+
session.Save(new Entity { Code = "two" });
41+
42+
// Querying the entity triggers an auto-flush
43+
var count = session.CreateQuery("select count(o) from Entity o").UniqueResult<long>();
44+
Assert.That(count, Is.GreaterThan(0));
45+
transaction.Commit();
46+
session.Flush();
47+
}
48+
}
49+
3150
protected override HbmMapping GetMappings()
3251
{
3352
var mapper = new ModelMapper();

src/NHibernate/Async/Event/Default/DefaultAutoFlushEventListener.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,37 @@ public virtual async Task OnAutoFlushAsync(AutoFlushEvent @event, CancellationTo
3636

3737
if (FlushMightBeNeeded(source))
3838
{
39-
int oldSize = source.ActionQueue.CollectionRemovalsCount;
39+
using (source.SuspendAutoFlush())
40+
{
41+
int oldSize = source.ActionQueue.CollectionRemovalsCount;
4042

41-
await (FlushEverythingToExecutionsAsync(@event, cancellationToken)).ConfigureAwait(false);
43+
await (FlushEverythingToExecutionsAsync(@event, cancellationToken)).ConfigureAwait(false);
4244

43-
if (FlushIsReallyNeeded(@event, source))
44-
{
45-
if (log.IsDebugEnabled)
46-
log.Debug("Need to execute flush");
45+
if (FlushIsReallyNeeded(@event, source))
46+
{
47+
if (log.IsDebugEnabled)
48+
log.Debug("Need to execute flush");
4749

48-
await (PerformExecutionsAsync(source, cancellationToken)).ConfigureAwait(false);
49-
PostFlush(source);
50-
// note: performExecutions() clears all collectionXxxxtion
51-
// collections (the collection actions) in the session
50+
await (PerformExecutionsAsync(source, cancellationToken)).ConfigureAwait(false);
51+
PostFlush(source);
52+
// note: performExecutions() clears all collectionXxxxtion
53+
// collections (the collection actions) in the session
5254

53-
if (source.Factory.Statistics.IsStatisticsEnabled)
55+
if (source.Factory.Statistics.IsStatisticsEnabled)
56+
{
57+
source.Factory.StatisticsImplementor.Flush();
58+
}
59+
}
60+
else
5461
{
55-
source.Factory.StatisticsImplementor.Flush();
62+
63+
if (log.IsDebugEnabled)
64+
log.Debug("Dont need to execute flush");
65+
source.ActionQueue.ClearFromFlushNeededCheck(oldSize);
5666
}
57-
}
58-
else
59-
{
6067

61-
if (log.IsDebugEnabled)
62-
log.Debug("Dont need to execute flush");
63-
source.ActionQueue.ClearFromFlushNeededCheck(oldSize);
68+
@event.FlushRequired = FlushIsReallyNeeded(@event, source);
6469
}
65-
66-
@event.FlushRequired = FlushIsReallyNeeded(@event, source);
6770
}
6871
}
6972

src/NHibernate/Async/Impl/SessionImpl.cs

Lines changed: 71 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -233,25 +233,26 @@ public override async Task ListAsync(IQueryExpression queryExpression, QueryPara
233233
await (AutoFlushIfRequiredAsync(plan.QuerySpaces, cancellationToken)).ConfigureAwait(false);
234234

235235
bool success = false;
236-
dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
237-
try
238-
{
239-
await (plan.PerformListAsync(queryParameters, this, results, cancellationToken)).ConfigureAwait(false);
240-
success = true;
241-
}
242-
catch (HibernateException)
243-
{
244-
// Do not call Convert on HibernateExceptions
245-
throw;
246-
}
247-
catch (Exception e)
248-
{
249-
throw Convert(e, "Could not execute query");
250-
}
251-
finally
236+
using (SuspendAutoFlush()) //stops flush being called multiple times if this method is recursively called
252237
{
253-
dontFlushFromFind--;
254-
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
238+
try
239+
{
240+
await (plan.PerformListAsync(queryParameters, this, results, cancellationToken)).ConfigureAwait(false);
241+
success = true;
242+
}
243+
catch (HibernateException)
244+
{
245+
// Do not call Convert on HibernateExceptions
246+
throw;
247+
}
248+
catch (Exception e)
249+
{
250+
throw Convert(e, "Could not execute query");
251+
}
252+
finally
253+
{
254+
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
255+
}
255256
}
256257
}
257258
}
@@ -277,15 +278,10 @@ public override async Task<IEnumerable<T>> EnumerableAsync<T>(IQueryExpression q
277278
var plan = GetHQLQueryPlan(queryExpression, true);
278279
await (AutoFlushIfRequiredAsync(plan.QuerySpaces, cancellationToken)).ConfigureAwait(false);
279280

280-
dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
281-
try
281+
using (SuspendAutoFlush()) //stops flush being called multiple times if this method is recursively called
282282
{
283283
return await (plan.PerformIterateAsync<T>(queryParameters, this, cancellationToken)).ConfigureAwait(false);
284284
}
285-
finally
286-
{
287-
dontFlushFromFind--;
288-
}
289285
}
290286
}
291287

@@ -299,15 +295,10 @@ public override async Task<IEnumerable> EnumerableAsync(IQueryExpression queryEx
299295
var plan = GetHQLQueryPlan(queryExpression, true);
300296
await (AutoFlushIfRequiredAsync(plan.QuerySpaces, cancellationToken)).ConfigureAwait(false);
301297

302-
dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
303-
try
298+
using (SuspendAutoFlush()) //stops flush being called multiple times if this method is recursively called
304299
{
305300
return await (plan.PerformIterateAsync(queryParameters, this, cancellationToken)).ConfigureAwait(false);
306301
}
307-
finally
308-
{
309-
dontFlushFromFind--;
310-
}
311302
}
312303
}
313304

@@ -961,19 +952,14 @@ public override async Task<object> InternalLoadAsync(string entityName, object i
961952
{
962953
throw new HibernateException("Flush during cascade is dangerous");
963954
}
964-
dontFlushFromFind++;
965-
try
955+
using (SuspendAutoFlush())
966956
{
967957
IFlushEventListener[] flushEventListener = listeners.FlushEventListeners;
968958
for (int i = 0; i < flushEventListener.Length; i++)
969959
{
970960
await (flushEventListener[i].OnFlushAsync(new FlushEvent(this), cancellationToken)).ConfigureAwait(false);
971961
}
972962
}
973-
finally
974-
{
975-
dontFlushFromFind--;
976-
}
977963
}
978964
}
979965

@@ -1032,25 +1018,26 @@ private async Task FilterAsync(object collection, string filter, QueryParameters
10321018
FilterQueryPlan plan = await (GetFilterQueryPlanAsync(collection, filter, queryParameters, false, cancellationToken)).ConfigureAwait(false);
10331019

10341020
bool success = false;
1035-
dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
1036-
try
1037-
{
1038-
await (plan.PerformListAsync(queryParameters, this, results, cancellationToken)).ConfigureAwait(false);
1039-
success = true;
1040-
}
1041-
catch (HibernateException)
1042-
{
1043-
// Do not call Convert on HibernateExceptions
1044-
throw;
1045-
}
1046-
catch (Exception e)
1047-
{
1048-
throw Convert(e, "could not execute query");
1049-
}
1050-
finally
1021+
using (SuspendAutoFlush()) //stops flush being called multiple times if this method is recursively called
10511022
{
1052-
dontFlushFromFind--;
1053-
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
1023+
try
1024+
{
1025+
await (plan.PerformListAsync(queryParameters, this, results, cancellationToken)).ConfigureAwait(false);
1026+
success = true;
1027+
}
1028+
catch (HibernateException)
1029+
{
1030+
// Do not call Convert on HibernateExceptions
1031+
throw;
1032+
}
1033+
catch (Exception e)
1034+
{
1035+
throw Convert(e, "could not execute query");
1036+
}
1037+
finally
1038+
{
1039+
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
1040+
}
10541041
}
10551042
}
10561043
}
@@ -1127,30 +1114,30 @@ public override async Task ListAsync(CriteriaImpl criteria, IList results, Cance
11271114

11281115
await (AutoFlushIfRequiredAsync(spaces, cancellationToken)).ConfigureAwait(false);
11291116

1130-
dontFlushFromFind++;
1131-
11321117
bool success = false;
1133-
try
1118+
using (SuspendAutoFlush())
11341119
{
1135-
for (int i = size - 1; i >= 0; i--)
1120+
try
11361121
{
1137-
ArrayHelper.AddAll(results, await (loaders[i].ListAsync(this, cancellationToken)).ConfigureAwait(false));
1122+
for (int i = size - 1; i >= 0; i--)
1123+
{
1124+
ArrayHelper.AddAll(results, await (loaders[i].ListAsync(this, cancellationToken)).ConfigureAwait(false));
1125+
}
1126+
success = true;
1127+
}
1128+
catch (HibernateException)
1129+
{
1130+
// Do not call Convert on HibernateExceptions
1131+
throw;
1132+
}
1133+
catch (Exception sqle)
1134+
{
1135+
throw Convert(sqle, "Unable to perform find");
1136+
}
1137+
finally
1138+
{
1139+
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
11381140
}
1139-
success = true;
1140-
}
1141-
catch (HibernateException)
1142-
{
1143-
// Do not call Convert on HibernateExceptions
1144-
throw;
1145-
}
1146-
catch (Exception sqle)
1147-
{
1148-
throw Convert(sqle, "Unable to perform find");
1149-
}
1150-
finally
1151-
{
1152-
dontFlushFromFind--;
1153-
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
11541141
}
11551142
}
11561143
}
@@ -1181,16 +1168,17 @@ public override async Task ListCustomQueryAsync(ICustomQuery customQuery, QueryP
11811168
await (AutoFlushIfRequiredAsync(loader.QuerySpaces, cancellationToken)).ConfigureAwait(false);
11821169

11831170
bool success = false;
1184-
dontFlushFromFind++;
1185-
try
1186-
{
1187-
ArrayHelper.AddAll(results, await (loader.ListAsync(this, queryParameters, cancellationToken)).ConfigureAwait(false));
1188-
success = true;
1189-
}
1190-
finally
1171+
using (SuspendAutoFlush())
11911172
{
1192-
dontFlushFromFind--;
1193-
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
1173+
try
1174+
{
1175+
ArrayHelper.AddAll(results, await (loader.ListAsync(this, queryParameters, cancellationToken)).ConfigureAwait(false));
1176+
success = true;
1177+
}
1178+
finally
1179+
{
1180+
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
1181+
}
11941182
}
11951183
}
11961184
}

src/NHibernate/Engine/ISessionImplementor.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ public partial interface ISessionImplementor
225225
/// <summary> Retrieves the configured event listeners from this event source. </summary>
226226
EventListeners Listeners { get; }
227227

228-
int DontFlushFromFind { get; }
229-
230228
ConnectionManager ConnectionManager { get; }
231229

232230
bool IsEventSource { get; }

0 commit comments

Comments
 (0)