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 {
44 public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
46 public abstract class DbDataAdapter : DataAdapter, ICloneable
51 public const string DefaultSourceTableName = "Table";
52 const string DefaultSourceColumnName = "Column";
58 protected DbDataAdapter()
63 protected DbDataAdapter(DbDataAdapter adapter) : base(adapter)
72 protected internal CommandBehavior FillCommandBehavior {
73 get { throw new NotImplementedException (); }
74 set { throw new NotImplementedException (); }
81 IDbCommand IDbDataAdapter.SelectCommand {
82 get { return ((IDbDataAdapter) this).SelectCommand; }
83 set { throw new NotImplementedException(); }
87 IDbCommand IDbDataAdapter.UpdateCommand{
88 get { return ((IDbDataAdapter) this).UpdateCommand; }
89 set { throw new NotImplementedException(); }
93 IDbCommand IDbDataAdapter.DeleteCommand{
94 get { return ((IDbDataAdapter) this).DeleteCommand; }
95 set { throw new NotImplementedException(); }
99 IDbCommand IDbDataAdapter.InsertCommand{
100 get { return ((IDbDataAdapter) this).InsertCommand; }
101 set { throw new NotImplementedException(); }
106 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
107 public DbCommand SelectCommand {
108 get { return (DbCommand) ((IDbDataAdapter) this).SelectCommand; }
109 set { throw new NotImplementedException(); }
114 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
115 public DbCommand DeleteCommand {
116 get { return (DbCommand) ((IDbDataAdapter) this).DeleteCommand; }
117 set { throw new NotImplementedException(); }
122 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
123 public DbCommand InsertCommand {
124 get { return (DbCommand) ((IDbDataAdapter) this).InsertCommand; }
125 set { throw new NotImplementedException(); }
130 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
131 public DbCommand UpdateCommand {
132 get { return (DbCommand) ((IDbDataAdapter) this).UpdateCommand; }
133 set { throw new NotImplementedException(); }
138 public int UpdateBatchSize {
139 get { throw new NotImplementedException (); }
140 set { throw new NotImplementedException (); }
143 IDbCommand SelectCommand {
144 get { return ((IDbDataAdapter) this).SelectCommand; }
147 IDbCommand UpdateCommand {
148 get { return ((IDbDataAdapter) this).UpdateCommand; }
151 IDbCommand DeleteCommand {
152 get { return ((IDbDataAdapter) this).DeleteCommand; }
155 IDbCommand InsertCommand {
156 get { return ((IDbDataAdapter) this).InsertCommand; }
160 #endregion // Properties
164 #if ONLY_1_0 || ONLY_1_1
166 [DataCategory ("Fill")]
167 [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
168 public event FillErrorEventHandler FillError;
176 protected virtual RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
177 StatementType statementType,
178 DataTableMapping tableMapping)
180 return new RowUpdatedEventArgs (dataRow, command, statementType, tableMapping);
183 protected virtual RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
184 StatementType statementType,
185 DataTableMapping tableMapping)
187 return new RowUpdatingEventArgs (dataRow, command, statementType, tableMapping);
191 protected virtual void OnRowUpdated (RowUpdatedEventArgs value)
196 protected virtual void OnRowUpdating (RowUpdatingEventArgs value)
200 protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
201 StatementType statementType,
202 DataTableMapping tableMapping);
203 protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
204 StatementType statementType,
205 DataTableMapping tableMapping);
207 protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
208 protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
210 private FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e)
212 FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values);
214 args.Continue = false;
218 protected override void Dispose (bool disposing)
221 IDbDataAdapter da = (IDbDataAdapter) this;
222 if (da.SelectCommand != null) {
223 da.SelectCommand.Dispose();
224 da.SelectCommand = null;
226 if (da.InsertCommand != null) {
227 da.InsertCommand.Dispose();
228 da.InsertCommand = null;
230 if (da.UpdateCommand != null) {
231 da.UpdateCommand.Dispose();
232 da.UpdateCommand = null;
234 if (da.DeleteCommand != null) {
235 da.DeleteCommand.Dispose();
236 da.DeleteCommand = null;
241 public override int Fill (DataSet dataSet)
243 return Fill (dataSet, 0, 0, DefaultSourceTableName, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
246 public int Fill (DataTable dataTable)
248 if (dataTable == null)
249 throw new ArgumentNullException ("DataTable");
251 return Fill (dataTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
254 public int Fill (DataSet dataSet, string srcTable)
256 return Fill (dataSet, 0, 0, srcTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
260 protected override int Fill (DataTable dataTable, IDataReader dataReader)
262 protected virtual int Fill (DataTable dataTable, IDataReader dataReader)
265 if (dataReader.FieldCount == 0) {
273 string tableName = SetupSchema (SchemaType.Mapped, dataTable.TableName);
274 if (tableName != null) {
275 dataTable.TableName = tableName;
276 FillTable (dataTable, dataReader, 0, 0, ref count);
285 protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
287 CommandBehavior commandBehavior = behavior;
289 // first see that the connection is not close.
290 if (command.Connection.State == ConnectionState.Closed)
292 command.Connection.Open ();
293 commandBehavior |= CommandBehavior.CloseConnection;
295 return Fill (dataTable, command.ExecuteReader (commandBehavior));
300 public int Fill (int startRecord, int maxRecords, DataTable[] dataTables)
302 throw new NotImplementedException ();
306 public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
308 return this.Fill (dataSet, startRecord, maxRecords, srcTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
313 protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
315 throw new NotImplementedException ();
320 protected override int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
322 protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
326 throw new ArgumentNullException ("DataSet");
329 throw new ArgumentException ("The startRecord parameter was less than 0.");
331 throw new ArgumentException ("The maxRecords parameter was less than 0.");
333 DataTable dataTable = null;
338 string tableName = srcTable;
340 // Non-resultset queries like insert, delete or update aren't processed.
341 if (dataReader.FieldCount != -1)
343 tableName = SetupSchema (SchemaType.Mapped, tableName);
344 if (tableName != null) {
346 // check if the table exists in the dataset
347 if (dataSet.Tables.Contains (tableName))
348 // get the table from the dataset
349 dataTable = dataSet.Tables [tableName];
351 // Do not create schema if MissingSchemAction is set to Ignore
352 if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
354 dataTable = dataSet.Tables.Add (tableName);
357 if (!FillTable (dataTable, dataReader, startRecord, maxRecords, ref count)) {
361 tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
367 } while (dataReader.NextResult ());
376 protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
378 if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
379 behavior |= CommandBehavior.KeyInfo;
380 CommandBehavior commandBehavior = behavior;
382 if (command.Connection.State == ConnectionState.Closed) {
383 command.Connection.Open ();
384 commandBehavior |= CommandBehavior.CloseConnection;
386 return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
389 private bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter)
391 if (dataReader.FieldCount == 0)
394 int counterStart = counter;
396 int[] mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
398 int[] sortedMapping = new int[mapping.Length];
399 int length = sortedMapping.Length;
400 for(int i=0; i < sortedMapping.Length; i++) {
402 sortedMapping[mapping[i]] = i;
404 sortedMapping[--length] = i;
407 for (int i = 0; i < startRecord; i++) {
411 dataTable.BeginLoadData ();
412 while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) {
414 dataTable.LoadDataRow (dataReader, sortedMapping, length, AcceptChangesDuringFill);
417 catch (Exception e) {
418 object[] readerArray = new object[dataReader.FieldCount];
419 object[] tableArray = new object[mapping.Length];
420 // we get the values from the datareader
421 dataReader.GetValues (readerArray);
422 // copy from datareader columns to table columns according to given mapping
423 for (int i = 0; i < mapping.Length; i++) {
424 if (mapping[i] >= 0) {
425 tableArray[i] = readerArray[mapping[i]];
428 FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e);
431 // if args.Continue is not set to true or if a handler is not set, rethrow the error..
436 dataTable.EndLoadData ();
442 /// Fills the given datatable using values from reader. if a value
443 /// for a column is null, that will be filled with default value.
445 /// <returns>No. of rows affected </returns>
446 internal static int FillFromReader (DataTable table,
451 LoadOption loadOption
454 if (reader.FieldCount == 0)
457 for (int i = 0; i < start; i++)
461 object [] values = new object [mapping.Length];
462 while (reader.Read () &&
463 (length == 0 || counter < length)) {
465 for (int i = 0 ; i < mapping.Length; i++)
466 values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
468 table.BeginLoadData ();
469 table.LoadDataRow (values, loadOption);
470 table.EndLoadData ();
478 public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType)
480 return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, DefaultSourceTableName, CommandBehavior.Default);
483 public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
485 return FillSchema (dataTable, schemaType, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
488 public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
490 return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, srcTable, CommandBehavior.Default);
493 [MonoTODO ("Verify")]
494 protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
496 if (dataTable == null)
497 throw new ArgumentNullException ("DataTable");
499 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
500 if (command.Connection.State == ConnectionState.Closed) {
501 command.Connection.Open ();
502 behavior |= CommandBehavior.CloseConnection;
505 IDataReader reader = command.ExecuteReader (behavior);
508 string tableName = SetupSchema (schemaType, dataTable.TableName);
509 if (tableName != null)
511 // FillSchema should add the KeyInfo unless MissingSchemaAction
512 // is set to Ignore or Error.
513 MissingSchemaAction schemaAction = MissingSchemaAction;
514 if (!(schemaAction == MissingSchemaAction.Ignore ||
515 schemaAction == MissingSchemaAction.Error))
516 schemaAction = MissingSchemaAction.AddWithKey;
518 BuildSchema (reader, dataTable, schemaType, schemaAction,
519 MissingMappingAction, TableMappings);
529 [MonoTODO ("Verify")]
530 protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
533 throw new ArgumentNullException ("DataSet");
535 behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
536 if (command.Connection.State == ConnectionState.Closed) {
537 command.Connection.Open ();
538 behavior |= CommandBehavior.CloseConnection;
541 IDataReader reader = command.ExecuteReader (behavior);
542 ArrayList output = new ArrayList ();
543 string tableName = srcTable;
548 // FillSchema should add the KeyInfo unless MissingSchemaAction
549 // is set to Ignore or Error.
550 MissingSchemaAction schemaAction = MissingSchemaAction;
551 if (!(MissingSchemaAction == MissingSchemaAction.Ignore ||
552 MissingSchemaAction == MissingSchemaAction.Error))
553 schemaAction = MissingSchemaAction.AddWithKey;
556 tableName = SetupSchema (schemaType, tableName);
557 if (tableName != null)
559 if (dataSet.Tables.Contains (tableName))
560 table = dataSet.Tables [tableName];
563 // Do not create schema if MissingSchemAction is set to Ignore
564 if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
566 table = dataSet.Tables.Add (tableName);
569 BuildSchema (reader, table, schemaType, schemaAction,
570 MissingMappingAction, TableMappings);
572 tableName = String.Format ("{0}{1}", srcTable, ++index);
574 }while (reader.NextResult ());
580 return (DataTable[]) output.ToArray (typeof (DataTable));
583 private string SetupSchema (SchemaType schemaType, string sourceTableName)
585 DataTableMapping tableMapping = null;
587 if (schemaType == SchemaType.Mapped)
589 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, sourceTableName, MissingMappingAction);
590 if (tableMapping != null)
591 return tableMapping.DataSetTable;
595 return sourceTableName;
598 [EditorBrowsable (EditorBrowsableState.Advanced)]
599 public override IDataParameter[] GetFillParameters ()
601 IDataParameter[] parameters = new IDataParameter[SelectCommand.Parameters.Count];
602 SelectCommand.Parameters.CopyTo (parameters, 0);
606 // this method builds the schema for a given datatable. it returns a int array with
607 // "array[ordinal of datatable column] == index of source column in data reader".
608 // each column in the datatable has a mapping to a specific column in the datareader,
609 // the int array represents this match.
611 private int[] BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType)
613 return BuildSchema (reader, table, schemaType, MissingSchemaAction,
614 MissingMappingAction, TableMappings);
618 /// Creates or Modifies the schema of the given DataTable based on the schema of
619 /// the reader and the arguments passed.
621 internal static int[] BuildSchema (IDataReader reader,
623 SchemaType schemaType,
624 MissingSchemaAction missingSchAction,
625 MissingMappingAction missingMapAction,
626 DataTableMappingCollection dtMapping
630 // FIXME : this fails if query has fewer columns than a table
631 int[] mapping = new int[table.Columns.Count]; // mapping the reader indexes to the datatable indexes
633 for(int i=0; i < mapping.Length; i++) {
637 ArrayList primaryKey = new ArrayList ();
638 ArrayList sourceColumns = new ArrayList ();
639 bool createPrimaryKey = true;
641 DataTable schemaTable = reader.GetSchemaTable ();
643 DataColumn ColumnNameCol = schemaTable.Columns["ColumnName"];
644 DataColumn DataTypeCol = schemaTable.Columns["DataType"];
645 DataColumn IsAutoIncrementCol = schemaTable.Columns["IsAutoIncrement"];
646 DataColumn AllowDBNullCol = schemaTable.Columns["AllowDBNull"];
647 DataColumn IsReadOnlyCol = schemaTable.Columns["IsReadOnly"];
648 DataColumn IsKeyCol = schemaTable.Columns["IsKey"];
649 DataColumn IsUniqueCol = schemaTable.Columns["IsUnique"];
650 DataColumn ColumnSizeCol = schemaTable.Columns["ColumnSize"];
652 foreach (DataRow schemaRow in schemaTable.Rows) {
653 // generate a unique column name in the source table.
654 string sourceColumnName;
655 string realSourceColumnName ;
656 if (ColumnNameCol == null || schemaRow.IsNull(ColumnNameCol) || (string)schemaRow [ColumnNameCol] == String.Empty) {
657 sourceColumnName = DefaultSourceColumnName;
658 realSourceColumnName = DefaultSourceColumnName + "1";
661 sourceColumnName = (string) schemaRow [ColumnNameCol];
662 realSourceColumnName = sourceColumnName;
665 for (int i = 1; sourceColumns.Contains (realSourceColumnName); i += 1)
666 realSourceColumnName = String.Format ("{0}{1}", sourceColumnName, i);
667 sourceColumns.Add(realSourceColumnName);
669 // generate DataSetColumnName from DataTableMapping, if any
670 string dsColumnName = realSourceColumnName;
671 DataTableMapping tableMapping = null;
673 //FIXME : The sourcetable name shud get passed as a parameter..
674 int index = dtMapping.IndexOfDataSetTable (table.TableName);
675 string srcTable = (index != -1 ? dtMapping[index].SourceTable : table.TableName);
676 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (dtMapping, srcTable, table.TableName, missingMapAction);
677 if (tableMapping != null)
679 table.TableName = tableMapping.DataSetTable;
680 // check to see if the column mapping exists
681 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction);
682 if (columnMapping != null)
684 Type columnType = (Type)schemaRow[DataTypeCol];
686 columnMapping.GetDataColumnBySchemaAction(
693 // if the column is not in the table - add it.
694 if (table.Columns.IndexOf(col) == -1)
696 if (missingSchAction == MissingSchemaAction.Add
697 || missingSchAction == MissingSchemaAction.AddWithKey)
698 table.Columns.Add(col);
700 int[] tmp = new int[mapping.Length + 1];
701 Array.Copy(mapping,0,tmp,0,col.Ordinal);
702 Array.Copy(mapping,col.Ordinal,tmp,col.Ordinal + 1,mapping.Length - col.Ordinal);
707 if (missingSchAction == MissingSchemaAction.AddWithKey) {
709 object value = (AllowDBNullCol != null) ? schemaRow[AllowDBNullCol] : null;
710 bool allowDBNull = value is bool ? (bool)value : true;
712 value = (IsKeyCol != null) ? schemaRow[IsKeyCol] : null;
713 bool isKey = value is bool ? (bool)value : false;
715 value = (IsAutoIncrementCol != null) ? schemaRow[IsAutoIncrementCol] : null;
716 bool isAutoIncrement = value is bool ? (bool)value : false;
718 value = (IsReadOnlyCol != null) ? schemaRow[IsReadOnlyCol] : null;
719 bool isReadOnly = value is bool ? (bool)value : false;
721 value = (IsUniqueCol != null) ? schemaRow[IsUniqueCol] : null;
722 bool isUnique = value is bool ? (bool)value : false;
724 col.AllowDBNull = allowDBNull;
725 // fill woth key info
726 if (isAutoIncrement && DataColumn.CanAutoIncrement(columnType)) {
727 col.AutoIncrement = true;
729 col.AllowDBNull = false;
732 if (columnType == DbTypes.TypeOfString) {
733 col.MaxLength = (ColumnSizeCol != null) ? (int)schemaRow[ColumnSizeCol] : 0;
739 if (!allowDBNull && (!isReadOnly || isKey))
740 col.AllowDBNull = false;
741 if (isUnique && !isKey && !columnType.IsArray) {
744 col.AllowDBNull = false;
747 // This might not be set by all DataProviders
748 bool isHidden = false;
749 if (schemaTable.Columns.Contains ("IsHidden")) {
750 value = schemaRow["IsHidden"];
751 isHidden = ((value is bool) ? (bool)value : false);
754 if (isKey && !isHidden) {
755 primaryKey.Add (col);
757 createPrimaryKey = false;
760 // add the ordinal of the column as a key and the index of the column in the datareader as a value.
761 mapping[col.Ordinal] = readerIndex++;
766 if (primaryKey.Count > 0) {
767 DataColumn[] colKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn)));
768 if (createPrimaryKey)
769 table.PrimaryKey = colKey;
771 UniqueConstraint uConstraint = new UniqueConstraint(colKey);
772 for (int i = 0; i < table.Constraints.Count; i++) {
773 if (table.Constraints[i].Equals(uConstraint)) {
779 if (uConstraint != null)
780 table.Constraints.Add(uConstraint);
787 object ICloneable.Clone ()
789 throw new NotImplementedException ();
793 public int Update (DataRow[] dataRows)
795 if (dataRows == null)
796 throw new ArgumentNullException("dataRows");
798 if (dataRows.Length == 0)
801 if (dataRows[0] == null)
802 throw new ArgumentException("dataRows[0].");
804 DataTable table = dataRows[0].Table;
806 throw new ArgumentException("table is null reference.");
808 // all rows must be in the same table
809 for (int i = 0; i < dataRows.Length; i++)
811 if (dataRows[i] == null)
812 throw new ArgumentException("dataRows[" + i + "].");
813 if (dataRows[i].Table != table)
814 throw new ArgumentException(
817 + "] is from a different DataTable than DataRow[0].");
820 // get table mapping for this rows
821 DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);
822 if (tableMapping == null)
824 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(
828 MissingMappingAction);
829 if (tableMapping != null) {
830 foreach (DataColumn col in table.Columns) {
831 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
833 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
834 if (columnMapping == null)
835 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
836 tableMapping.ColumnMappings.Add (columnMapping);
839 ArrayList cmc = new ArrayList ();
840 foreach (DataColumn col in table.Columns)
841 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
843 new DataTableMapping (
846 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
850 DataRow[] copy = table.NewRowArray(dataRows.Length);
851 Array.Copy(dataRows, 0, copy, 0, dataRows.Length);
852 return Update(copy, tableMapping);
855 public override int Update (DataSet dataSet)
857 return Update (dataSet, DefaultSourceTableName);
860 public int Update (DataTable dataTable)
863 int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
865 throw new ArgumentException ();
866 return Update (dataTable, TableMappings [index]);
868 DataTableMapping tableMapping = TableMappings.GetByDataSetTable (dataTable.TableName);
869 if (tableMapping == null)
871 tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (
875 MissingMappingAction);
876 if (tableMapping != null) {
877 foreach (DataColumn col in dataTable.Columns) {
878 if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
880 DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
881 if (columnMapping == null)
882 columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
883 tableMapping.ColumnMappings.Add (columnMapping);
886 ArrayList cmc = new ArrayList ();
887 foreach (DataColumn col in dataTable.Columns)
888 cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
890 new DataTableMapping (
893 cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
896 return Update (dataTable, tableMapping);
899 private int Update (DataTable dataTable, DataTableMapping tableMapping)
901 DataRow[] rows = dataTable.NewRowArray(dataTable.Rows.Count);
902 dataTable.Rows.CopyTo (rows, 0);
903 return Update (rows, tableMapping);
907 protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping)
910 foreach (DataRow row in dataRows) {
911 StatementType statementType = StatementType.Update;
912 IDbCommand command = null;
913 string commandName = String.Empty;
915 switch (row.RowState) {
916 case DataRowState.Added:
917 statementType = StatementType.Insert;
918 command = ((IDbDataAdapter) this).InsertCommand;
919 commandName = "Insert";
921 case DataRowState.Deleted:
922 statementType = StatementType.Delete;
923 command = ((IDbDataAdapter) this).DeleteCommand;
924 commandName = "Delete";
926 case DataRowState.Modified:
927 statementType = StatementType.Update;
928 command = ((IDbDataAdapter) this).UpdateCommand;
929 commandName = "Update";
931 case DataRowState.Unchanged:
932 case DataRowState.Detached:
936 RowUpdatingEventArgs argsUpdating = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
938 OnRowUpdating(argsUpdating);
939 switch(argsUpdating.Status) {
940 case UpdateStatus.Continue :
941 //continue in update operation
943 case UpdateStatus.ErrorsOccurred :
944 if (argsUpdating.Errors == null) {
945 argsUpdating.Errors = ExceptionHelper.RowUpdatedError();
947 row.RowError += argsUpdating.Errors.Message;
948 if (!ContinueUpdateOnError) {
949 throw argsUpdating.Errors;
952 case UpdateStatus.SkipAllRemainingRows :
954 case UpdateStatus.SkipCurrentRow :
958 throw ExceptionHelper.InvalidUpdateStatus(argsUpdating.Status);
960 command = argsUpdating.Command;
962 if (command != null) {
963 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
964 foreach (IDataParameter parameter in command.Parameters) {
965 if ((parameter.Direction & ParameterDirection.Input) != 0) {
966 string dsColumnName = parameter.SourceColumn;
967 if (columnMappings.Contains(parameter.SourceColumn))
968 dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
969 if (dsColumnName == null || dsColumnName.Length <= 0)
972 DataRowVersion rowVersion = parameter.SourceVersion;
973 // Parameter version is ignored for non-update commands
974 if (statementType == StatementType.Delete)
975 rowVersion = DataRowVersion.Original;
977 parameter.Value = row [dsColumnName, rowVersion];
982 catch (Exception e) {
983 argsUpdating.Errors = e;
984 argsUpdating.Status = UpdateStatus.ErrorsOccurred;
988 IDataReader reader = null;
990 if (command == null) {
991 throw ExceptionHelper.UpdateRequiresCommand(commandName);
994 CommandBehavior commandBehavior = CommandBehavior.Default;
995 if (command.Connection.State == ConnectionState.Closed) {
996 command.Connection.Open ();
997 commandBehavior |= CommandBehavior.CloseConnection;
1000 // use ExecuteReader because we want to use the commandbehavior parameter.
1001 // so the connection will be closed if needed.
1002 reader = command.ExecuteReader (commandBehavior);
1004 // update the current row, if the update command returns any resultset
1005 // ignore other than the first record.
1006 DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
1008 if (command.UpdatedRowSource == UpdateRowSource.Both ||
1009 command.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord) {
1010 if (reader.Read ()){
1011 DataTable retSchema = reader.GetSchemaTable ();
1012 foreach (DataRow dr in retSchema.Rows) {
1013 string columnName = dr ["ColumnName"].ToString ();
1014 string dstColumnName = columnName;
1015 if (columnMappings != null &&
1016 columnMappings.Contains(columnName))
1017 dstColumnName = columnMappings [dstColumnName].DataSetColumn;
1018 DataColumn dstColumn = row.Table.Columns [dstColumnName];
1019 if (dstColumn == null
1020 || (dstColumn.Expression != null
1021 && dstColumn.Expression.Length > 0))
1023 // info from : http://www.error-bank.com/microsoft.public.dotnet.framework.windowsforms.databinding/
1024 // _35_hcsyiv0dha.2328@tk2msftngp10.phx.gbl_Thread.aspx
1025 // disable readonly for non-expression columns.
1026 bool readOnlyState = dstColumn.ReadOnly;
1027 dstColumn.ReadOnly = false;
1029 row [dstColumnName] = reader [columnName];
1031 dstColumn.ReadOnly = readOnlyState;
1038 int tmp = reader.RecordsAffected; // records affected is valid only after closing reader
1039 // if the execute does not effect any rows we throw an exception.
1041 throw new DBConcurrencyException("Concurrency violation: the " +
1042 commandName +"Command affected 0 records.");
1045 if (command.UpdatedRowSource == UpdateRowSource.Both ||
1046 command.UpdatedRowSource == UpdateRowSource.OutputParameters) {
1047 // Update output parameters to row values
1048 foreach (IDataParameter parameter in command.Parameters) {
1049 if (parameter.Direction != ParameterDirection.InputOutput
1050 && parameter.Direction != ParameterDirection.Output
1051 && parameter.Direction != ParameterDirection.ReturnValue)
1054 string dsColumnName = parameter.SourceColumn;
1055 if (columnMappings != null &&
1056 columnMappings.Contains(parameter.SourceColumn))
1057 dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
1058 DataColumn dstColumn = row.Table.Columns [dsColumnName];
1059 if (dstColumn == null
1060 || (dstColumn.Expression != null
1061 && dstColumn.Expression.Length > 0))
1063 bool readOnlyState = dstColumn.ReadOnly;
1064 dstColumn.ReadOnly = false;
1066 row [dsColumnName] = parameter.Value;
1068 dstColumn.ReadOnly = readOnlyState;
1074 RowUpdatedEventArgs updatedArgs = CreateRowUpdatedEvent(row, command, statementType, tableMapping);
1075 OnRowUpdated(updatedArgs);
1076 switch(updatedArgs.Status) {
1077 case UpdateStatus.Continue:
1079 case UpdateStatus.ErrorsOccurred:
1080 if (updatedArgs.Errors == null) {
1081 updatedArgs.Errors = ExceptionHelper.RowUpdatedError();
1083 row.RowError += updatedArgs.Errors.Message;
1084 if (!ContinueUpdateOnError) {
1085 throw updatedArgs.Errors;
1088 case UpdateStatus.SkipCurrentRow:
1090 case UpdateStatus.SkipAllRemainingRows:
1093 row.AcceptChanges ();
1094 } catch(Exception e) {
1095 row.RowError = e.Message;
1096 if (!ContinueUpdateOnError) {
1100 if (reader != null && ! reader.IsClosed) {
1108 public int Update (DataSet dataSet, string sourceTable)
1110 MissingMappingAction mappingAction = MissingMappingAction;
1112 if (mappingAction == MissingMappingAction.Ignore)
1113 mappingAction = MissingMappingAction.Error;
1115 DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTable, sourceTable, mappingAction);
1117 DataTable dataTable = dataSet.Tables[tableMapping.DataSetTable];
1118 if (dataTable == null)
1119 throw new ArgumentException (String.Format ("Missing table {0}",
1121 return Update (dataTable, tableMapping);
1124 #if ONLY_1_0 || ONLY_1_1
1125 protected virtual void OnFillError (FillErrorEventArgs value)
1127 if (FillError != null)
1128 FillError (this, value);
1132 #endregion // Methods