protected virtual async Task <bool> HandleInterceptionAsync(FlushEntityEvent @event, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ISessionImplementor session = @event.Session; EntityEntry entry = @event.EntityEntry; IEntityPersister persister = entry.Persister; object entity = @event.Entity; //give the Interceptor a chance to modify property values object[] values = @event.PropertyValues; bool intercepted = InvokeInterceptor(session, entity, entry, values, persister); //now we might need to recalculate the dirtyProperties array if (intercepted && @event.DirtyCheckPossible && [email protected]) { int[] dirtyProperties; if (@event.HasDatabaseSnapshot) { dirtyProperties = await(persister.FindModifiedAsync(@event.DatabaseSnapshot, values, entity, session, cancellationToken)).ConfigureAwait(false); } else { dirtyProperties = await(persister.FindDirtyAsync(values, entry.LoadedState, entity, session, cancellationToken)).ConfigureAwait(false); } @event.DirtyProperties = dirtyProperties; } return(intercepted); }
/// <summary> Perform a dirty check, and attach the results to the event</summary> protected virtual async Task DirtyCheckAsync(FlushEntityEvent @event, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); object entity = @event.Entity; object[] values = @event.PropertyValues; ISessionImplementor session = @event.Session; EntityEntry entry = @event.EntityEntry; IEntityPersister persister = entry.Persister; object id = entry.Id; object[] loadedState = entry.LoadedState; int[] dirtyProperties = session.Interceptor.FindDirty(entity, id, values, loadedState, persister.PropertyNames, persister.PropertyTypes); @event.DatabaseSnapshot = null; bool interceptorHandledDirtyCheck; bool cannotDirtyCheck; if (dirtyProperties == null) { // Interceptor returned null, so do the dirtycheck ourself, if possible interceptorHandledDirtyCheck = false; cannotDirtyCheck = loadedState == null; // object loaded by update() if (!cannotDirtyCheck) { // dirty check against the usual snapshot of the entity dirtyProperties = await(persister.FindDirtyAsync(values, loadedState, entity, session, cancellationToken)).ConfigureAwait(false); } else if (entry.Status == Status.Deleted && [email protected]()) { // A non-modifiable (e.g., read-only or immutable) entity needs to be have // references to transient entities set to null before being deleted. No other // fields should be updated. if (values != entry.DeletedState) { throw new InvalidOperationException("Entity has status Status.Deleted but values != entry.DeletedState"); } // Even if loadedState == null, we can dirty-check by comparing currentState and // entry.getDeletedState() because the only fields to be updated are those that // refer to transient entities that are being set to null. // - currentState contains the entity's current property values. // - entry.getDeletedState() contains the entity's current property values with // references to transient entities set to null. // - dirtyProperties will only contain properties that refer to transient entities object[] currentState = persister.GetPropertyValues(@event.Entity); dirtyProperties = await(persister.FindDirtyAsync(entry.DeletedState, currentState, entity, session, cancellationToken)).ConfigureAwait(false); cannotDirtyCheck = false; } else { // dirty check against the database snapshot, if possible/necessary object[] databaseSnapshot = await(GetDatabaseSnapshotAsync(session, persister, id, cancellationToken)).ConfigureAwait(false); if (databaseSnapshot != null) { dirtyProperties = await(persister.FindModifiedAsync(databaseSnapshot, values, entity, session, cancellationToken)).ConfigureAwait(false); cannotDirtyCheck = false; @event.DatabaseSnapshot = databaseSnapshot; } } } else { // the Interceptor handled the dirty checking cannotDirtyCheck = false; interceptorHandledDirtyCheck = true; } @event.DirtyProperties = dirtyProperties; @event.DirtyCheckHandledByInterceptor = interceptorHandledDirtyCheck; @event.DirtyCheckPossible = !cannotDirtyCheck; }