2 // System.Data.Common.DbDataAdapter.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Tim Coleman (tim@timcoleman.com)
7 // Sureshkumar T <tsureshkumar@novell.com>
8 // Veerapuram Varadhan <vvaradhan@novell.com>
11 // Copyright (C) Tim Coleman, 2002-2003
15 // Copyright (C) 2004, 2009 Novell, Inc (http://www.novell.com)
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System.Collections;
39 using System.ComponentModel;
41 using System.Reflection;
42 using System.Runtime.InteropServices;
44 namespace System.Data.Common
47 public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
49 public abstract class DbDataAdapter : DataAdapter, ICloneable
54 public const string DefaultSourceTableName = "Table";
55 const string DefaultSourceColumnName = "Column";
56 CommandBehavior _behavior = CommandBehavior.Default;
59 IDbCommand _selectCommand;
60 IDbCommand _updateCommand;
61 IDbCommand _deleteCommand;
62 IDbCommand _insertCommand;
69 protected DbDataAdapter ()
73 protected DbDataAdapter (DbDataAdapter adapter) : base (adapter)
82 protected internal CommandBehavior FillCommandBehavior {
83 get { return _behavior; }
84 set { _behavior = value; }
87 IDbCommand IDbDataAdapter.SelectCommand {
88 get { return ((DbDataAdapter)this).SelectCommand; }
89 set { ((DbDataAdapter)this).SelectCommand = (DbCommand)value; }
92 IDbCommand IDbDataAdapter.UpdateCommand{
93 get { return ((DbDataAdapter)this).UpdateCommand; }
94 set { ((DbDataAdapter)this).UpdateCommand = (DbCommand)value; }
97 IDbCommand IDbDataAdapter.DeleteCommand{
98 get { return ((DbDataAdapter)this).DeleteCommand; }
99 set { ((DbDataAdapter)this).DeleteCommand = (DbCommand)value; }
102 IDbCommand IDbDataAdapter.InsertCommand{
103 get { return ((DbDataAdapter)this).InsertCommand; }
104 set { ((DbDataAdapter)this).InsertCommand = (DbCommand)value; }
108 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
109 public DbCommand SelectCommand {
111 return (DbCommand) _selectCommand;
112 //return (DbCommand) ((IDbDataAdapter)this).SelectCommand;
115 if (_selectCommand != value) {
116 _selectCommand = value;
117 ((IDbDataAdapter)this).SelectCommand = value;
123 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
124 public DbCommand DeleteCommand {
126 return (DbCommand) _deleteCommand;
127 //return (DbCommand) ((IDbDataAdapter)this).DeleteCommand;
130 if (_deleteCommand != value) {
131 _deleteCommand = value;
132 ((IDbDataAdapter)this).DeleteCommand = value;
138 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
139 public DbCommand InsertCommand {
141 return (DbCommand) _insertCommand;
142 //return (DbCommand) ((IDbDataAdapter)this).InsertCommand;
145 if (_insertCommand != value) {
146 _insertCommand = value;
147 ((IDbDataAdapter)this).InsertCommand = value;
153 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
154 public DbCommand UpdateCommand {
156 return (DbCommand) _updateCommand;
157 //return (DbCommand) ((IDbDataAdapter)this).DeleteCommand;
160 if (_updateCommand != value) {
161 _updateCommand = value;
162 ((IDbDataAdapter)this).UpdateCommand = value;
168 public virtual int UpdateBatchSize {
172 throw new NotSupportedException ();
177 #endregion // Properties
181 #if ONLY_1_0 || ONLY_1_1
182 [DataCategory ("Fill")]
183 [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
184 public event FillErrorEventHandler FillError;
192 protected virtual RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
193 StatementType statementType,
194 DataTableMapping tableMapping)
196 return new RowUpdatedEventArgs (dataRow, command, statementType, tableMapping);
199 protected virtual RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
200 StatementType statementType,
201 DataTableMapping tableMapping)
203 return new RowUpdatingEventArgs (dataRow, command, statementType, tableMapping);
206 protected virtual void OnRowUpdated (RowUpdatedEventArgs value)
208 if (Events ["RowUpdated"] != null) {
209 Delegate [] rowUpdatedList = Events ["RowUpdated"].GetInvocationList ();
210 foreach (Delegate rowUpdated in rowUpdatedList) {
211 MethodInfo rowUpdatedMethod = rowUpdated.Method;
212 rowUpdatedMethod.Invoke (value, null);
217 protected virtual void OnRowUpdating (RowUpdatingEventArgs value)
219 if (Events ["RowUpdating"] != null) {
220 Delegate [] rowUpdatingList = Events ["RowUpdating"].GetInvocationList ();
221 foreach (Delegate rowUpdating in rowUpdatingList) {
222 MethodInfo rowUpdatingMethod = rowUpdating.Method;
223 rowUpdatingMethod.Invoke (value, null);
228 protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
229 StatementType statementType,
230 DataTableMapping tableMapping);
232 protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
233 StatementType statementType,
234 DataTableMapping tableMapping);
236 protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
237 protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
240 protected override void Dispose (bool disposing)
243 IDbDataAdapter da = (IDbDataAdapter) this;
244 if (da.SelectCommand != null) {
245 da.SelectCommand.Dispose();
246 da.SelectCommand = null;
248 if (da.InsertCommand != null) {
249 da.InsertCommand.Dispose();
250 da.InsertCommand = null;
252 if (da.UpdateCommand != null) {
253 da.UpdateCommand.Dispose();
254 da.UpdateCommand = null;
256 if (da.DeleteCommand != null) {
257 da.DeleteCommand.Dispose();
258 da.DeleteCommand = null;
263 public override int Fill (DataSet dataSet)
265 return Fill (dataSet, 0, 0, DefaultSourceTableName, ((IDbDataAdapter) this).SelectCommand, _behavior);
268 public int Fill (DataTable dataTable)
270 if (dataTable == null)
271 throw new ArgumentNullException ("DataTable");
273 return Fill (dataTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
276 public int Fill (DataSet dataSet, string srcTable)
278 return Fill (dataSet, 0, 0, srcTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
282 protected virtual int Fill (DataTable dataTable, IDataReader dataReader)
284 return base.FillInternal (dataTable, dataReader);
288 protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
290 CommandBehavior commandBehavior = behavior;
292 // first see that the connection is not close.
293 if (command.Connection.State == ConnectionState.Closed) {
294 command.Connection.Open ();
295 commandBehavior |= CommandBehavior.CloseConnection;
297 return Fill (dataTable, command.ExecuteReader (commandBehavior));
300 public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
302 return this.Fill (dataSet, startRecord, maxRecords, srcTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
307 public int Fill (int startRecord, int maxRecords, params DataTable[] dataTables)
309 throw new NotImplementedException ();
313 protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
315 throw new NotImplementedException ();
318 protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
320 return base.FillInternal (dataSet, srcTable, dataReader, startRecord, maxRecords);
324 protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
326 if (command.Connection == null)
327 throw new InvalidOperationException ("Connection state is closed");
329 if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
330 behavior |= CommandBehavior.KeyInfo;
331 CommandBehavior commandBehavior = behavior;
333 if (command.Connection.State == ConnectionState.Closed) {
334 command.Connection.Open ();
335 commandBehavior |= CommandBehavior.CloseConnection;
337 return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior),
338 startRecord, maxRecords);
343 /// Fills the given datatable using values from reader. if a value
344 /// for a column is null, that will be filled with default value.
346 /// <returns>No. of rows affected </returns>
347 internal static int FillFromReader (DataTable table,
352 LoadOption loadOption
355 if (reader.FieldCount == 0)
358 for (int i = 0; i < start; i++)
362 object [] values = new object [mapping.Length];
363 while (reader.Read () && (length == 0 || counter < length)) {
364 for (int i = 0 ; i < mapping.Length; i++)
365 values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
366 table.BeginLoadData ();
367 table.LoadDataRow (values, loadOption);
368 table.EndLoadData ();
374 internal static int FillFromReader (DataTable table,
379 LoadOption loadOption,
380 FillErrorEventHandler errorHandler)
382 if (reader.FieldCount == 0)
385 for (int i = 0; i < start; i++)
389 object [] values = new object [mapping.Length];
390 while (reader.Read () && (length == 0 || counter < length)) {
391 for (int i = 0 ; i < mapping.Length; i++)
392 values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
393 table.BeginLoadData ();
395 table.LoadDataRow (values, loadOption);
396 } catch (Exception e) {
397 FillErrorEventArgs args = new FillErrorEventArgs (table, values);
399 args.Continue = false;
400 errorHandler (table, args);
401 // if args.Continue is not set to true or if a handler is not set, rethrow the error..
405 table.EndLoadData ();
412 public override DataTable [] FillSchema (DataSet dataSet, SchemaType schemaType)
414 return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, DefaultSourceTableName, _behavior);
417 public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
419 return FillSchema (dataTable, schemaType, ((IDbDataAdapter) this).SelectCommand, _behavior);
422 public DataTable [] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
424 return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, srcTable, _behavior);
427 protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
429 if (dataTable == null)
430 throw new ArgumentNullException ("DataTable");
432 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
433 if (command.Connection.State == ConnectionState.Closed) {
434 command.Connection.Open ();
435 behavior |= CommandBehavior.CloseConnection;
438 IDataReader reader = command.ExecuteReader (behavior);
440 string tableName = SetupSchema (schemaType, dataTable.TableName);
441 if (tableName != null) {
442 // FillSchema should add the KeyInfo unless MissingSchemaAction
443 // is set to Ignore or Error.
444 MissingSchemaAction schemaAction = MissingSchemaAction;
445 if (!(schemaAction == MissingSchemaAction.Ignore ||
446 schemaAction == MissingSchemaAction.Error))
447 schemaAction = MissingSchemaAction.AddWithKey;
449 BuildSchema (reader, dataTable, schemaType, schemaAction,
450 MissingMappingAction, TableMappings);
458 protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
461 throw new ArgumentNullException ("DataSet");
463 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
464 if (command.Connection.State == ConnectionState.Closed) {
465 command.Connection.Open ();
466 behavior |= CommandBehavior.CloseConnection;
469 IDataReader reader = command.ExecuteReader (behavior);
470 ArrayList output = new ArrayList ();
471 string tableName = srcTable;
475 // FillSchema should add the KeyInfo unless MissingSchemaAction
476 // is set to Ignore or Error.
477 MissingSchemaAction schemaAction = MissingSchemaAction;
478 if (!(MissingSchemaAction == MissingSchemaAction.Ignore ||
479 MissingSchemaAction == MissingSchemaAction.Error))
480 schemaAction = MissingSchemaAction.AddWithKey;
483 tableName = SetupSchema (schemaType, tableName);
484 if (tableName != null) {
485 if (dataSet.Tables.Contains (tableName))
486 table = dataSet.Tables [tableName];
488 // Do not create schema if MissingSchemAction is set to Ignore
489 if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
491 table = dataSet.Tables.Add (tableName);
494 BuildSchema (reader, table, schemaType, schemaAction,
495 MissingMappingAction, TableMappings);
497 tableName = String.Format ("{0}{1}", srcTable, ++index);
499 }while (reader.NextResult ());
503 return (DataTable []) output.ToArray (typeof (DataTable));
506 [EditorBrowsable (EditorBrowsableState.Advanced)]
507 public override IDataParameter[] GetFillParameters ()
509 IDbCommand selectCmd = ((IDbDataAdapter) this).SelectCommand;
510 IDataParameter[] parameters = new IDataParameter [selectCmd.Parameters.Count];
511 selectCmd.Parameters.CopyTo (parameters, 0);
516 [Obsolete ("use 'protected DbDataAdapter(DbDataAdapter)' ctor")]
517 object ICloneable.Clone ()
519 throw new NotImplementedException ();
522 public int Update (DataRow [] dataRows)
524 if (dataRows == null)
525 throw new ArgumentNullException("dataRows");
527 if (dataRows.Length == 0)
530 if (dataRows [0] == null)
531 throw new ArgumentException("dataRows[0].");
533 DataTable table = dataRows [0].Table;
535 throw new ArgumentException("table is null reference.");
537 // all rows must be in the same table
538 for (int i = 0; i < dataRows.Length; i++) {
539 if (dataRows [i] == null)
540 throw new ArgumentException ("dataRows[" + i + "].");
541 if (dataRows [i].Table != table)
542 throw new ArgumentException(
545 + "] is from a different DataTable than DataRow[0].");
548 // get table mapping for this rows
549 DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);
550 if (tableMapping == null) {
551 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(
555 MissingMappingAction);
556 if (tableMapping != null) {
557 foreach (DataColumn col in table.Columns) {
558 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
560 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
561 if (columnMapping == null)
562 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
563 tableMapping.ColumnMappings.Add (columnMapping);
566 ArrayList cmc = new ArrayList ();
567 foreach (DataColumn col in table.Columns)
568 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
570 new DataTableMapping (
573 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
577 DataRow[] copy = table.NewRowArray (dataRows.Length);
578 Array.Copy (dataRows, 0, copy, 0, dataRows.Length);
579 return Update (copy, tableMapping);
582 public override int Update (DataSet dataSet)
584 return Update (dataSet, DefaultSourceTableName);
587 public int Update (DataTable dataTable)
590 int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
592 throw new ArgumentException ();
593 return Update (dataTable, TableMappings [index]);
595 DataTableMapping tableMapping = TableMappings.GetByDataSetTable (dataTable.TableName);
596 if (tableMapping == null) {
597 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (
601 MissingMappingAction);
602 if (tableMapping != null) {
603 foreach (DataColumn col in dataTable.Columns) {
604 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
606 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
607 if (columnMapping == null)
608 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
609 tableMapping.ColumnMappings.Add (columnMapping);
612 ArrayList cmc = new ArrayList ();
613 foreach (DataColumn col in dataTable.Columns)
614 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
616 new DataTableMapping (
619 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
622 return Update (dataTable, tableMapping);
625 private int Update (DataTable dataTable, DataTableMapping tableMapping)
627 DataRow [] rows = dataTable.NewRowArray(dataTable.Rows.Count);
628 dataTable.Rows.CopyTo (rows, 0);
629 return Update (rows, tableMapping);
632 protected virtual int Update (DataRow [] dataRows, DataTableMapping tableMapping)
635 foreach (DataRow row in dataRows) {
636 StatementType statementType = StatementType.Update;
637 IDbCommand command = null;
638 string commandName = String.Empty;
640 switch (row.RowState) {
641 case DataRowState.Added:
642 statementType = StatementType.Insert;
643 command = ((IDbDataAdapter) this).InsertCommand;
644 commandName = "Insert";
646 case DataRowState.Deleted:
647 statementType = StatementType.Delete;
648 command = ((IDbDataAdapter) this).DeleteCommand;
649 commandName = "Delete";
651 case DataRowState.Modified:
652 statementType = StatementType.Update;
653 command = ((IDbDataAdapter) this).UpdateCommand;
654 commandName = "Update";
656 case DataRowState.Unchanged:
657 case DataRowState.Detached:
661 RowUpdatingEventArgs argsUpdating = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
663 OnRowUpdating (argsUpdating);
664 switch (argsUpdating.Status) {
665 case UpdateStatus.Continue :
666 //continue in update operation
668 case UpdateStatus.ErrorsOccurred :
669 if (argsUpdating.Errors == null)
670 argsUpdating.Errors = ExceptionHelper.RowUpdatedError();
671 row.RowError += argsUpdating.Errors.Message;
672 if (!ContinueUpdateOnError)
673 throw argsUpdating.Errors;
675 case UpdateStatus.SkipAllRemainingRows :
677 case UpdateStatus.SkipCurrentRow :
681 throw ExceptionHelper.InvalidUpdateStatus (argsUpdating.Status);
683 command = argsUpdating.Command;
685 if (command != null) {
686 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
688 IDataParameter nullCheckParam = null;
690 foreach (IDataParameter parameter in command.Parameters) {
691 if ((parameter.Direction & ParameterDirection.Input) == 0)
694 DataRowVersion rowVersion = parameter.SourceVersion;
695 // Parameter version is ignored for non-update commands
696 if (statementType == StatementType.Delete)
697 rowVersion = DataRowVersion.Original;
699 string dsColumnName = parameter.SourceColumn;
701 if (columnMappings.Contains(dsColumnName)) {
702 dsColumnName = columnMappings [dsColumnName].DataSetColumn;
703 parameter.Value = row [dsColumnName, rowVersion];
705 parameter.Value = null;
708 DbParameter nullCheckParam = parameter as DbParameter;
710 if (columnMappings.Contains(dsColumnName))
711 dsColumnName = columnMappings [dsColumnName].DataSetColumn;
712 if (dsColumnName == null || dsColumnName.Length == 0) {
713 nullCheckParam = parameter;
716 parameter.Value = row [dsColumnName, rowVersion];
720 if (nullCheckParam != null && nullCheckParam.SourceColumnNullMapping) {
722 if (nullCheckParam != null) {
724 if (parameter.Value != null && parameter.Value != DBNull.Value)
725 nullCheckParam.Value = 0;
727 nullCheckParam.Value = 1;
728 nullCheckParam = null;
732 } catch (Exception e) {
733 argsUpdating.Errors = e;
734 argsUpdating.Status = UpdateStatus.ErrorsOccurred;
737 IDataReader reader = null;
740 throw ExceptionHelper.UpdateRequiresCommand (commandName);
742 CommandBehavior commandBehavior = CommandBehavior.Default;
743 if (command.Connection.State == ConnectionState.Closed) {
744 command.Connection.Open ();
745 commandBehavior |= CommandBehavior.CloseConnection;
748 // use ExecuteReader because we want to use the commandbehavior parameter.
749 // so the connection will be closed if needed.
750 reader = command.ExecuteReader (commandBehavior);
752 // update the current row, if the update command returns any resultset
753 // ignore other than the first record.
754 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
756 if (command.UpdatedRowSource == UpdateRowSource.Both ||
757 command.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord) {
759 DataTable retSchema = reader.GetSchemaTable ();
760 foreach (DataRow dr in retSchema.Rows) {
761 string columnName = dr ["ColumnName"].ToString ();
762 string dstColumnName = columnName;
763 if (columnMappings != null &&
764 columnMappings.Contains(columnName))
765 dstColumnName = columnMappings [dstColumnName].DataSetColumn;
766 DataColumn dstColumn = row.Table.Columns [dstColumnName];
767 if (dstColumn == null
768 || (dstColumn.Expression != null
769 && dstColumn.Expression.Length > 0))
771 // info from : http://www.error-bank.com/microsoft.public.dotnet.framework.windowsforms.databinding/
772 // _35_hcsyiv0dha.2328@tk2msftngp10.phx.gbl_Thread.aspx
773 // disable readonly for non-expression columns.
774 bool readOnlyState = dstColumn.ReadOnly;
775 dstColumn.ReadOnly = false;
777 row [dstColumnName] = reader [columnName];
779 dstColumn.ReadOnly = readOnlyState;
786 int tmp = reader.RecordsAffected; // records affected is valid only after closing reader
787 // if the execute does not effect any rows we throw an exception.
789 throw new DBConcurrencyException("Concurrency violation: the " +
790 commandName +"Command affected 0 records.", null,
791 new DataRow [] { row });
794 if (command.UpdatedRowSource == UpdateRowSource.Both ||
795 command.UpdatedRowSource == UpdateRowSource.OutputParameters) {
796 // Update output parameters to row values
797 foreach (IDataParameter parameter in command.Parameters) {
798 if (parameter.Direction != ParameterDirection.InputOutput
799 && parameter.Direction != ParameterDirection.Output
800 && parameter.Direction != ParameterDirection.ReturnValue)
803 string dsColumnName = parameter.SourceColumn;
804 if (columnMappings != null &&
805 columnMappings.Contains(parameter.SourceColumn))
806 dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
807 DataColumn dstColumn = row.Table.Columns [dsColumnName];
808 if (dstColumn == null
809 || (dstColumn.Expression != null
810 && dstColumn.Expression.Length > 0))
812 bool readOnlyState = dstColumn.ReadOnly;
813 dstColumn.ReadOnly = false;
815 row [dsColumnName] = parameter.Value;
817 dstColumn.ReadOnly = readOnlyState;
822 RowUpdatedEventArgs updatedArgs = CreateRowUpdatedEvent (row, command, statementType, tableMapping);
823 OnRowUpdated (updatedArgs);
824 switch (updatedArgs.Status) {
825 case UpdateStatus.Continue:
827 case UpdateStatus.ErrorsOccurred:
828 if (updatedArgs.Errors == null)
829 updatedArgs.Errors = ExceptionHelper.RowUpdatedError();
830 row.RowError += updatedArgs.Errors.Message;
831 if (!ContinueUpdateOnError)
832 throw updatedArgs.Errors;
834 case UpdateStatus.SkipCurrentRow:
836 case UpdateStatus.SkipAllRemainingRows:
840 if (!AcceptChangesDuringUpdate)
843 row.AcceptChanges ();
844 } catch (Exception e) {
845 row.RowError = e.Message;
846 if (!ContinueUpdateOnError)
849 if (reader != null && ! reader.IsClosed)
856 public int Update (DataSet dataSet, string srcTable)
858 MissingMappingAction mappingAction = MissingMappingAction;
860 if (mappingAction == MissingMappingAction.Ignore)
861 mappingAction = MissingMappingAction.Error;
863 DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, srcTable, srcTable, mappingAction);
865 DataTable dataTable = dataSet.Tables [tableMapping.DataSetTable];
866 if (dataTable == null)
867 throw new ArgumentException (String.Format ("Missing table {0}",
869 return Update (dataTable, tableMapping);
873 // All the batch methods, should be implemented, if supported,
874 // by individual providers
876 protected virtual int AddToBatch (IDbCommand command)
878 throw CreateMethodNotSupportedException ();
881 protected virtual void ClearBatch ()
883 throw CreateMethodNotSupportedException ();
886 protected virtual int ExecuteBatch ()
888 throw CreateMethodNotSupportedException ();
891 protected virtual IDataParameter GetBatchedParameter (int commandIdentifier, int parameterIndex)
893 throw CreateMethodNotSupportedException ();
896 protected virtual bool GetBatchedRecordsAffected (int commandIdentifier, out int recordsAffected, out Exception error)
903 protected virtual void InitializeBatching ()
905 throw CreateMethodNotSupportedException ();
908 protected virtual void TerminateBatching ()
910 throw CreateMethodNotSupportedException ();
913 Exception CreateMethodNotSupportedException ()
915 return new NotSupportedException ("Method is not supported.");
918 internal override void OnFillErrorInternal (FillErrorEventArgs value)
923 protected virtual void OnFillError (FillErrorEventArgs value)
925 if (FillError != null)
926 FillError (this, value);
929 #endregion // Methods