2 // System.Data.Common.DbDataAdapter.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Tim Coleman (tim@timcoleman.com)
7 // Sureshkumar T <tsureshkumar@novell.com>
10 // Copyright (C) Tim Coleman, 2002-2003
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.ComponentModel;
40 using System.Runtime.InteropServices;
42 namespace System.Data.Common {
43 public abstract class DbDataAdapter : DataAdapter, ICloneable
47 public const string DefaultSourceTableName = "Table";
48 const string DefaultSourceColumnName = "Column";
54 protected DbDataAdapter()
59 protected DbDataAdapter(DbDataAdapter adapter) : base(adapter)
69 protected virtual IDbConnection BaseConnection {
70 get { throw new NotImplementedException (); }
71 set { throw new NotImplementedException (); }
74 public IDbConnection Connection {
75 get { return BaseConnection; }
76 set { BaseConnection = value; }
80 IDbCommand DeleteCommand {
81 get { return ((IDbDataAdapter) this).DeleteCommand; }
85 protected internal CommandBehavior FillCommandBehavior {
86 get { throw new NotImplementedException (); }
87 set { throw new NotImplementedException (); }
91 IDbCommand InsertCommand {
92 get { return ((IDbDataAdapter) this).InsertCommand; }
97 protected virtual IDbCommand this [[Optional] StatementType statementType] {
98 get { throw new NotImplementedException (); }
99 set { throw new NotImplementedException (); }
102 protected virtual DbProviderFactory ProviderFactory {
103 get { throw new NotImplementedException (); }
107 IDbCommand SelectCommand {
108 get { return ((IDbDataAdapter) this).SelectCommand; }
113 public IDbTransaction Transaction {
114 get { throw new NotImplementedException (); }
115 set { throw new NotImplementedException (); }
119 public int UpdateBatchSize {
120 get { throw new NotImplementedException (); }
121 set { throw new NotImplementedException (); }
125 IDbCommand UpdateCommand {
126 get { return ((IDbDataAdapter) this).UpdateCommand; }
129 #endregion // Properties
133 #if ONLY_1_0 || ONLY_1_1
135 [DataCategory ("Fill")]
136 [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
137 public event FillErrorEventHandler FillError;
146 public virtual void BeginInit ()
148 throw new NotImplementedException ();
152 protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
153 protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
155 private FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e)
157 FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values);
159 args.Continue = false;
163 protected override void Dispose (bool disposing)
166 IDbDataAdapter da = (IDbDataAdapter) this;
167 if (da.SelectCommand != null) {
168 da.SelectCommand.Dispose();
169 da.SelectCommand = null;
171 if (da.InsertCommand != null) {
172 da.InsertCommand.Dispose();
173 da.InsertCommand = null;
175 if (da.UpdateCommand != null) {
176 da.UpdateCommand.Dispose();
177 da.UpdateCommand = null;
179 if (da.DeleteCommand != null) {
180 da.DeleteCommand.Dispose();
181 da.DeleteCommand = null;
188 public virtual void EndInit ()
190 throw new NotImplementedException ();
194 public override int Fill (DataSet dataSet)
196 return Fill (dataSet, 0, 0, DefaultSourceTableName, SelectCommand, CommandBehavior.Default);
199 public int Fill (DataTable dataTable)
201 if (dataTable == null)
202 throw new NullReferenceException ();
204 return Fill (dataTable, SelectCommand, CommandBehavior.Default);
207 public int Fill (DataSet dataSet, string srcTable)
209 return Fill (dataSet, 0, 0, srcTable, SelectCommand, CommandBehavior.Default);
213 protected override int Fill (DataTable dataTable, IDataReader dataReader)
215 protected virtual int Fill (DataTable dataTable, IDataReader dataReader)
218 if (dataReader.FieldCount == 0) {
226 string tableName = SetupSchema (SchemaType.Mapped, dataTable.TableName);
227 if (tableName != null) {
228 dataTable.TableName = tableName;
229 FillTable (dataTable, dataReader, 0, 0, ref count);
238 protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
240 CommandBehavior commandBehavior = behavior;
241 // first see that the connection is not close.
242 if (command.Connection.State == ConnectionState.Closed)
244 command.Connection.Open ();
245 commandBehavior |= CommandBehavior.CloseConnection;
247 return Fill (dataTable, command.ExecuteReader (commandBehavior));
252 public int Fill (int startRecord, int maxRecords, DataTable[] dataTables)
254 throw new NotImplementedException ();
258 public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
260 return this.Fill (dataSet, startRecord, maxRecords, srcTable, SelectCommand, CommandBehavior.Default);
265 protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
267 throw new NotImplementedException ();
272 protected override int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
274 protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
278 throw new ArgumentException ("The startRecord parameter was less than 0.");
280 throw new ArgumentException ("The maxRecords parameter was less than 0.");
287 string tableName = srcTable;
289 // Non-resultset queries like insert, delete or update aren't processed.
290 if (dataReader.FieldCount != -1)
292 tableName = SetupSchema (SchemaType.Mapped, tableName);
293 if (tableName != null) {
295 // check if the table exists in the dataset
296 if (dataSet.Tables.Contains (tableName))
297 // get the table from the dataset
298 dataTable = dataSet.Tables [tableName];
300 dataTable = new DataTable(tableName);
301 dataSet.Tables.Add (dataTable);
304 if (!FillTable (dataTable, dataReader, startRecord, maxRecords, ref count)) {
308 tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
314 } while (dataReader.NextResult ());
323 protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
325 if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
326 behavior |= CommandBehavior.KeyInfo;
327 CommandBehavior commandBehavior = behavior;
328 if (command.Connection.State == ConnectionState.Closed) {
329 command.Connection.Open ();
330 commandBehavior |= CommandBehavior.CloseConnection;
332 return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
335 private bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter)
337 if (dataReader.FieldCount == 0)
340 int[] mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
342 FillTable (dataTable, dataReader, startRecord, maxRecords, mapping,
343 AcceptChangesDuringFill, ref counter);
344 } catch (Exception e) {
345 object[] readerArray = new object[dataReader.FieldCount];
346 object[] tableArray = new object[dataReader.FieldCount];
347 // we get the values from the datareader
348 dataReader.GetValues (readerArray);
349 // copy from datareader columns to table columns according to given mapping
351 for (int i = 0; i < dataTable.Columns.Count; i++) {
352 if (mapping [i] >= 0)
353 tableArray[count++] = readerArray[mapping[i]];
355 FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e);
365 /// Fills the given datatable using values from reader. if a column
366 /// does not have a mapped reader column (-1 in mapping), that will
367 /// be filled with default value.
369 internal static void FillTable (DataTable dataTable,
370 IDataReader dataReader,
377 if (dataReader.FieldCount == 0)
380 for (int i = 0; i < startRecord; i++)
383 int counterStart = counter;
384 while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) {
385 dataTable.BeginLoadData ();
386 dataTable.LoadDataRow (dataReader, mapping, acceptChanges);
387 dataTable.EndLoadData ();
393 /// Fills the given datatable using values from reader. if a value
394 /// for a column is null, that will be filled with default value.
396 /// <returns>No. of rows affected </returns>
397 internal static int FillFromReader (DataTable table,
402 LoadOption loadOption
405 if (reader.FieldCount == 0)
408 for (int i = 0; i < start; i++)
412 object [] values = new object [mapping.Length];
413 while (reader.Read () &&
414 (length == 0 || counter < length)) {
416 for (int i = 0 ; i < mapping.Length; i++)
417 values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
419 table.BeginLoadData ();
420 table.LoadDataRow (values, loadOption);
421 table.EndLoadData ();
429 public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType)
431 return FillSchema (dataSet, schemaType, SelectCommand, DefaultSourceTableName, CommandBehavior.Default);
434 public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
436 return FillSchema (dataTable, schemaType, SelectCommand, CommandBehavior.Default);
439 public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
441 return FillSchema (dataSet, schemaType, SelectCommand, srcTable, CommandBehavior.Default);
444 [MonoTODO ("Verify")]
445 protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
447 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
448 if (command.Connection.State == ConnectionState.Closed) {
449 command.Connection.Open ();
450 behavior |= CommandBehavior.CloseConnection;
453 IDataReader reader = command.ExecuteReader (behavior);
456 string tableName = SetupSchema (schemaType, dataTable.TableName);
457 if (tableName != null)
459 BuildSchema (reader, dataTable, schemaType);
469 [MonoTODO ("Verify")]
470 protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
472 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
473 if (command.Connection.State == ConnectionState.Closed) {
474 command.Connection.Open ();
475 behavior |= CommandBehavior.CloseConnection;
478 IDataReader reader = command.ExecuteReader (behavior);
479 ArrayList output = new ArrayList ();
480 string tableName = srcTable;
485 tableName = SetupSchema (schemaType, tableName);
486 if (tableName != null)
488 if (dataSet.Tables.Contains (tableName))
489 table = dataSet.Tables [tableName];
492 table = new DataTable(tableName);
493 dataSet.Tables.Add (table);
495 BuildSchema (reader, table, schemaType);
497 tableName = String.Format ("{0}{1}", srcTable, ++index);
504 return (DataTable[]) output.ToArray (typeof (DataTable));
509 public DataSet GetDataSet ()
511 throw new NotImplementedException ();
515 public DataTable GetDataTable ()
517 throw new NotImplementedException ();
521 private string SetupSchema (SchemaType schemaType, string sourceTableName)
523 DataTableMapping tableMapping = null;
525 if (schemaType == SchemaType.Mapped)
527 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, sourceTableName, MissingMappingAction);
529 if (tableMapping != null)
530 return tableMapping.DataSetTable;
534 return sourceTableName;
537 [EditorBrowsable (EditorBrowsableState.Advanced)]
538 public override IDataParameter[] GetFillParameters ()
540 IDataParameter[] parameters = new IDataParameter[SelectCommand.Parameters.Count];
541 SelectCommand.Parameters.CopyTo (parameters, 0);
545 // this method builds the schema for a given datatable. it returns a int array with
546 // "array[ordinal of datatable column] == index of source column in data reader".
547 // each column in the datatable has a mapping to a specific column in the datareader,
548 // the int array represents this match.
550 private int[] BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType)
552 return BuildSchema (reader, table, schemaType, MissingSchemaAction,
553 MissingMappingAction, TableMappings);
557 /// Creates or Modifies the schema of the given DataTable based on the schema of
558 /// the reader and the arguments passed.
560 internal static int[] BuildSchema (IDataReader reader,
562 SchemaType schemaType,
563 MissingSchemaAction missingSchAction,
564 MissingMappingAction missingMapAction,
565 DataTableMappingCollection dtMapping
569 int[] mapping = new int[reader.FieldCount + table.Columns.Count]; // mapping the reader indexes to the datatable indexes
570 for (int i =0 ; i < mapping.Length; i++)
571 mapping [i] = -1; // no mapping
573 ArrayList primaryKey = new ArrayList ();
574 ArrayList sourceColumns = new ArrayList ();
576 foreach (DataRow schemaRow in reader.GetSchemaTable ().Rows) {
577 // generate a unique column name in the source table.
578 string sourceColumnName;
579 if (schemaRow.IsNull("ColumnName"))
580 sourceColumnName = DefaultSourceColumnName;
582 sourceColumnName = (string) schemaRow ["ColumnName"];
584 string realSourceColumnName = sourceColumnName;
586 for (int i = 1; sourceColumns.Contains (realSourceColumnName); i += 1)
587 realSourceColumnName = String.Format ("{0}{1}", sourceColumnName, i);
588 sourceColumns.Add(realSourceColumnName);
590 // generate DataSetColumnName from DataTableMapping, if any
591 string dsColumnName = realSourceColumnName;
592 DataTableMapping tableMapping = null;
593 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (dtMapping, table.TableName, table.TableName, missingMapAction);
594 if (tableMapping != null)
597 table.TableName = tableMapping.DataSetTable;
598 // check to see if the column mapping exists
599 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction);
600 if (columnMapping != null)
603 columnMapping.GetDataColumnBySchemaAction(
605 (Type)schemaRow["DataType"],
610 // if the column is not in the table - add it.
611 if (table.Columns.IndexOf(col) == -1)
613 if (missingSchAction == MissingSchemaAction.Add
614 || missingSchAction == MissingSchemaAction.AddWithKey)
615 table.Columns.Add(col);
618 if (missingSchAction == MissingSchemaAction.AddWithKey) {
619 if (!schemaRow["IsKey"].Equals (DBNull.Value))
620 if ((bool) (schemaRow ["IsKey"]))
621 primaryKey.Add (col);
623 col.AutoIncrement = (bool) schemaRow ["IsAutoIncrement"];
626 // add the ordinal of the column as a key and the index of the column in the datareader as a value.
627 mapping[col.Ordinal] = readerIndex;
633 if (primaryKey.Count > 0)
634 table.PrimaryKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn)));
641 object ICloneable.Clone ()
643 throw new NotImplementedException ();
647 public int Update (DataRow[] dataRows)
649 if (dataRows == null)
650 throw new ArgumentNullException("dataRows");
652 if (dataRows.Length == 0)
655 if (dataRows[0] == null)
656 throw new ArgumentException("dataRows[0].");
658 DataTable table = dataRows[0].Table;
660 throw new ArgumentException("table is null reference.");
662 // all rows must be in the same table
663 for (int i = 0; i < dataRows.Length; i++)
665 if (dataRows[i] == null)
666 throw new ArgumentException("dataRows[" + i + "].");
667 if (dataRows[i].Table != table)
668 throw new ArgumentException(
671 + "] is from a different DataTable than DataRow[0].");
674 // get table mapping for this rows
675 DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);
676 if (tableMapping == null)
678 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(
682 MissingMappingAction);
683 if (tableMapping != null) {
684 foreach (DataColumn col in table.Columns) {
685 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
687 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
688 if (columnMapping == null)
689 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
690 tableMapping.ColumnMappings.Add (columnMapping);
693 ArrayList cmc = new ArrayList ();
694 foreach (DataColumn col in table.Columns)
695 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
697 new DataTableMapping (
700 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
704 DataRow[] copy = new DataRow [dataRows.Length];
705 Array.Copy(dataRows, 0, copy, 0, dataRows.Length);
706 return Update(copy, tableMapping);
709 public override int Update (DataSet dataSet)
711 return Update (dataSet, DefaultSourceTableName);
714 public int Update (DataTable dataTable)
717 int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
719 throw new ArgumentException ();
720 return Update (dataTable, TableMappings [index]);
722 DataTableMapping tableMapping = TableMappings.GetByDataSetTable (dataTable.TableName);
723 if (tableMapping == null)
725 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (
729 MissingMappingAction);
730 if (tableMapping != null) {
731 foreach (DataColumn col in dataTable.Columns) {
732 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
734 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
735 if (columnMapping == null)
736 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
737 tableMapping.ColumnMappings.Add (columnMapping);
740 ArrayList cmc = new ArrayList ();
741 foreach (DataColumn col in dataTable.Columns)
742 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
744 new DataTableMapping (
747 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
750 return Update (dataTable, tableMapping);
753 private int Update (DataTable dataTable, DataTableMapping tableMapping)
755 DataRow[] rows = new DataRow [dataTable.Rows.Count];
756 dataTable.Rows.CopyTo (rows, 0);
757 return Update (rows, tableMapping);
761 protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping)
765 foreach (DataRow row in dataRows) {
766 StatementType statementType = StatementType.Update;
767 IDbCommand command = null;
768 string commandName = String.Empty;
769 bool useCommandBuilder = false;
771 switch (row.RowState) {
772 case DataRowState.Added:
773 statementType = StatementType.Insert;
774 command = InsertCommand;
775 commandName = "Insert";
777 case DataRowState.Deleted:
778 statementType = StatementType.Delete;
779 command = DeleteCommand;
780 commandName = "Delete";
782 case DataRowState.Modified:
783 statementType = StatementType.Update;
784 command = UpdateCommand;
785 commandName = "Update";
787 case DataRowState.Unchanged:
789 case DataRowState.Detached:
790 throw new NotImplementedException ();
794 useCommandBuilder = true;
796 RowUpdatingEventArgs updatingArgs = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
797 OnRowUpdating (updatingArgs);
799 if (updatingArgs.Status == UpdateStatus.ErrorsOccurred)
800 throw (updatingArgs.Errors);
802 if (command == null && updatingArgs.Command != null)
803 command = updatingArgs.Command;
804 else if (command == null)
805 throw new InvalidOperationException (String.Format ("Update requires a valid {0}Command when passed a DataRow collection with modified rows.", commandName));
807 if (!useCommandBuilder) {
808 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
810 foreach (IDataParameter parameter in command.Parameters) {
811 string dsColumnName = parameter.SourceColumn;
812 if (columnMappings.Contains(parameter.SourceColumn))
813 dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
814 if (dsColumnName == null || dsColumnName.Length <= 0)
816 DataRowVersion rowVersion = DataRowVersion.Default;
818 // Parameter version is ignored for non-update commands
819 if (statementType == StatementType.Update)
820 rowVersion = parameter.SourceVersion;
821 if (statementType == StatementType.Delete)
822 rowVersion = DataRowVersion.Original;
824 parameter.Value = row [dsColumnName, rowVersion];
828 CommandBehavior commandBehavior = CommandBehavior.Default;
829 if (command.Connection.State == ConnectionState.Closed)
831 command.Connection.Open ();
832 commandBehavior |= CommandBehavior.CloseConnection;
835 IDataReader reader = null;
838 // use ExecuteReader because we want to use the commandbehavior parameter.
839 // so the connection will be closed if needed.
840 reader = command.ExecuteReader (commandBehavior);
842 // update the current row, if the update command returns any resultset
843 // ignore other than the first record.
844 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
846 if (command.UpdatedRowSource == UpdateRowSource.Both ||
847 command.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord) {
849 DataTable retSchema = reader.GetSchemaTable ();
850 foreach (DataRow dr in retSchema.Rows) {
851 string columnName = dr ["ColumnName"].ToString ();
852 string dstColumnName = columnName;
853 if (columnMappings != null &&
854 columnMappings.Contains(columnName))
855 dstColumnName = columnMappings [dstColumnName].DataSetColumn;
856 DataColumn dstColumn = row.Table.Columns [dstColumnName];
857 if (dstColumn == null
858 || (dstColumn.Expression != null
859 && dstColumn.Expression.Length > 0))
861 // info from : http://www.error-bank.com/microsoft.public.dotnet.framework.windowsforms.databinding/
862 // _35_hcsyiv0dha.2328@tk2msftngp10.phx.gbl_Thread.aspx
863 // disable readonly for non-expression columns.
864 bool readOnlyState = dstColumn.ReadOnly;
865 dstColumn.ReadOnly = false;
867 row [dstColumnName] = reader [columnName];
869 dstColumn.ReadOnly = readOnlyState;
878 int tmp = reader.RecordsAffected; // records affected is valid only after closing reader
879 // if the execute does not effect any rows we throw an exception.
881 throw new DBConcurrencyException("Concurrency violation: the " +
882 commandName +"Command affected 0 records.");
885 if (command.UpdatedRowSource == UpdateRowSource.Both ||
886 command.UpdatedRowSource == UpdateRowSource.OutputParameters) {
887 // Update output parameters to row values
888 foreach (IDataParameter parameter in command.Parameters) {
889 if (parameter.Direction != ParameterDirection.InputOutput
890 && parameter.Direction != ParameterDirection.Output
891 && parameter.Direction != ParameterDirection.ReturnValue)
894 string dsColumnName = parameter.SourceColumn;
895 if (columnMappings != null &&
896 columnMappings.Contains(parameter.SourceColumn))
897 dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
898 DataColumn dstColumn = row.Table.Columns [dsColumnName];
899 if (dstColumn == null
900 || (dstColumn.Expression != null
901 && dstColumn.Expression.Length > 0))
903 bool readOnlyState = dstColumn.ReadOnly;
904 dstColumn.ReadOnly = false;
906 row [dsColumnName] = parameter.Value;
908 dstColumn.ReadOnly = readOnlyState;
915 RowUpdatedEventArgs updatedArgs = CreateRowUpdatedEvent(row, command, statementType, tableMapping);
916 OnRowUpdated(updatedArgs);
917 switch(updatedArgs.Status) {
918 case UpdateStatus.Continue:
920 case UpdateStatus.ErrorsOccurred:
921 throw(updatedArgs.Errors);
922 case UpdateStatus.SkipCurrentRow:
924 case UpdateStatus.SkipAllRemainingRows:
927 row.AcceptChanges ();
931 if (ContinueUpdateOnError)
932 row.RowError = e.Message;// do somthing with the error
938 if (reader != null && !reader.IsClosed)
946 public int Update (DataSet dataSet, string sourceTable)
948 MissingMappingAction mappingAction = MissingMappingAction;
949 if (mappingAction == MissingMappingAction.Ignore)
950 mappingAction = MissingMappingAction.Error;
951 DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTable, sourceTable, mappingAction);
953 DataTable dataTable = dataSet.Tables[tableMapping.DataSetTable];
954 if (dataTable == null)
955 throw new ArgumentException ("sourceTable");
957 return Update (dataTable, tableMapping);
960 #if ONLY_1_0 || ONLY_1_1
961 protected virtual void OnFillError (FillErrorEventArgs value)
963 if (FillError != null)
964 FillError (this, value);
968 protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
969 protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
971 #endregion // Methods