private static async Task PerformPersist(
            SubmitContext context,
            IEnumerable <ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            // Once the change is persisted, the EntityState is lost.
            // In order to invoke the correct post-CUD event, remember which action was performed on the entity.
            foreach (ChangeSetEntry item in changeSetItems)
            {
                if (item.Type == ChangeSetEntryType.DataModification)
                {
                    DataModificationEntry dataModification = (DataModificationEntry)item;
                    if (dataModification.IsNew)
                    {
                        dataModification.AddAction = AddAction.Inserting;
                    }
                    else if (dataModification.IsUpdate)
                    {
                        dataModification.AddAction = AddAction.Updating;
                    }
                    else if (dataModification.IsDelete)
                    {
                        dataModification.AddAction = AddAction.Removing;
                    }
                }
            }

            var executor = context.GetHookPoint <ISubmitExecutor>();

            if (executor == null)
            {
                throw new NotSupportedException();
            }

            context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken);
        }
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public async Task<SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetHookPoint<IChangeSetPreparer>();
            if (preparer == null)
            {
                throw new NotSupportedException();
            }

            await preparer.PrepareAsync(context, cancellationToken);

            // authorize
            var authorized = true;
            foreach (var authorizer in context
                .GetHookPoints<ISubmitAuthorizer>().Reverse())
            {
                authorized = await authorizer.AuthorizeAsync(
                    context, cancellationToken);
                if (!authorized || context.Result != null)
                {
                    break;
                }
            }

            if (!authorized)
            {
                // TODO GitHubIssue#32 : Figure out a more appropriate exception
                throw new SecurityException();
            }

            if (context.Result != null)
            {
                return context.Result;
            }

            ChangeSet eventsChangeSet = context.ChangeSet;

            IEnumerable<ChangeSetEntry> currentChangeSetItems;
            int outerLoopCount = 0;

            do
            {
                outerLoopCount++;
                int innerLoopCount = 0;
                do
                {
                    innerLoopCount++;
                    eventsChangeSet.AnEntityHasChanged = false;
                    currentChangeSetItems = eventsChangeSet.Entries.ToArray();

                    if (eventsChangeSet.AnEntityHasChanged)
                    {
                        eventsChangeSet.AnEntityHasChanged = false;
                        currentChangeSetItems = eventsChangeSet.Entries.ToArray();
                    }

                    await PerformValidate(context, currentChangeSetItems, cancellationToken);

                    await PerformPreEvent(context, currentChangeSetItems, cancellationToken);
                }
                while (eventsChangeSet.AnEntityHasChanged && (innerLoopCount < MaxLoop));

                VerifyNoEntityHasChanged(eventsChangeSet);

                await PerformPersist(context, currentChangeSetItems, cancellationToken);

                eventsChangeSet.Entries.Clear();

                await PerformPostEvent(context, currentChangeSetItems, cancellationToken);
            }
            while (eventsChangeSet.AnEntityHasChanged && (outerLoopCount < MaxLoop));

            VerifyNoEntityHasChanged(eventsChangeSet);

            return context.Result;
        }
        private static async Task PerformPersist(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            // Once the change is persisted, the EntityState is lost.
            // In order to invoke the correct post-CUD event, remember which action was performed on the entity.
            foreach (ChangeSetEntry item in changeSetItems)
            {
                if (item.Type == ChangeSetEntryType.DataModification)
                {
                    DataModificationEntry dataModification = (DataModificationEntry)item;
                    if (dataModification.IsNew)
                    {
                        dataModification.AddAction = AddAction.Inserting;
                    }
                    else if (dataModification.IsUpdate)
                    {
                        dataModification.AddAction = AddAction.Updating;
                    }
                    else if (dataModification.IsDelete)
                    {
                        dataModification.AddAction = AddAction.Removing;
                    }
                }
            }

            var executor = context.GetHookPoint<ISubmitExecutor>();
            if (executor == null)
            {
                throw new NotSupportedException();
            }

            context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken);
        }
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public async Task <SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetHookPoint <IChangeSetPreparer>();

            if (preparer == null)
            {
                throw new NotSupportedException();
            }

            await preparer.PrepareAsync(context, cancellationToken);

            // authorize
            var authorized = true;

            foreach (var authorizer in context
                     .GetHookPoints <ISubmitAuthorizer>().Reverse())
            {
                authorized = await authorizer.AuthorizeAsync(
                    context, cancellationToken);

                if (!authorized || context.Result != null)
                {
                    break;
                }
            }

            if (!authorized)
            {
                // TODO GitHubIssue#32 : Figure out a more appropriate exception
                throw new SecurityException();
            }

            if (context.Result != null)
            {
                return(context.Result);
            }

            ChangeSet eventsChangeSet = context.ChangeSet;

            IEnumerable <ChangeSetEntry> currentChangeSetItems;
            int outerLoopCount = 0;

            do
            {
                outerLoopCount++;
                int innerLoopCount = 0;
                do
                {
                    innerLoopCount++;
                    eventsChangeSet.AnEntityHasChanged = false;
                    currentChangeSetItems = eventsChangeSet.Entries.ToArray();

                    if (eventsChangeSet.AnEntityHasChanged)
                    {
                        eventsChangeSet.AnEntityHasChanged = false;
                        currentChangeSetItems = eventsChangeSet.Entries.ToArray();
                    }

                    await PerformValidate(context, currentChangeSetItems, cancellationToken);

                    await PerformPreEvent(context, currentChangeSetItems, cancellationToken);
                }while (eventsChangeSet.AnEntityHasChanged && (innerLoopCount < MaxLoop));

                VerifyNoEntityHasChanged(eventsChangeSet);

                await PerformPersist(context, currentChangeSetItems, cancellationToken);

                eventsChangeSet.Entries.Clear();

                await PerformPostEvent(context, currentChangeSetItems, cancellationToken);
            }while (eventsChangeSet.AnEntityHasChanged && (outerLoopCount < MaxLoop));

            VerifyNoEntityHasChanged(eventsChangeSet);

            return(context.Result);
        }