Skip to content

Commit 651fdfe

Browse files
committed
Async After-/BeforeTransactionComplete
1 parent b6f16b6 commit 651fdfe

16 files changed

+267
-83
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace NHibernate.Action
6+
{
7+
public class AfterTransactionCompletionProcess : IAfterTransactionCompletionProcess
8+
{
9+
private readonly Action<bool> _syncAction;
10+
private readonly Func<bool, CancellationToken, Task> _asyncAction;
11+
12+
public AfterTransactionCompletionProcess(Action<bool> syncAction, Func<bool, CancellationToken, Task> asyncAction)
13+
{
14+
15+
_syncAction = syncAction;
16+
_asyncAction = asyncAction;
17+
}
18+
19+
public AfterTransactionCompletionProcess(Action<bool> syncAction)
20+
{
21+
_syncAction = syncAction;
22+
_asyncAction = (success, cancellationToken) =>
23+
{
24+
if (cancellationToken.IsCancellationRequested)
25+
{
26+
return Task.FromCanceled<object>(cancellationToken);
27+
}
28+
try
29+
{
30+
_syncAction(success);
31+
return Task.CompletedTask;
32+
}
33+
catch (Exception ex)
34+
{
35+
return Task.FromException<object>(ex);
36+
}
37+
};
38+
}
39+
40+
public void AfterTransactionCompletion(bool success)
41+
{
42+
_syncAction(success);
43+
}
44+
45+
public Task AfterTransactionCompletionAsync(bool success, CancellationToken cancellationToken)
46+
{
47+
return _asyncAction(success, cancellationToken);
48+
}
49+
}
50+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace NHibernate.Action
6+
{
7+
public class BeforeTransactionCompletionProcess : IBeforeTransactionCompletionProcess
8+
{
9+
private readonly System.Action _syncAction;
10+
private readonly Func<CancellationToken, Task> _asyncAction;
11+
12+
public BeforeTransactionCompletionProcess(System.Action syncAction, Func<CancellationToken, Task> asyncAction)
13+
{
14+
_syncAction = syncAction;
15+
_asyncAction = asyncAction;
16+
}
17+
18+
public BeforeTransactionCompletionProcess(System.Action syncAction)
19+
{
20+
_syncAction = syncAction;
21+
_asyncAction = (cancellationToken) =>
22+
{
23+
if (cancellationToken.IsCancellationRequested)
24+
{
25+
return Task.FromCanceled<object>(cancellationToken);
26+
}
27+
try
28+
{
29+
_syncAction();
30+
return Task.CompletedTask;
31+
}
32+
catch (Exception ex)
33+
{
34+
return Task.FromException<object>(ex);
35+
}
36+
};
37+
}
38+
39+
public void BeforeTransactionCompletion()
40+
{
41+
_syncAction();
42+
}
43+
44+
public Task BeforeTransactionCompletionAsync(CancellationToken cancellationToken)
45+
{
46+
return _asyncAction(cancellationToken);
47+
}
48+
}
49+
}

src/NHibernate/Action/BulkOperationCleanupAction.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,30 @@ public void Execute()
111111
// nothing to do
112112
}
113113

114-
public BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
114+
public IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess
115115
{
116-
get
117-
{
116+
get
117+
{
118118
return null;
119119
}
120120
}
121121

122-
public AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
122+
public IAfterTransactionCompletionProcess AfterTransactionCompletionProcess
123123
{
124124
get
125125
{
126-
return new AfterTransactionCompletionProcessDelegate((success) =>
127-
{
128-
this.EvictEntityRegions();
129-
this.EvictCollectionRegions();
130-
});
126+
return new AfterTransactionCompletionProcess(
127+
(success) =>
128+
{
129+
EvictEntityRegions();
130+
EvictCollectionRegions();
131+
},
132+
async (success, cancellationToken) =>
133+
{
134+
await EvictEntityRegionsAsync(cancellationToken);
135+
await EvictCollectionRegionsAsync(cancellationToken);
136+
}
137+
);
131138
}
132139
}
133140

src/NHibernate/Action/CollectionAction.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,27 +104,34 @@ public virtual void BeforeExecutions()
104104
/// <summary>Execute this action</summary>
105105
public abstract void Execute();
106106

107-
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
107+
public virtual IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess
108108
{
109109
get
110110
{
111111
return null;
112112
}
113113
}
114114

115-
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
115+
public virtual IAfterTransactionCompletionProcess AfterTransactionCompletionProcess
116116
{
117117

118118
get
119119
{
120120
// Only make sense to add the delegate if there is a cache.
121121
if (persister.HasCache)
122122
{
123-
return new AfterTransactionCompletionProcessDelegate((success) =>
124-
{
125-
CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.Factory);
126-
persister.Cache.Release(ck, softLock);
127-
});
123+
return new AfterTransactionCompletionProcess(
124+
(success) =>
125+
{
126+
CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.Factory);
127+
persister.Cache.Release(ck, softLock);
128+
},
129+
async (success, cancellationToken) =>
130+
{
131+
CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.Factory);
132+
await persister.Cache.ReleaseAsync(ck, softLock, cancellationToken);
133+
}
134+
);
128135
}
129136
return null;
130137
}

src/NHibernate/Action/CollectionUpdateAction.cs

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,49 +113,75 @@ private void PostUpdate()
113113
}
114114
}
115115

116-
public override BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
116+
public override IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess
117117
{
118118
get
119119
{
120120
return null;
121121
}
122122
}
123123

