Skip to content

Commit f5a7a1f

Browse files
wvoptcsharper2010
andauthored
Fix version update on dirty collection with another property having optimistic-lock false (#3632)
Co-authored-by: CSharper2010 <[email protected]>
1 parent 0c9e442 commit f5a7a1f

File tree

6 files changed

+36
-25
lines changed

6 files changed

+36
-25
lines changed

src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public async System.Threading.Tasks.Task CollectionVersionAsync()
5252
admin = await (s.GetAsync<Group>(admin.Id));
5353
guy.Groups.Add(admin);
5454
admin.Users.Add(guy);
55+
guy.NoOptimisticLock = "changed";
5556
await (t.CommitAsync());
5657
s.Close();
5758

src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public void CollectionVersion()
4242
admin = s.Get<Group>(admin.Id);
4343
guy.Groups.Add(admin);
4444
admin.Users.Add(guy);
45+
guy.NoOptimisticLock = "changed";
4546
t.Commit();
4647
s.Close();
4748

src/NHibernate.Test/VersionTest/Db/User.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ public class User
1111

1212
public virtual string Username { get; set; }
1313

14+
public virtual string NoOptimisticLock { get; set; }
15+
1416
public virtual ISet<Group> Groups { get; set; }
1517

1618
public virtual ISet<Permission> Permissions { get; set; }
1719
}
18-
}
20+
}

src/NHibernate.Test/VersionTest/Db/User.hbm.xml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8" ?>
1+
<?xml version="1.0" encoding="utf-8" ?>
22
<!--
33
Demonstrates how to control the optimistic locking behavior
44
of a collection (do changes to the collection result in
@@ -14,6 +14,7 @@
1414
</id>
1515
<timestamp name="Timestamp" column="ts" source="db"/>
1616
<property name="Username" column="user_name" type="string" unique="true"/>
17+
<property name="NoOptimisticLock" column="no_optimistic_lock" type="string" optimistic-lock="false"/>
1718
<set name="Groups" table="db_vers_user_group" batch-size="9" inverse="true" optimistic-lock="true" lazy="true" cascade="none" >
1819
<key column="user_id"/>
1920
<many-to-many column="group_id" class="Group" lazy="false" fetch="join" />
@@ -45,4 +46,4 @@
4546
<property name="Context" column="ctx" type="string"/>
4647
<property name="Access" column="priv" type="string"/>
4748
</class>
48-
</hibernate-mapping>
49+
</hibernate-mapping>

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

+16-14
Original file line numberDiff line numberDiff line change
@@ -336,33 +336,35 @@ private async Task<object> GetNextVersionAsync(FlushEntityEvent @event, Cancella
336336
/// to synchronize its state to the database. Modifies the event by side-effect!
337337
/// Note: this method is quite slow, avoid calling if possible!
338338
/// </summary>
339-
protected Task<bool> IsUpdateNecessaryAsync(FlushEntityEvent @event, CancellationToken cancellationToken)
339+
protected async Task<bool> IsUpdateNecessaryAsync(FlushEntityEvent @event, CancellationToken cancellationToken)
340340
{
341-
if (cancellationToken.IsCancellationRequested)
342-
{
343-
return Task.FromCanceled<bool>(cancellationToken);
344-
}
341+
cancellationToken.ThrowIfCancellationRequested();
345342
IEntityPersister persister = @event.EntityEntry.Persister;
346343
Status status = @event.EntityEntry.Status;
347344

348345
if (!@event.DirtyCheckPossible)
349346
{
350-
return Task.FromResult<bool>(true);
347+
return true;
351348
}
352349
else
353350
{
351+
// call to HasDirtyCollections must not be optimized away because of its side effect
352+
bool hasDirtyCollections = await (HasDirtyCollectionsAsync(@event, persister, status, cancellationToken)).ConfigureAwait(false);
353+
354354
int[] dirtyProperties = @event.DirtyProperties;
355-
if (dirtyProperties != null && dirtyProperties.Length != 0)
356-
{
357-
return Task.FromResult<bool>(true); //TODO: suck into event class
358-
}
359-
else
360-
{
361-
return HasDirtyCollectionsAsync(@event, persister, status, cancellationToken);
362-
}
355+
return dirtyProperties != null && dirtyProperties.Length != 0 || hasDirtyCollections;
363356
}
364357
}
365358

359+
/// <summary>
360+
/// Check if there are any dirty collections.
361+
/// Has a side effect of setting the HasDirtyCollection property of the event.
362+
/// </summary>
363+
/// <param name="event"></param>
364+
/// <param name="persister"></param>
365+
/// <param name="status"></param>
366+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
367+
/// <returns></returns>
366368
private async Task<bool> HasDirtyCollectionsAsync(FlushEntityEvent @event, IEntityPersister persister, Status status, CancellationToken cancellationToken)
367369
{
368370
cancellationToken.ThrowIfCancellationRequested();

src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs

+12-8
Original file line numberDiff line numberDiff line change
@@ -389,18 +389,22 @@ protected bool IsUpdateNecessary(FlushEntityEvent @event)
389389
}
390390
else
391391
{
392+
// call to HasDirtyCollections must not be optimized away because of its side effect
393+
bool hasDirtyCollections = HasDirtyCollections(@event, persister, status);
394+
392395
int[] dirtyProperties = @event.DirtyProperties;
393-
if (dirtyProperties != null && dirtyProperties.Length != 0)
394-
{
395-
return true; //TODO: suck into event class
396-
}
397-
else
398-
{
399-
return HasDirtyCollections(@event, persister, status);
400-
}
396+
return dirtyProperties != null && dirtyProperties.Length != 0 || hasDirtyCollections;
401397
}
402398
}
403399

400+
/// <summary>
401+
/// Check if there are any dirty collections.
402+
/// Has a side effect of setting the HasDirtyCollection property of the event.
403+
/// </summary>
404+
/// <param name="event"></param>
405+
/// <param name="persister"></param>
406+
/// <param name="status"></param>
407+
/// <returns></returns>
404408
private bool HasDirtyCollections(FlushEntityEvent @event, IEntityPersister persister, Status status)
405409
{
406410
if (IsCollectionDirtyCheckNecessary(persister, status))

0 commit comments

Comments
 (0)