private void UpdateBatchExecute(BatchCommandInfo[] batchCommands, int commandCount, RowUpdatedEventArgs rowUpdatedEvent)
{
try
{
// the batch execution may succeed, partially succeed and throw an exception (or not), or totally fail
int recordsAffected = ExecuteBatch();
rowUpdatedEvent.AdapterInit(recordsAffected);
}
catch (DbException e)
{
// an exception was thrown be but some part of the batch may have been succesfull
ADP.TraceExceptionForCapture(e);
rowUpdatedEvent.Errors = e;
rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
}
Data.MissingMappingAction missingMapping = UpdateMappingAction;
Data.MissingSchemaAction missingSchema = UpdateSchemaAction;
int checkRecordsAffected = 0;
bool hasConcurrencyViolation = false;
List<DataRow> rows = null;
// walk through the batch to build the sum of recordsAffected
// determine possible indivdual messages per datarow
// determine possible concurrency violations per datarow
// map output parameters to the datarow
for (int bc = 0; bc < commandCount; ++bc)
{
BatchCommandInfo batchCommand = batchCommands[bc];
StatementType statementType = batchCommand._statementType;
// default implementation always returns 1, derived classes must override
// otherwise DbConcurrencyException will only be thrown if sum of all records in batch is 0
int rowAffected;
if (GetBatchedRecordsAffected(batchCommand._commandIdentifier, out rowAffected, out batchCommands[bc]._errors))
{
batchCommands[bc]._recordsAffected = rowAffected;
}
if ((null == batchCommands[bc]._errors) && batchCommands[bc]._recordsAffected.HasValue)
{
// determine possible concurrency violations per datarow
if ((StatementType.Update == statementType) || (StatementType.Delete == statementType))
{
checkRecordsAffected++;
if (0 == rowAffected)
{
if (null == rows)
{
rows = new List<DataRow>();
}
batchCommands[bc]._errors = ADP.UpdateConcurrencyViolation(batchCommands[bc]._statementType, 0, 1, new DataRow[] { rowUpdatedEvent.Rows[bc] });
hasConcurrencyViolation = true;
rows.Add(rowUpdatedEvent.Rows[bc]);
}
}
// map output parameters to the datarow
if (((StatementType.Insert == statementType) || (StatementType.Update == statementType))
&& (0 != (UpdateRowSource.OutputParameters & batchCommand._updatedRowSource)) && (0 != rowAffected))
{
if (StatementType.Insert == statementType)
{
// AcceptChanges for 'added' rows so backend generated keys that are returned
// propagte into the datatable correctly.
rowUpdatedEvent.Rows[bc].AcceptChanges();
}
for (int i = 0; i < batchCommand._parameterCount; ++i)
{
IDataParameter parameter = GetBatchedParameter(batchCommand._commandIdentifier, i);
ParameterOutput(parameter, batchCommand._row, rowUpdatedEvent.TableMapping, missingMapping, missingSchema);
}
}
}
}
if (null == rowUpdatedEvent.Errors)
{
// Only error if RecordsAffect == 0, not -1. A value of -1 means no count was received from server,
// do not error in that situation (means 'set nocount on' was executed on server).
if (UpdateStatus.Continue == rowUpdatedEvent.Status)
{
if ((0 < checkRecordsAffected) && ((0 == rowUpdatedEvent.RecordsAffected) || hasConcurrencyViolation))
{
// bug50526, an exception if no records affected and attempted an Update/Delete
Debug.Assert(null == rowUpdatedEvent.Errors, "Continue - but contains an exception");
DataRow[] rowsInError = (null != rows) ? rows.ToArray() : rowUpdatedEvent.Rows;
rowUpdatedEvent.Errors = ADP.UpdateConcurrencyViolation(StatementType.Batch, commandCount - rowsInError.Length, commandCount, rowsInError);
rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
}
}
}
}