Use ExecuteReader instead of ExecuteNonQuery. We need to use the CommandBehavior...
[mono.git] / mcs / class / System.Data / System.Data.Common / DbDataAdapter.cs
1 //
2 // System.Data.Common.DbDataAdapter.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Tim Coleman (tim@timcoleman.com)
7 //
8 // (C) Ximian, Inc
9 // Copyright (C) Tim Coleman, 2002-2003
10 //
11
12 using System;
13 using System.Collections;
14 using System.ComponentModel;
15 using System.Data;
16 using System.Runtime.InteropServices;
17
18 namespace System.Data.Common {
19         public abstract class DbDataAdapter : DataAdapter, ICloneable
20         {
21                 #region Fields
22
23                 public const string DefaultSourceTableName = "Table";
24                 const string DefaultSourceColumnName = "Column";
25
26                 #endregion // Fields
27                 
28                 #region Constructors
29
30                 protected DbDataAdapter() 
31                 {
32                 }
33
34                 #endregion // Fields
35
36                 #region Properties
37
38 #if NET_1_2
39                 [MonoTODO]
40                 protected virtual IDbConnection BaseConnection {
41                         get { throw new NotImplementedException (); }
42                         set { throw new NotImplementedException (); }
43                 }
44
45                 public IDbConnection Connection { 
46                         get { return BaseConnection; }
47                         set { BaseConnection = value; }
48                 }
49 #endif
50
51                 IDbCommand DeleteCommand {
52                         get { return ((IDbDataAdapter) this).DeleteCommand; }
53                 }
54
55 #if NET_1_2
56                 protected internal CommandBehavior FillCommandBehavior {
57                         get { throw new NotImplementedException (); }
58                         set { throw new NotImplementedException (); }
59                 }
60 #endif
61
62                 IDbCommand InsertCommand {
63                         get { return ((IDbDataAdapter) this).InsertCommand; }
64                 }
65
66 #if NET_1_2
67                 [MonoTODO]
68                 protected virtual IDbCommand this [[Optional] StatementType statementType] {
69                         get { throw new NotImplementedException (); }
70                         set { throw new NotImplementedException (); }
71                 }
72
73                 protected virtual DbProviderFactory ProviderFactory {
74                         get { throw new NotImplementedException (); }
75                 }
76 #endif
77
78                 IDbCommand SelectCommand {
79                         get { return ((IDbDataAdapter) this).SelectCommand; }
80                 }
81
82 #if NET_1_2
83                 [MonoTODO]
84                 public IDbTransaction Transaction {
85                         get { throw new NotImplementedException (); }
86                         set { throw new NotImplementedException (); }
87                 }
88
89                 [MonoTODO]
90                 public int UpdateBatchSize {
91                         get { throw new NotImplementedException (); }
92                         set { throw new NotImplementedException (); }
93                 }
94 #endif
95
96                 IDbCommand UpdateCommand {
97                         get { return ((IDbDataAdapter) this).UpdateCommand; }
98                 }
99
100                 #endregion // Properties
101                 
102                 #region Events
103
104 #if ONLY_1_0 || ONLY_1_1
105
106                 [DataCategory ("Fill")]
107                 [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
108                 public event FillErrorEventHandler FillError;
109
110 #endif
111                 #endregion // Events
112
113                 #region Methods
114
115 #if NET_1_2
116                 [MonoTODO]
117                 public virtual void BeginInit ()
118                 {
119                         throw new NotImplementedException ();
120                 }
121 #endif
122
123                 protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
124                 protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
125
126                 private FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e)
127                 {
128                         FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values);
129                         args.Errors = e;
130                         args.Continue = false;
131                         return args;
132                 }
133
134                 protected override void Dispose (bool disposing)
135                 {
136                         if (disposing) {
137                                 IDbDataAdapter da = (IDbDataAdapter) this;
138                                 if (da.SelectCommand != null) {
139                                         da.SelectCommand.Dispose();
140                                         da.SelectCommand = null;
141                                 }
142                                 if (da.InsertCommand != null) {
143                                         da.InsertCommand.Dispose();
144                                         da.InsertCommand = null;
145                                 }
146                                 if (da.UpdateCommand != null) {
147                                         da.UpdateCommand.Dispose();
148                                         da.UpdateCommand = null;
149                                 }
150                                 if (da.DeleteCommand != null) {
151                                         da.DeleteCommand.Dispose();
152                                         da.DeleteCommand = null;
153                                 }
154                         }
155                 }
156
157 #if NET_1_2
158                 [MonoTODO]
159                 public virtual void EndInit ()
160                 {
161                         throw new NotImplementedException ();
162                 }
163 #endif
164
165                 public override int Fill (DataSet dataSet)
166                 {
167                         return Fill (dataSet, 0, 0, DefaultSourceTableName, SelectCommand, CommandBehavior.Default);
168                 }
169
170                 public int Fill (DataTable dataTable) 
171                 {
172                         if (dataTable == null)
173                                 throw new NullReferenceException ();
174
175                         return Fill (dataTable, SelectCommand, CommandBehavior.Default);
176                 }
177
178                 public int Fill (DataSet dataSet, string srcTable) 
179                 {
180                         return Fill (dataSet, 0, 0, srcTable, SelectCommand, CommandBehavior.Default);
181                 }
182
183 #if NET_1_2
184                 protected override int Fill (DataTable dataTable, IDataReader dataReader) 
185 #else
186                 protected virtual int Fill (DataTable dataTable, IDataReader dataReader) 
187 #endif
188                 {
189                         int count = 0;
190                         bool doContinue = true;
191
192                         if (dataReader.FieldCount == 0) {
193                                 dataReader.Close ();
194                                 return 0;
195                         }
196                         
197                         try
198                         {
199                                 object[] itemArray = new object [dataReader.FieldCount];
200                                 string tableName = SetupSchema (SchemaType.Mapped, dataTable.TableName);
201                                 if (tableName != null)
202                                 {
203                                         dataTable.TableName = tableName;
204                                         Hashtable mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
205
206                                         while (doContinue && dataReader.Read ()) 
207                                         {
208                                                 // we get the values from the datareader
209                                                 dataReader.GetValues (itemArray);
210
211                                                 // we only need the values that has a mapping to the table.
212                                                 object[] tableArray = new object[mapping.Count];
213                                                 for (int i = 0; i < tableArray.Length; i++)
214                                                         tableArray[i] = mapping[i]; // get the value for each column
215
216                                                 try 
217                                                 {
218                                                         dataTable.BeginLoadData ();
219                                                         dataTable.LoadDataRow (itemArray, AcceptChangesDuringFill);
220                                                         dataTable.EndLoadData ();
221                                                         count += 1;
222                                                 }
223                                                 catch (Exception e) 
224                                                 {
225                                                         FillErrorEventArgs args = CreateFillErrorEvent (dataTable, itemArray, e);
226                                                         OnFillError (args);
227                                                         doContinue = args.Continue;
228                                                 }
229                                         }
230                                 }
231                         }
232                         finally
233                         {
234                                 dataReader.Close ();
235                         }
236
237                         return count;
238                 }
239
240                 protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior) 
241                 {
242                         CommandBehavior commandBehavior = behavior;
243                         // first see that the connection is not close.
244                         if (command.Connection.State == ConnectionState.Closed) 
245                         {
246                                 command.Connection.Open ();
247                                 commandBehavior |= CommandBehavior.CloseConnection;
248                         }
249                         return Fill (dataTable, command.ExecuteReader (commandBehavior));
250                 }
251
252 #if NET_1_2
253                 [MonoTODO]
254                 public int Fill (int startRecord, int maxRecords, DataTable[] dataTables)
255                 {
256                         throw new NotImplementedException ();
257                 }
258 #endif
259
260                 public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable) 
261                 {
262                         return this.Fill (dataSet, startRecord, maxRecords, srcTable, SelectCommand, CommandBehavior.Default);
263                 }
264
265 #if NET_1_2
266                 [MonoTODO]
267                 protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
268                 {
269                         throw new NotImplementedException ();
270                 }
271 #endif
272
273 #if NET_1_2
274                 protected override int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords) 
275 #else
276                 protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords) 
277 #endif
278                 {
279                         if (startRecord < 0)
280                                 throw new ArgumentException ("The startRecord parameter was less than 0.");
281                         if (maxRecords < 0)
282                                 throw new ArgumentException ("The maxRecords parameter was less than 0.");
283
284                         if (dataReader.FieldCount == 0) {
285                                 dataReader.Close ();
286                                 return 0;
287                         }
288
289                         DataTable dataTable;
290                         int resultIndex = 0;
291                         int count = 0;
292                         bool doContinue = true;
293                         
294                         try
295                         {
296                                 string tableName = srcTable;
297                                 object[] itemArray;
298
299                                 do 
300                                 {
301                                         tableName = SetupSchema (SchemaType.Mapped, tableName);
302                                         if (tableName != null)
303                                         {
304                                                 // check if the table exists in the dataset
305                                                 if (dataSet.Tables.Contains (tableName)) 
306                                                         // get the table from the dataset
307                                                         dataTable = dataSet.Tables [tableName];
308                                                 else
309                                                 {
310                                                         dataTable = new DataTable(tableName);
311                                                         dataSet.Tables.Add (dataTable);
312                                                 }
313                                                 Hashtable mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
314
315                                                 for (int i = 0; i < startRecord; i += 1)
316                                                         dataReader.Read ();
317                                                 
318                                                 itemArray = new object [dataReader.FieldCount];
319
320                                                 while (doContinue && dataReader.Read () && !(maxRecords > 0 && count >= maxRecords)) 
321                                                 {
322                                                         // we get the values from the datareader
323                                                         dataReader.GetValues (itemArray);
324                                                         
325                                                         // we only need the values that has a mapping to the table.
326                                                         object[] tableArray = new object[mapping.Count];
327                                                         for (int i = 0; i < tableArray.Length; i++)
328                                                                 tableArray[i] = itemArray[(int)mapping[i]]; // get the value for each column
329                                                         
330                                                         try 
331                                                         {
332                                                                 dataTable.BeginLoadData ();
333                                                                 //dataTable.LoadDataRow (itemArray, AcceptChangesDuringFill);
334                                                                 dataTable.LoadDataRow (tableArray, AcceptChangesDuringFill);
335                                                                 dataTable.EndLoadData ();
336                                                                 count += 1;
337                                                         }
338                                                         catch (Exception e) 
339                                                         {
340                                                                 FillErrorEventArgs args = CreateFillErrorEvent (dataTable, itemArray, e);
341                                                                 OnFillError (args);
342                                                                 doContinue = args.Continue;
343                                                         }
344                                                 }
345
346                                                 tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
347
348                                                 startRecord = 0;
349                                                 maxRecords = 0;
350                                         }
351
352                                 } while (doContinue && dataReader.NextResult ());
353                         }
354                         finally
355                         {
356                                 dataReader.Close ();
357                         }
358
359                         return count;
360                 }
361
362                 
363                 protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior) 
364                 {
365                         if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
366                             behavior |= CommandBehavior.KeyInfo;
367                         CommandBehavior commandBehavior = behavior;
368                         if (command.Connection.State == ConnectionState.Closed) {
369                                 command.Connection.Open ();
370                                 commandBehavior |= CommandBehavior.CloseConnection;
371                         }
372                         return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
373                 }
374
375                 public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType) 
376                 {
377                         return FillSchema (dataSet, schemaType, SelectCommand, DefaultSourceTableName, CommandBehavior.Default);
378                 }
379
380                 public DataTable FillSchema (DataTable dataTable, SchemaType schemaType) 
381                 {
382                         return FillSchema (dataTable, schemaType, SelectCommand, CommandBehavior.Default);
383                 }
384
385                 public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable) 
386                 {
387                         return FillSchema (dataSet, schemaType, SelectCommand, srcTable, CommandBehavior.Default);
388                 }
389
390                 [MonoTODO ("Verify")]
391                 protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior) 
392                 {
393                         behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
394                         if (command.Connection.State == ConnectionState.Closed) {
395                                 command.Connection.Open ();
396                                 behavior |= CommandBehavior.CloseConnection;
397                         }
398
399                         IDataReader reader = command.ExecuteReader (behavior);
400                         try
401                         {
402                                 string tableName =  SetupSchema (schemaType, dataTable.TableName);
403                                 if (tableName != null)
404                                 {
405                                         BuildSchema (reader, dataTable, schemaType);
406                                 }
407                         }
408                         finally
409                         {
410                                 reader.Close ();
411                         }
412                         return dataTable;
413                 }
414
415                 [MonoTODO ("Verify")]
416                 protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior) 
417                 {
418                         behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
419                         if (command.Connection.State == ConnectionState.Closed) {
420                                 command.Connection.Open ();
421                                 behavior |= CommandBehavior.CloseConnection;
422                         }
423
424                         IDataReader reader = command.ExecuteReader (behavior);
425                         ArrayList output = new ArrayList ();
426                         string tableName = srcTable;
427                         int index = 0;
428                         DataTable table;
429                         try
430                         {
431                                 tableName = SetupSchema (schemaType, tableName);
432                                 if (tableName != null)
433                                 {
434                                         if (dataSet.Tables.Contains (tableName))
435                                                 table = dataSet.Tables [tableName];     
436                                         else
437                                         {
438                                                 table = new DataTable(tableName);
439                                                 dataSet.Tables.Add (table);
440                                         }
441                                         BuildSchema (reader, table, schemaType);
442                                         output.Add (table);
443                                         tableName = String.Format ("{0}{1}", srcTable, ++index);
444                                 }
445                         }
446                         finally
447                         {
448                                 reader.Close ();
449                         }
450                         return (DataTable[]) output.ToArray (typeof (DataTable));
451                 }
452
453 #if NET_1_2
454                 [MonoTODO]
455                 public DataSet GetDataSet ()
456                 {
457                         throw new NotImplementedException ();
458                 }
459
460                 [MonoTODO]
461                 public DataTable GetDataTable ()
462                 {
463                         throw new NotImplementedException ();
464                 }
465 #endif
466
467                 private string SetupSchema (SchemaType schemaType, string sourceTableName)
468                 {
469                         DataTableMapping tableMapping = null;
470
471                         if (schemaType == SchemaType.Mapped) 
472                         {
473                                 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, sourceTableName, MissingMappingAction);
474
475                                 if (tableMapping != null)
476                                         return tableMapping.DataSetTable;
477                                 return null;
478                         }
479                         else
480                                 return sourceTableName;
481                 }
482
483                 [EditorBrowsable (EditorBrowsableState.Advanced)]
484                 public override IDataParameter[] GetFillParameters () 
485                 {
486                         IDataParameter[] parameters = new IDataParameter[SelectCommand.Parameters.Count];
487                         SelectCommand.Parameters.CopyTo (parameters, 0);
488                         return parameters;
489                 }
490                 
491                 // this method bulds the schema for a given datatable
492                 // returns a hashtable that his keys are the ordinal of the datatable columns, and his values
493                 // are the indexes of the source columns in the data reader.
494                 // each column in the datatable has a mapping to a specific column in the datareader
495                 // the hashtable represents this match.
496                 [MonoTODO ("Test")]
497                 private Hashtable BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType)
498                 {
499                         int readerIndex = 0;
500                         Hashtable mapping = new Hashtable(); // hashing the reader indexes with the datatable indexes
501                         ArrayList primaryKey = new ArrayList ();
502                         ArrayList sourceColumns = new ArrayList ();
503
504                         foreach (DataRow schemaRow in reader.GetSchemaTable ().Rows) {
505                                 // generate a unique column name in the source table.
506                                 string sourceColumnName;
507                                 if (schemaRow ["ColumnName"].Equals (DBNull.Value))
508                                         sourceColumnName = DefaultSourceColumnName;
509                                 else 
510                                         sourceColumnName = (string) schemaRow ["ColumnName"];
511
512                                 string realSourceColumnName = sourceColumnName;
513
514                                 for (int i = 1; sourceColumns.Contains (realSourceColumnName); i += 1) 
515                                         realSourceColumnName = String.Format ("{0}{1}", sourceColumnName, i);
516                                 sourceColumns.Add(realSourceColumnName);
517
518                                 // generate DataSetColumnName from DataTableMapping, if any
519                                 string dsColumnName = realSourceColumnName;
520                                 DataTableMapping tableMapping = null;
521                                 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, table.TableName, table.TableName, MissingMappingAction); 
522                                 if (tableMapping != null) 
523                                 {
524                                         
525                                         table.TableName = tableMapping.DataSetTable;
526                                         // check to see if the column mapping exists
527                                         DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, MissingMappingAction);
528                                         if (columnMapping != null)
529                                         {
530                                                 DataColumn col =
531                                                         columnMapping.GetDataColumnBySchemaAction(
532                                                         table ,
533                                                         (Type)schemaRow["DataType"],
534                                                         MissingSchemaAction);
535
536                                                 if (col != null)
537                                                 {
538                                                         // if the column is not in the table - add it.
539                                                         if (table.Columns.IndexOf(col) == -1)
540                                                         {
541                                                                 if (MissingSchemaAction == MissingSchemaAction.Add || MissingSchemaAction == MissingSchemaAction.AddWithKey)
542                                                                         table.Columns.Add(col);
543                                                         }
544
545                                                         if (!schemaRow["IsKey"].Equals (DBNull.Value))
546                                                                 if ((bool) (schemaRow ["IsKey"]))
547                                                                         primaryKey.Add (col);
548                                                         
549                                                         // add the ordinal of the column as a key and the index of the column in the datareader as a value.
550                                                         mapping.Add(col.Ordinal, readerIndex);
551                                                 }
552                                         }
553                                 }
554                                 readerIndex++;
555                         }
556                         if (primaryKey.Count > 0)
557                                 table.PrimaryKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn)));
558
559                         return mapping;
560                 }
561
562                 [MonoTODO]
563                 object ICloneable.Clone ()
564                 {
565                         throw new NotImplementedException ();
566                 }
567
568                 [MonoTODO]
569                 public int Update (DataRow[] dataRows) 
570                 {
571                         if (dataRows == null)\r
572                                 throw new ArgumentNullException("dataRows");\r
573                         \r
574                         if (dataRows.Length == 0)\r
575                                 return 0;\r
576 \r
577                         if (dataRows[0] == null)\r
578                                 throw new ArgumentException("dataRows[0].");\r
579 \r
580                         DataTable table = dataRows[0].Table;\r
581                         if (table == null)\r
582                                 throw new ArgumentException("table is null reference.");\r
583                         \r
584                         // all rows must be in the same table\r
585                         for (int i = 0; i < dataRows.Length; i++)\r
586                         {\r
587                                 if (dataRows[i] == null)\r
588                                         throw new ArgumentException("dataRows[" + i + "].");\r
589                                 if (dataRows[i].Table != table)\r
590                                         throw new ArgumentException(\r
591                                                 " DataRow["\r
592                                                 + i\r
593                                                 + "] is from a different DataTable than DataRow[0].");\r
594                         }\r
595                         
596                         // get table mapping for this rows
597                         DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);\r
598                         if (tableMapping == null)\r
599                         {\r
600                                 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(\r
601                                         TableMappings,\r
602                                         table.TableName,\r
603                                         table.TableName,\r
604                                         MissingMappingAction);\r
605                                 if (tableMapping == null)\r
606                                         tableMapping =\r
607                                                 new DataTableMapping(\r
608                                                 table.TableName,\r
609                                                 table.TableName);\r
610                         }
611
612                         DataRow[] copy = new DataRow [dataRows.Length];
613                         Array.Copy(dataRows, 0, copy, 0, dataRows.Length);
614                         return Update(copy, tableMapping);
615                 }
616
617                 public override int Update (DataSet dataSet) 
618                 {
619                         return Update (dataSet, DefaultSourceTableName);
620                 }
621
622                 public int Update (DataTable dataTable) 
623                 {
624                         int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
625                         if (index < 0)
626                                 throw new ArgumentException ();
627                         return Update (dataTable, TableMappings [index]);
628                 }
629
630                 private int Update (DataTable dataTable, DataTableMapping tableMapping)
631                 {
632                         DataRow[] rows = new DataRow [dataTable.Rows.Count];
633                         dataTable.Rows.CopyTo (rows, 0);
634                         return Update (rows, tableMapping);
635                 }
636
637                 [MonoTODO]
638                 protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping) 
639                 {
640                         int updateCount = 0;
641
642                         foreach (DataRow row in dataRows) {
643                                 StatementType statementType = StatementType.Update;
644                                 IDbCommand command = null;
645                                 string commandName = String.Empty;
646                                 bool useCommandBuilder = false;
647
648                                 switch (row.RowState) {
649                                 case DataRowState.Added:
650                                         statementType = StatementType.Insert;
651                                         command = InsertCommand;
652                                         commandName = "Insert";
653                                         break;
654                                 case DataRowState.Deleted:
655                                         statementType = StatementType.Delete;
656                                         command = DeleteCommand;
657                                         commandName = "Delete";
658                                         break;
659                                 case DataRowState.Modified:
660                                         statementType = StatementType.Update;
661                                         command = UpdateCommand;
662                                         commandName = "Update";
663                                         break;
664                                 case DataRowState.Unchanged:
665                                         continue;
666                                 case DataRowState.Detached:
667                                         throw new NotImplementedException ();
668                                 }
669
670                                 if (command == null)
671                                         useCommandBuilder = true;
672
673                                 RowUpdatingEventArgs args = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
674                                 OnRowUpdating (args);
675
676                                 if (args.Status == UpdateStatus.ErrorsOccurred)
677                                         throw (args.Errors);
678
679                                 if (command == null && args.Command != null)
680                                         command = args.Command;
681                                 else if (command == null)
682                                         throw new InvalidOperationException (String.Format ("Update requires a valid {0}Command when passed a DataRow collection with modified rows.", commandName));
683
684                                 if (!useCommandBuilder) {
685                                         DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
686
687                                         foreach (IDataParameter parameter in command.Parameters) {
688                                                 string dsColumnName = parameter.SourceColumn;
689                                                 if (columnMappings.Contains(parameter.SourceColumn))
690                                                         dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
691                                                 DataRowVersion rowVersion = DataRowVersion.Default;
692
693                                                 // Parameter version is ignored for non-update commands
694                                                 if (statementType == StatementType.Update) 
695                                                         rowVersion = parameter.SourceVersion;
696                                                 if (statementType == StatementType.Delete) 
697                                                         rowVersion = DataRowVersion.Original;
698
699                                                 parameter.Value = row [dsColumnName, rowVersion];
700                                         }
701                                 }
702                                 
703                                 CommandBehavior commandBehavior = CommandBehavior.Default;
704                                 if (command.Connection.State == ConnectionState.Closed) 
705                                 {
706                                         command.Connection.Open ();
707                                         commandBehavior |= CommandBehavior.CloseConnection;
708                                 }
709                                 
710                                 IDataReader reader = null;
711                                 try
712                                 {
713                                         // use ExecuteReader because we want to use the commandbehavior parameter.
714                                         // so the connection will be closed if needed.
715                                         reader = command.ExecuteReader (commandBehavior);
716                                         int tmp = reader.RecordsAffected;
717                                         // if the execute does not effect any rows we throw an exception.
718                                         if (tmp == 0)
719                                                 throw new DBConcurrencyException("Concurrency violation: the " + commandName +"Command affected 0 records.");
720                                         updateCount += tmp;
721                                         OnRowUpdated (CreateRowUpdatedEvent (row, command, statementType, tableMapping));
722                                         row.AcceptChanges ();
723                                 }
724                                 catch (Exception e)
725                                 {
726                                         if (ContinueUpdateOnError)
727                                                 row.RowError = e.Message;// do somthing with the error
728                                         else
729                                                 throw e;
730                                 }
731                                 finally
732                                 {
733                                         if (reader != null)
734                                                 reader.Close ();
735                                 }
736                         }
737                         
738                         return updateCount;
739                 }
740
741                 public int Update (DataSet dataSet, string sourceTable) 
742                 {
743                         MissingMappingAction mappingAction = MissingMappingAction;
744                         if (mappingAction == MissingMappingAction.Ignore)
745                                 mappingAction = MissingMappingAction.Error;
746                         DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTable, sourceTable, mappingAction);
747
748                         DataTable dataTable = dataSet.Tables[tableMapping.DataSetTable];
749                         if (dataTable == null)
750                             throw new ArgumentException ("sourceTable");
751
752                         return Update (dataTable, tableMapping);
753                 }
754
755 #if ONLY_1_0 || ONLY_1_1
756                 protected virtual void OnFillError (FillErrorEventArgs value) 
757                 {
758                         if (FillError != null)
759                                 FillError (this, value);
760                 }
761 #endif
762
763                 protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
764                 protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
765                 
766                 #endregion // Methods
767         }
768 }