Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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;
        }