124-
public override AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
124+
public override IAfterTransactionCompletionProcess AfterTransactionCompletionProcess
125125
{
126126
get
127127
{
128128
// Only make sense to add the delegate if there is a cache.
129129
if (Persister.HasCache)
130130
{
131131
// NH Different behavior: to support unlocking collections from the cache.(r3260)
132-
return new AfterTransactionCompletionProcessDelegate((success) =>
133-
{
134-
CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
135-
136-
if (success)
132+
return new AfterTransactionCompletionProcess(
133+
(success) =>
137134
{
138-
// we can't disassemble a collection if it was uninitialized
139-
// or detached from the session
140-
if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
141-
{
142-
CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister);
143-
bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock);
135+
CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
144136

145-
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
137+
if (success)
138+
{
139+
// we can't disassemble a collection if it was uninitialized
140+
// or detached from the session
141+
if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
146142
{
147-
Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
143+
CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister);
144+
bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock);
145+
146+
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
147+
{
148+
Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
149+
}
148150
}
149151
}
150-
}
151-
else
152+
else
153+
{
154+
Persister.Cache.Release(ck, Lock);
155+
}
156+
},
157+
async (success, cancellationToken) =>
152158
{
153-
Persister.Cache.Release(ck, Lock);
159+
CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
160+
161+
if (success)
162+
{
163+
// we can't disassemble a collection if it was uninitialized
164+
// or detached from the session
165+
if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
166+
{
167+
CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister);
168+
bool put = await Persister.Cache.AfterUpdateAsync(ck, entry, null, Lock, cancellationToken);
169+
170+
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
171+
{
172+
Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
173+
}
174+
}
175+
}
176+
else
177+
{
178+
await Persister.Cache.ReleaseAsync(ck, Lock, cancellationToken);
179+
}
154180
}
155-
});
181+
);
156182
}
157183
return null;
158184
}
159185
}
160186
}
161-
}
187+
}

src/NHibernate/Action/EntityAction.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,22 @@ public void BeforeExecutions()
102102

103103
public abstract void Execute();
104104

105-
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
105+
public virtual IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess
106106
{
107107
get
108108
{
109109
return NeedsBeforeTransactionCompletion()
110-
? new BeforeTransactionCompletionProcessDelegate(BeforeTransactionCompletionProcessImpl)
110+
? new BeforeTransactionCompletionProcess(BeforeTransactionCompletionProcessImpl, BeforeTransactionCompletionProcessImplAsync)
111111
: null;
112112
}
113113
}
114114

115-
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
115+
public virtual IAfterTransactionCompletionProcess AfterTransactionCompletionProcess
116116
{
117117
get
118118
{
119119
return NeedsAfterTransactionCompletion()
120-
? new AfterTransactionCompletionProcessDelegate(AfterTransactionCompletionProcessImpl)
120+
? new AfterTransactionCompletionProcess(AfterTransactionCompletionProcessImpl, AfterTransactionCompletionProcessImplAsync)
121121
: null;
122122
}
123123
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace NHibernate.Action
5+
{
6+
public partial interface IAfterTransactionCompletionProcess
7+
{
8+
/// <summary>
9+
/// Perform whatever processing is encapsulated here after completion of the transaction.
10+
/// </summary>
11+
/// <param name="success">Did the transaction complete successfully? True means it did.</param>
12+
void AfterTransactionCompletion(bool success);
13+
}
14+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace NHibernate.Action
5+
{
6+
public partial interface IBeforeTransactionCompletionProcess
7+
{
8+
void BeforeTransactionCompletion();
9+
}
10+
}

src/NHibernate/Action/IExecutable.cs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
1-
using NHibernate.Engine;
2-
31
namespace NHibernate.Action
42
{
5-
/// <summary>
6-
/// Delegate representing some process that needs to occur before transaction completion.
7-
/// </summary>
8-
/// <remarks>
9-
/// NH specific: C# does not support dynamic interface proxies so a delegate is used in
10-
/// place of the Hibernate interface (see Action/BeforeTransactionCompletionProcess). The
11-
/// delegate omits the <see cref="ISessionImplementor" /> parameter as it is not used.
12-
/// </remarks>
13-
public delegate void BeforeTransactionCompletionProcessDelegate();
14-
15-
/// <summary>
16-
/// Delegate representing some process that needs to occur after transaction completion.
17-
/// </summary>
18-
/// <param name="success"> Did the transaction complete successfully? True means it did.</param>
19-
/// <remarks>
20-
/// NH specific: C# does not support dynamic interface proxies so a delegate is used in
21-
/// place of the Hibernate interface (see Action/AfterTransactionCompletionProcess). The
22-
/// delegate omits the <see cref="ISessionImplementor" /> parameter as it is not used.
23-
/// </remarks>
24-
public delegate void AfterTransactionCompletionProcessDelegate(bool success);
25-
263
/// <summary>
274
/// An operation which may be scheduled for later execution.
285
/// Usually, the operation is a database insert/update/delete,
@@ -44,11 +21,11 @@ public partial interface IExecutable
4421
/// <summary>
4522
/// Get the before-transaction-completion process, if any, for this action.
4623
/// </summary>
47-
BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { get; }
48-
24+
IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess { get; }
25+
4926
/// <summary>
5027
/// Get the after-transaction-completion process, if any, for this action.
5128
/// </summary>
52-
AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { get; }
29+
IAfterTransactionCompletionProcess AfterTransactionCompletionProcess { get; }
5330
}
5431
}

src/NHibernate/Async/Action/CollectionUpdateAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,4 @@ private async Task PostUpdateAsync(CancellationToken cancellationToken)
119119
}
120120
}
121121
}
122-
}
122+
}

0 commit comments

Comments
 (0)