public static int UpdatedRowStatusContinue(IUpdatedRowOptions opts, BatchCommandInfo[] batchCommands, int commandCount)
        {
            Debug.Assert(null != batchCommands, "null batchCommands?");
            int cumulativeDataRowsAffected = 0;
            // 1. We delay accepting the changes until after we fire RowUpdatedEvent
            //    so the user has a chance to call RejectChanges for any given reason
            // 2. If the DataSource return 0 records affected, its an indication that
            //    the command didn't take so we don't want to automatically
            //    AcceptChanges.
            // With 'set nocount on' the count will be -1, accept changes in that case too.
            // 3.  Don't accept changes if no rows were affected, the user needs
            //     to know that there is a concurrency violation

            // Only accept changes if the row is not already accepted, ie detached.
            bool acdu = opts.AcceptChangesDuringUpdate;

            for (int i = 0; i < commandCount; i++)
            {
                DataRow row = batchCommands[i].Row;
                if ((null == batchCommands[i].Errors) && batchCommands[i].RecordsAffected.HasValue && (0 != batchCommands[i].RecordsAffected.Value))
                {
                    Debug.Assert(null != row, "null dataRow?");
                    if (acdu)
                    {
                        if (0 != ((DataRowState.Added | DataRowState.Deleted | DataRowState.Modified) & row.RowState))
                        {
                            row.AcceptChanges();
                        }
                    }
                    cumulativeDataRowsAffected++;
                }
            }
            return(cumulativeDataRowsAffected);
        }
        public static int UpdatedRowStatus(IUpdatedRowOptions opts, RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, int commandCount)
        {
            Debug.Assert(null != rowUpdatedEvent, "null rowUpdatedEvent");
            int cumulativeDataRowsAffected;

            switch (rowUpdatedEvent.Status)
            {
            case UpdateStatus.Continue:
                cumulativeDataRowsAffected = UpdatedRowStatusContinue(opts, batchCommands, commandCount);
                break;     // return to foreach DataRow

            case UpdateStatus.ErrorsOccurred:
                cumulativeDataRowsAffected = UpdatedRowStatusErrors(opts, rowUpdatedEvent, batchCommands, commandCount);
                break;     // no datarow affected if ErrorsOccured

            case UpdateStatus.SkipCurrentRow:
            case UpdateStatus.SkipAllRemainingRows: // cancel the Update method
                cumulativeDataRowsAffected = UpdatedRowStatusSkip(batchCommands, commandCount);
                break;                              // foreach DataRow without accepting changes on this row (but user may haved accepted chagnes for us)

            default:
                throw ADP.InvalidUpdateStatus(rowUpdatedEvent.Status);
            }

            return(cumulativeDataRowsAffected);
        }
        public static int UpdatedRowStatusErrors(IUpdatedRowOptions opts, RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, int commandCount)
        {
            Debug.Assert(null != batchCommands, "null batchCommands?");
            Exception errors = rowUpdatedEvent.Errors;

            if (null == errors)
            {
                // user changed status to ErrorsOccured without supplying an exception message
                errors = new DataException("RowUpdatedEvent: Errors occurred; no additional is information available.");
                rowUpdatedEvent.Errors = errors;
            }

            int    affected = 0;
            bool   done     = false;
            string message  = errors.Message;

            for (int i = 0; i < commandCount; i++)
            {
                DataRow row = batchCommands[i].Row;
                Debug.Assert(null != row, "null dataRow?");

                if (null != batchCommands[i].Errors)
                { // will exist if 0 == RecordsAffected
                    string rowMsg = batchCommands[i].Errors.Message;
                    if (String.IsNullOrEmpty(rowMsg))
                    {
                        rowMsg = message;
                    }
                    row.RowError += rowMsg;
                    done          = true;
                }
            }

            if (!done)
            { // all rows are in 'error'
                for (int i = 0; i < commandCount; i++)
                {
                    DataRow row = batchCommands[i].Row;
                    // its possible a DBConcurrencyException exists and all rows have records affected
                    // via not overriding GetBatchedRecordsAffected or user setting the exception
                    row.RowError += message; // MDAC 65808
                }
            }
            else
            {
                affected = UpdatedRowStatusContinue(opts, batchCommands, commandCount);
            }

            if (!opts.ContinueUpdateOnError)
            {
                throw errors; // out of Update
            }
            return(affected); // return the count of successful rows within the batch failure
        }