Skip to content

Commit 891c632

Browse files
bahusoidhazzik
authored andcommitted
Optimize GetOrphans and remove wrong checks from IsNotTransientSlow (#2056)
Co-authored-by: Alexander Zaytsev <hazzik@gmail.com>
1 parent bf2f7f2 commit 891c632

19 files changed

+187
-203
lines changed

src/NHibernate/Async/Collection/AbstractPersistentCollection.cs

Lines changed: 6 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
using System.Collections;
1313
using System.Collections.Generic;
1414
using System.Data.Common;
15+
using System.Linq;
16+
using System.Threading;
17+
using System.Threading.Tasks;
1518
using NHibernate.Collection.Generic;
1619
using NHibernate.Engine;
1720
using NHibernate.Impl;
@@ -22,8 +25,6 @@
2225

2326
namespace NHibernate.Collection
2427
{
25-
using System.Threading.Tasks;
26-
using System.Threading;
2728
public abstract partial class AbstractPersistentCollection : IPersistentCollection, ILazyInitializedCollection
2829
{
2930

@@ -91,42 +92,7 @@ public virtual Task ForceInitializationAsync(CancellationToken cancellationToken
9192
}
9293
return Task.CompletedTask;
9394
}
94-
95-
public Task<ICollection> GetQueuedOrphansAsync(string entityName, CancellationToken cancellationToken)
96-
{
97-
if (cancellationToken.IsCancellationRequested)
98-
{
99-
return Task.FromCanceled<ICollection>(cancellationToken);
100-
}
101-
try
102-
{
103-
if (HasQueuedOperations)
104-
{
105-
List<object> additions = new List<object>(operationQueue.Count);
106-
List<object> removals = new List<object>(operationQueue.Count);
107-
for (int i = 0; i < operationQueue.Count; i++)
108-
{
109-
IDelayedOperation op = operationQueue[i];
110-
if (op.AddedInstance != null)
111-
{
112-
additions.Add(op.AddedInstance);
113-
}
114-
if (op.Orphan != null)
115-
{
116-
removals.Add(op.Orphan);
117-
}
118-
}
119-
return GetOrphansAsync(removals, additions, entityName, session, cancellationToken);
120-
}
121-
122-
return Task.FromResult<ICollection>(CollectionHelper.EmptyCollection);
123-
}
124-
catch (Exception ex)
125-
{
126-
return Task.FromException<ICollection>(ex);
127-
}
128-
}
129-
95+
13096
/// <summary>
13197
/// Called before inserting rows, to ensure that any surrogate keys are fully generated
13298
/// </summary>
@@ -149,60 +115,8 @@ public virtual Task PreInsertAsync(ICollectionPersister persister, CancellationT
149115
}
150116
}
151117

152-
/// <summary>
153-
/// Get all "orphaned" elements
154-
/// </summary>
155-
public abstract Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken);
156-
157-
/// <summary>
158-
/// Given a collection of entity instances that used to
159-
/// belong to the collection, and a collection of instances
160-
/// that currently belong, return a collection of orphans
161-
/// </summary>
162-
protected virtual async Task<ICollection> GetOrphansAsync(ICollection oldElements, ICollection currentElements, string entityName, ISessionImplementor session, CancellationToken cancellationToken)
163-
{
164-
cancellationToken.ThrowIfCancellationRequested();
165-
// short-circuit(s)
166-
if (currentElements.Count == 0)
167-
{
168-
// no new elements, the old list contains only Orphans
169-
return oldElements;
170-
}
171-
if (oldElements.Count == 0)
172-
{
173-
// no old elements, so no Orphans neither
174-
return oldElements;
175-
}
176-
177-
IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;
178-
179-
// create the collection holding the orphans
180-
List<object> res = new List<object>();
181-
182-
// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
183-
var currentIds = new HashSet<TypedValue>();
184-
foreach (object current in currentElements)
185-
{
186-
if (current != null && await (ForeignKeys.IsNotTransientSlowAsync(entityName, current, session, cancellationToken)).ConfigureAwait(false))
187-
{
188-
object currentId = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(entityName, current, session, cancellationToken)).ConfigureAwait(false);
189-
currentIds.Add(new TypedValue(idType, currentId, false));
190-
}
191-
}
192-
193-
// iterate over the *old* list
194-
foreach (object old in oldElements)
195-
{
196-
object oldId = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(entityName, old, session, cancellationToken)).ConfigureAwait(false);
197-
if (!currentIds.Contains(new TypedValue(idType, oldId, false)))
198-
{
199-
res.Add(old);
200-
}
201-
}
202-
203-
return res;
204-
}
205-
118+
// Since 5.3
119+
[Obsolete("This method has no more usages and will be removed in a future version")]
206120
public async Task IdentityRemoveAsync(IList list, object obj, string entityName, ISessionImplementor session, CancellationToken cancellationToken)
207121
{
208122
cancellationToken.ThrowIfCancellationRequested();

src/NHibernate/Async/Collection/Generic/PersistentGenericBag.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ public override Task<IEnumerable> GetDeletesAsync(ICollectionPersister persister
7575
return Task.FromException<IEnumerable>(ex);
7676
}
7777
}
78-
78+
79+
// Since 5.3
80+
[Obsolete("This method has no more usages and will be removed in a future version")]
7981
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
8082
{
8183
if (cancellationToken.IsCancellationRequested)
@@ -85,7 +87,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
8587
try
8688
{
8789
var sn = (ICollection) snapshot;
88-
return GetOrphansAsync(sn, (ICollection) _gbag, entityName, Session, cancellationToken);
90+
return Task.FromResult<ICollection>(GetOrphans(sn, (ICollection) _gbag, entityName, Session));
8991
}
9092
catch (Exception ex)
9193
{

src/NHibernate/Async/Collection/Generic/PersistentGenericIdentifierBag.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ public override async Task<object> ReadFromAsync(DbDataReader reader, ICollectio
155155
}
156156
return element;
157157
}
158-
158+
159+
// Since 5.3
160+
[Obsolete("This method has no more usages and will be removed in a future version")]
159161
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
160162
{
161163
if (cancellationToken.IsCancellationRequested)
@@ -165,7 +167,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
165167
try
166168
{
167169
var sn = (ISet<SnapshotElement>)GetSnapshot();
168-
return GetOrphansAsync(sn.ToArray(x => x.Value), (ICollection) _values, entityName, Session, cancellationToken);
170+
return Task.FromResult<ICollection>(GetOrphans(sn.ToArray(x => x.Value), (ICollection) _values, entityName, Session));
169171
}
170172
catch (Exception ex)
171173
{

src/NHibernate/Async/Collection/Generic/PersistentGenericList.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ namespace NHibernate.Collection.Generic
2929
using System.Threading;
3030
public partial class PersistentGenericList<T> : AbstractPersistentCollection, IList<T>, IList, IQueryable<T>
3131
{
32-
32+
33+
// Since 5.3
34+
[Obsolete("This method has no more usages and will be removed in a future version")]
3335
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
3436
{
3537
if (cancellationToken.IsCancellationRequested)
@@ -39,7 +41,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
3941
try
4042
{
4143
var sn = (IList<T>)snapshot;
42-
return GetOrphansAsync((ICollection)sn, (ICollection) WrappedList, entityName, Session, cancellationToken);
44+
return Task.FromResult<ICollection>(GetOrphans((ICollection)sn, (ICollection) WrappedList, entityName, Session));
4345
}
4446
catch (Exception ex)
4547
{

src/NHibernate/Async/Collection/Generic/PersistentGenericMap.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ namespace NHibernate.Collection.Generic
2929
using System.Threading;
3030
public partial class PersistentGenericMap<TKey, TValue> : AbstractPersistentCollection, IDictionary<TKey, TValue>, ICollection
3131
{
32-
32+
33+
// Since 5.3
34+
[Obsolete("This method has no more usages and will be removed in a future version")]
3335
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
3436
{
3537
if (cancellationToken.IsCancellationRequested)
@@ -39,7 +41,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
3941
try
4042
{
4143
var sn = (IDictionary<TKey, TValue>) snapshot;
42-
return GetOrphansAsync((ICollection)sn.Values, (ICollection)WrappedMap.Values, entityName, Session, cancellationToken);
44+
return Task.FromResult<ICollection>(GetOrphans((ICollection)sn.Values, (ICollection)WrappedMap.Values, entityName, Session));
4345
}
4446
catch (Exception ex)
4547
{

src/NHibernate/Async/Collection/Generic/PersistentGenericSet.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ namespace NHibernate.Collection.Generic
3030
using System.Threading;
3131
public partial class PersistentGenericSet<T> : AbstractPersistentCollection, ISet<T>, IQueryable<T>
3232
{
33-
33+
34+
// Since 5.3
35+
[Obsolete("This method has no more usages and will be removed in a future version")]
3436
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
3537
{
3638
if (cancellationToken.IsCancellationRequested)
@@ -44,7 +46,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
4446
// TODO: Avoid duplicating shortcuts and array copy, by making base class GetOrphans() more flexible
4547
if (WrappedSet.Count == 0) return Task.FromResult<ICollection>(sn);
4648
if (((ICollection)sn).Count == 0) return Task.FromResult<ICollection>(sn);
47-
return GetOrphansAsync(sn, WrappedSet.ToArray(), entityName, Session, cancellationToken);
49+
return Task.FromResult<ICollection>(GetOrphans(sn, WrappedSet.ToArray(), entityName, Session));
4850
}
4951
catch (Exception ex)
5052
{

src/NHibernate/Async/Collection/IPersistentCollection.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using System;
1212
using System.Collections;
1313
using System.Data.Common;
14+
using System.Threading;
15+
using System.Threading.Tasks;
1416
using NHibernate.Collection.Generic;
1517
using NHibernate.Engine;
1618
using NHibernate.Loader;
@@ -19,8 +21,6 @@
1921

2022
namespace NHibernate.Collection
2123
{
22-
using System.Threading.Tasks;
23-
using System.Threading;
2424
public partial interface IPersistentCollection
2525
{
2626

@@ -92,27 +92,11 @@ public partial interface IPersistentCollection
9292
/// </summary>
9393
Task<IEnumerable> GetDeletesAsync(ICollectionPersister persister, bool indexIsFormula, CancellationToken cancellationToken);
9494

95-
/// <summary> Get the "queued" orphans</summary>
96-
Task<ICollection> GetQueuedOrphansAsync(string entityName, CancellationToken cancellationToken);
97-
9895
/// <summary>
9996
/// Called before inserting rows, to ensure that any surrogate keys are fully generated
10097
/// </summary>
10198
/// <param name="persister"></param>
10299
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
103100
Task PreInsertAsync(ICollectionPersister persister, CancellationToken cancellationToken);
104-
105-
/// <summary>
106-
/// Get all "orphaned" elements
107-
/// </summary>
108-
/// <param name="snapshot">The snapshot of the collection.</param>
109-
/// <param name="entityName">The persistent class whose objects
110-
/// the collection is expected to contain.</param>
111-
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
112-
/// <returns>
113-
/// An <see cref="ICollection"/> that contains all of the elements
114-
/// that have been orphaned.
115-
/// </returns>
116-
Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken);
117101
}
118102
}

src/NHibernate/Async/Collection/PersistentArrayHolder.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,23 @@ namespace NHibernate.Collection
2626
using System.Threading;
2727
public partial class PersistentArrayHolder : AbstractPersistentCollection, ICollection
2828
{
29-
30-
public override async Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
29+
30+
// Since 5.3
31+
[Obsolete("This method has no more usages and will be removed in a future version")]
32+
public override Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken)
3133
{
32-
cancellationToken.ThrowIfCancellationRequested();
33-
object[] sn = (object[]) snapshot;
34-
object[] arr = (object[]) array;
35-
List<object> result = new List<object>(sn);
36-
for (int i = 0; i < sn.Length; i++)
34+
if (cancellationToken.IsCancellationRequested)
3735
{
38-
await (IdentityRemoveAsync(result, arr[i], entityName, Session, cancellationToken)).ConfigureAwait(false);
36+
return Task.FromCanceled<ICollection>(cancellationToken);
37+
}
38+
try
39+
{
40+
return Task.FromResult<ICollection>(GetOrphans((object[]) snapshot, (object[]) array, entityName, Session));
41+
}
42+
catch (Exception ex)
43+
{
44+
return Task.FromException<ICollection>(ex);
3945
}
40-
return result;
4146
}
4247

4348
public override async Task<bool> EqualsSnapshotAsync(ICollectionPersister persister, CancellationToken cancellationToken)
@@ -147,4 +152,4 @@ public override async Task<bool> NeedsUpdatingAsync(object entry, int i, IType e
147152
&& await (elemType.IsDirtyAsync(array.GetValue(i), sn.GetValue(i), Session, cancellationToken)).ConfigureAwait(false);
148153
}
149154
}
150-
}
155+
}

src/NHibernate/Async/Engine/Cascade.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,11 @@ private async Task DeleteOrphansAsync(string entityName, IPersistentCollection p
285285
if (pc.WasInitialized)
286286
{
287287
CollectionEntry ce = eventSource.PersistenceContext.GetCollectionEntry(pc);
288-
orphans = ce == null ? CollectionHelper.EmptyCollection : await (ce.GetOrphansAsync(entityName, pc, cancellationToken)).ConfigureAwait(false);
288+
orphans = ce == null ? CollectionHelper.EmptyCollection : ce.GetOrphans(entityName, pc);
289289
}
290290
else
291291
{
292-
orphans = await (pc.GetQueuedOrphansAsync(entityName, cancellationToken)).ConfigureAwait(false);
292+
orphans = pc.GetQueuedOrphans(entityName);
293293
}
294294

295295
foreach (object orphan in orphans)

src/NHibernate/Async/Engine/CollectionEntry.cs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010

1111
using System;
1212
using System.Collections;
13+
using System.Threading;
14+
using System.Threading.Tasks;
1315
using NHibernate.Action;
1416
using NHibernate.Collection;
1517
using NHibernate.Impl;
1618
using NHibernate.Persister.Collection;
1719

1820
namespace NHibernate.Engine
1921
{
20-
using System.Threading.Tasks;
21-
using System.Threading;
2222
public partial class CollectionEntry
2323
{
2424

@@ -70,18 +70,5 @@ public async Task PreFlushAsync(IPersistentCollection collection, CancellationTo
7070
reached = false;
7171
processed = false;
7272
}
73-
74-
public Task<ICollection> GetOrphansAsync(string entityName, IPersistentCollection collection, CancellationToken cancellationToken)
75-
{
76-
if (snapshot == null)
77-
{
78-
throw new AssertionFailure("no collection snapshot for orphan delete");
79-
}
80-
if (cancellationToken.IsCancellationRequested)
81-
{
82-
return Task.FromCanceled<ICollection>(cancellationToken);
83-
}
84-
return collection.GetOrphansAsync(snapshot, entityName, cancellationToken);
85-
}
8673
}
8774
}

src/NHibernate/Async/Engine/ForeignKeys.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,6 @@ private async Task<bool> IsNullifiableAsync(string entityName, object obj, Cance
157157
public static async Task<bool> IsNotTransientSlowAsync(string entityName, object entity, ISessionImplementor session, CancellationToken cancellationToken)
158158
{
159159
cancellationToken.ThrowIfCancellationRequested();
160-
if (entity.IsProxy())
161-
return true;
162-
if (session.PersistenceContext.IsEntryFor(entity))
163-
return true;
164160
return !await (IsTransientSlowAsync(entityName, entity, session, cancellationToken)).ConfigureAwait(false);
165161
}
166162

@@ -271,16 +267,6 @@ public static async Task<object> GetEntityIdentifierIfNotUnsavedAsync(string ent
271267

272268
if ((await (IsTransientFastAsync(entityName, entity, session, cancellationToken)).ConfigureAwait(false)).GetValueOrDefault())
273269
{
274-
/***********************************************/
275-
// TODO NH verify the behavior of NH607 test
276-
// these lines are only to pass test NH607 during PersistenceContext porting
277-
// i'm not secure that NH607 is a test for a right behavior
278-
EntityEntry entry = session.PersistenceContext.GetEntry(entity);
279-
if (entry != null)
280-
return entry.Id;
281-
// the check was put here to have les possible impact
282-
/**********************************************/
283-
284270
entityName = entityName ?? session.GuessEntityName(entity);
285271
string entityString = entity.ToString();
286272
throw new TransientObjectException(

0 commit comments

Comments
 (0)