Skip to content

Commit 99407a4

Browse files
committed
Optimize GetOrphans and remove wrong checks from IsNotTransientSlow
1 parent 151194f commit 99407a4

14 files changed

+108
-180
lines changed

src/NHibernate/Async/Collection/AbstractPersistentCollection.cs

Lines changed: 15 additions & 101 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

@@ -92,41 +93,6 @@ public virtual Task ForceInitializationAsync(CancellationToken cancellationToken
9293
return Task.CompletedTask;
9394
}
9495

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-
13096
/// <summary>
13197
/// Called before inserting rows, to ensure that any surrogate keys are fully generated
13298
/// </summary>
@@ -154,79 +120,27 @@ public virtual Task PreInsertAsync(ICollectionPersister persister, CancellationT
154120
/// </summary>
155121
public abstract Task<ICollection> GetOrphansAsync(object snapshot, string entityName, CancellationToken cancellationToken);
156122

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)
123+
public async Task IdentityRemoveAsync(IList list, object obj, string entityName, ISessionImplementor session, CancellationToken cancellationToken)
163124
{
164125
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;
126+
if (obj == null || await (ForeignKeys.IsTransientSlowAsync(entityName, obj, session, cancellationToken)).ConfigureAwait(false))
127+
return;
178128

179-
// create the collection holding the orphans
180-
List<object> res = new List<object>();
129+
var persister = session.Factory.GetEntityPersister(entityName);
130+
IType idType = persister.IdentifierType;
131+
object idToRemove = ForeignKeys.GetIdentifier(persister, obj);
181132

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)
133+
for (var index = list.Count - 1; index >= 0; index--)
185134
{
186-
if (current != null && await (ForeignKeys.IsNotTransientSlowAsync(entityName, current, session, cancellationToken)).ConfigureAwait(false))
135+
object current = list[index];
136+
if (current == null)
187137
{
188-
object currentId = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(entityName, current, session, cancellationToken)).ConfigureAwait(false);
189-
currentIds.Add(new TypedValue(idType, currentId, false));
138+
continue;
190139
}
191-
}
192140

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-
206-
public async Task IdentityRemoveAsync(IList list, object obj, string entityName, ISessionImplementor session, CancellationToken cancellationToken)
207-
{
208-
cancellationToken.ThrowIfCancellationRequested();
209-
if (obj != null && await (ForeignKeys.IsNotTransientSlowAsync(entityName, obj, session, cancellationToken)).ConfigureAwait(false))
210-
{
211-
IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;
212-
213-
object idOfCurrent = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(entityName, obj, session, cancellationToken)).ConfigureAwait(false);
214-
List<object> toRemove = new List<object>(list.Count);
215-
foreach (object current in list)
216-
{
217-
if (current == null)
218-
{
219-
continue;
220-
}
221-
object idOfOld = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(entityName, current, session, cancellationToken)).ConfigureAwait(false);
222-
if (idType.IsEqual(idOfCurrent, idOfOld, session.Factory))
223-
{
224-
toRemove.Add(current);
225-
}
226-
}
227-
foreach (object ro in toRemove)
141+
if (obj == current || idType.IsEqual(idToRemove, ForeignKeys.GetIdentifier(persister, current), session.Factory))
228142
{
229-
list.Remove(ro);
143+
list.RemoveAt(index);
230144
}
231145
}
232146
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
8484
}
8585
try
8686
{
87-
var sn = (ICollection) snapshot;
88-
return GetOrphansAsync(sn, (ICollection) _gbag, entityName, Session, cancellationToken);
87+
return Task.FromResult<ICollection>(GetOrphans(snapshot, entityName));
8988
}
9089
catch (Exception ex)
9190
{

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
163163
}
164164
try
165165
{
166-
var sn = (ISet<SnapshotElement>)GetSnapshot();
167-
return GetOrphansAsync(sn.Select(x => x.Value).ToArray(), (ICollection) _values, entityName, Session, cancellationToken);
166+
return Task.FromResult<ICollection>(GetOrphans(snapshot, entityName));
168167
}
169168
catch (Exception ex)
170169
{

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
3838
}
3939
try
4040
{
41-
var sn = (IList<T>)snapshot;
42-
return GetOrphansAsync((ICollection)sn, (ICollection) WrappedList, entityName, Session, cancellationToken);
41+
return Task.FromResult<ICollection>(GetOrphans(snapshot, entityName));
4342
}
4443
catch (Exception ex)
4544
{

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
3838
}
3939
try
4040
{
41-
var sn = (IDictionary<TKey, TValue>) snapshot;
42-
return GetOrphansAsync((ICollection)sn.Values, (ICollection)WrappedMap.Values, entityName, Session, cancellationToken);
41+
return Task.FromResult<ICollection>(GetOrphans(snapshot, entityName));
4342
}
4443
catch (Exception ex)
4544
{

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,7 @@ public override Task<ICollection> GetOrphansAsync(object snapshot, string entity
3939
}
4040
try
4141
{
42-
var sn = new SetSnapShot<T>((IEnumerable<T>)snapshot);
43-
44-
// TODO: Avoid duplicating shortcuts and array copy, by making base class GetOrphans() more flexible
45-
if (WrappedSet.Count == 0) return Task.FromResult<ICollection>(sn);
46-
if (((ICollection)sn).Count == 0) return Task.FromResult<ICollection>(sn);
47-
return GetOrphansAsync(sn, WrappedSet.ToArray(), entityName, Session, cancellationToken);
42+
return Task.FromResult<ICollection>(GetOrphans(snapshot, entityName));
4843
}
4944
catch (Exception ex)
5045
{

src/NHibernate/Async/Collection/IPersistentCollection.cs

Lines changed: 2 additions & 5 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,9 +92,6 @@ 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>

src/NHibernate/Async/Engine/Cascade.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ private async Task DeleteOrphansAsync(string entityName, IPersistentCollection p
288288
}
289289
else
290290
{
291-
orphans = await (pc.GetQueuedOrphansAsync(entityName, cancellationToken)).ConfigureAwait(false);
291+
orphans = pc.GetQueuedOrphans(entityName);
292292
}
293293

294294
foreach (object orphan in orphans)

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(

src/NHibernate/Async/Type/IType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
using System.Collections;
12+
using System.Collections.Generic;
1213
using System.Data.Common;
1314
using NHibernate.Engine;
1415
using NHibernate.SqlTypes;
@@ -17,7 +18,7 @@ namespace NHibernate.Type
1718
{
1819
using System.Threading.Tasks;
1920
using System.Threading;
20-
21+
2122
public partial interface IType : ICacheAssembler
2223
{
2324

0 commit comments

Comments
 (0)