DbDataAdapter.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. //
  2. // System.Data.Common.DbDataAdapter.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya ([email protected])
  6. // Tim Coleman ([email protected])
  7. // Sureshkumar T <[email protected]>
  8. //
  9. // (C) Ximian, Inc
  10. // Copyright (C) Tim Coleman, 2002-2003
  11. //
  12. //
  13. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System;
  35. using System.Collections;
  36. using System.ComponentModel;
  37. using System.Data;
  38. using System.Reflection;
  39. using System.Runtime.InteropServices;
  40. namespace System.Data.Common {
  41. #if NET_2_0
  42. public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
  43. #else
  44. public abstract class DbDataAdapter : DataAdapter, ICloneable
  45. #endif
  46. {
  47. #region Fields
  48. public const string DefaultSourceTableName = "Table";
  49. const string DefaultSourceColumnName = "Column";
  50. CommandBehavior _behavior = CommandBehavior.Default;
  51. #if NET_2_0
  52. IDbCommand _selectCommand;
  53. IDbCommand _updateCommand;
  54. IDbCommand _deleteCommand;
  55. IDbCommand _insertCommand;
  56. #endif
  57. #endregion // Fields
  58. #region Constructors
  59. protected DbDataAdapter()
  60. {
  61. }
  62. protected DbDataAdapter (DbDataAdapter adapter) : base (adapter)
  63. {
  64. }
  65. #endregion // Fields
  66. #region Properties
  67. #if NET_2_0
  68. protected internal CommandBehavior FillCommandBehavior {
  69. get { return _behavior; }
  70. set { _behavior = value; }
  71. }
  72. IDbCommand IDbDataAdapter.SelectCommand {
  73. get { return _selectCommand; }
  74. set { _selectCommand = value; }
  75. }
  76. IDbCommand IDbDataAdapter.UpdateCommand{
  77. get { return _updateCommand; }
  78. set { _updateCommand = value; }
  79. }
  80. IDbCommand IDbDataAdapter.DeleteCommand{
  81. get { return _deleteCommand; }
  82. set { _deleteCommand = value; }
  83. }
  84. IDbCommand IDbDataAdapter.InsertCommand{
  85. get { return _insertCommand; }
  86. set { _insertCommand = value; }
  87. }
  88. [Browsable (false)]
  89. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  90. public DbCommand SelectCommand {
  91. get { return (DbCommand) ((IDbDataAdapter) this).SelectCommand; }
  92. set { ((IDbDataAdapter) this).SelectCommand = value; }
  93. }
  94. [Browsable (false)]
  95. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  96. public DbCommand DeleteCommand {
  97. get { return (DbCommand) ((IDbDataAdapter) this).DeleteCommand; }
  98. set { ((IDbDataAdapter) this).DeleteCommand = value; }
  99. }
  100. [Browsable (false)]
  101. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  102. public DbCommand InsertCommand {
  103. get { return (DbCommand) ((IDbDataAdapter) this).InsertCommand; }
  104. set { ((IDbDataAdapter) this).InsertCommand = value; }
  105. }
  106. [Browsable (false)]
  107. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  108. public DbCommand UpdateCommand {
  109. get { return (DbCommand) ((IDbDataAdapter) this).UpdateCommand; }
  110. set { ((IDbDataAdapter) this).UpdateCommand = value; }
  111. }
  112. [DefaultValue (1)]
  113. public virtual int UpdateBatchSize {
  114. get { return 1; }
  115. set {
  116. if (value != 1)
  117. throw new NotSupportedException ();
  118. }
  119. }
  120. #else
  121. IDbCommand SelectCommand {
  122. get { return ((IDbDataAdapter) this).SelectCommand; }
  123. }
  124. IDbCommand UpdateCommand {
  125. get { return ((IDbDataAdapter) this).UpdateCommand; }
  126. }
  127. IDbCommand DeleteCommand {
  128. get { return ((IDbDataAdapter) this).DeleteCommand; }
  129. }
  130. IDbCommand InsertCommand {
  131. get { return ((IDbDataAdapter) this).InsertCommand; }
  132. }
  133. #endif
  134. #endregion // Properties
  135. #region Events
  136. #if ONLY_1_0 || ONLY_1_1
  137. [DataCategory ("Fill")]
  138. [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
  139. public event FillErrorEventHandler FillError;
  140. #endif
  141. #endregion // Events
  142. #region Methods
  143. #if NET_2_0
  144. protected virtual RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
  145. StatementType statementType,
  146. DataTableMapping tableMapping)
  147. {
  148. return new RowUpdatedEventArgs (dataRow, command, statementType, tableMapping);
  149. }
  150. protected virtual RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
  151. StatementType statementType,
  152. DataTableMapping tableMapping)
  153. {
  154. return new RowUpdatingEventArgs (dataRow, command, statementType, tableMapping);
  155. }
  156. protected virtual void OnRowUpdated (RowUpdatedEventArgs value)
  157. {
  158. if (Events ["RowUpdated"] != null) {
  159. Delegate [] rowUpdatedList = Events ["RowUpdated"].GetInvocationList ();
  160. foreach (Delegate rowUpdated in rowUpdatedList) {
  161. MethodInfo rowUpdatedMethod = rowUpdated.Method;
  162. rowUpdatedMethod.Invoke (value, null);
  163. }
  164. }
  165. }
  166. protected virtual void OnRowUpdating (RowUpdatingEventArgs value)
  167. {
  168. if (Events ["RowUpdating"] != null) {
  169. Delegate [] rowUpdatingList = Events ["RowUpdating"].GetInvocationList ();
  170. foreach (Delegate rowUpdating in rowUpdatingList) {
  171. MethodInfo rowUpdatingMethod = rowUpdating.Method;
  172. rowUpdatingMethod.Invoke (value, null);
  173. }
  174. }
  175. }
  176. #else
  177. protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
  178. StatementType statementType,
  179. DataTableMapping tableMapping);
  180. protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
  181. StatementType statementType,
  182. DataTableMapping tableMapping);
  183. protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
  184. protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
  185. #endif
  186. protected override void Dispose (bool disposing)
  187. {
  188. if (disposing) {
  189. IDbDataAdapter da = (IDbDataAdapter) this;
  190. if (da.SelectCommand != null) {
  191. da.SelectCommand.Dispose();
  192. da.SelectCommand = null;
  193. }
  194. if (da.InsertCommand != null) {
  195. da.InsertCommand.Dispose();
  196. da.InsertCommand = null;
  197. }
  198. if (da.UpdateCommand != null) {
  199. da.UpdateCommand.Dispose();
  200. da.UpdateCommand = null;
  201. }
  202. if (da.DeleteCommand != null) {
  203. da.DeleteCommand.Dispose();
  204. da.DeleteCommand = null;
  205. }
  206. }
  207. }
  208. public override int Fill (DataSet dataSet)
  209. {
  210. return Fill (dataSet, 0, 0, DefaultSourceTableName, ((IDbDataAdapter) this).SelectCommand, _behavior);
  211. }
  212. public int Fill (DataTable dataTable)
  213. {
  214. if (dataTable == null)
  215. throw new ArgumentNullException ("DataTable");
  216. return Fill (dataTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
  217. }
  218. public int Fill (DataSet dataSet, string srcTable)
  219. {
  220. return Fill (dataSet, 0, 0, srcTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
  221. }
  222. #if NET_1_0
  223. protected
  224. #else
  225. internal
  226. #endif
  227. virtual new int Fill (DataTable dataTable, IDataReader dataReader)
  228. {
  229. return base.FillInternal (dataTable, dataReader);
  230. }
  231. protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
  232. {
  233. CommandBehavior commandBehavior = behavior;
  234. // first see that the connection is not close.
  235. if (command.Connection.State == ConnectionState.Closed)
  236. {
  237. command.Connection.Open ();
  238. commandBehavior |= CommandBehavior.CloseConnection;
  239. }
  240. return Fill (dataTable, command.ExecuteReader (commandBehavior));
  241. }
  242. public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
  243. {
  244. return this.Fill (dataSet, startRecord, maxRecords, srcTable, ((IDbDataAdapter) this).SelectCommand, _behavior);
  245. }
  246. #if NET_2_0
  247. [MonoTODO]
  248. public int Fill (int startRecord, int maxRecords, params DataTable[] dataTables)
  249. {
  250. throw new NotImplementedException ();
  251. }
  252. [MonoTODO]
  253. protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
  254. {
  255. throw new NotImplementedException ();
  256. }
  257. #endif
  258. #if !NET_2_0
  259. protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
  260. {
  261. return base.FillInternal (dataSet, srcTable, dataReader, startRecord, maxRecords);
  262. }
  263. #endif
  264. protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
  265. {
  266. if (command.Connection == null) {
  267. throw new InvalidOperationException ("Connection state is closed");
  268. }
  269. if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
  270. behavior |= CommandBehavior.KeyInfo;
  271. CommandBehavior commandBehavior = behavior;
  272. if (command.Connection.State == ConnectionState.Closed) {
  273. command.Connection.Open ();
  274. commandBehavior |= CommandBehavior.CloseConnection;
  275. }
  276. return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
  277. }
  278. #if NET_2_0
  279. /// <summary>
  280. /// Fills the given datatable using values from reader. if a value
  281. /// for a column is null, that will be filled with default value.
  282. /// </summary>
  283. /// <returns>No. of rows affected </returns>
  284. internal static int FillFromReader (DataTable table,
  285. IDataReader reader,
  286. int start,
  287. int length,
  288. int [] mapping,
  289. LoadOption loadOption
  290. )
  291. {
  292. if (reader.FieldCount == 0)
  293. return 0 ;
  294. for (int i = 0; i < start; i++)
  295. reader.Read ();
  296. int counter = 0;
  297. object [] values = new object [mapping.Length];
  298. while (reader.Read () &&
  299. (length == 0 || counter < length)) {
  300. for (int i = 0 ; i < mapping.Length; i++)
  301. values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
  302. table.BeginLoadData ();
  303. table.LoadDataRow (values, loadOption);
  304. table.EndLoadData ();
  305. counter++;
  306. }
  307. return counter;
  308. }
  309. internal static int FillFromReader (DataTable table,
  310. IDataReader reader,
  311. int start,
  312. int length,
  313. int [] mapping,
  314. LoadOption loadOption,
  315. FillErrorEventHandler errorHandler)
  316. {
  317. if (reader.FieldCount == 0)
  318. return 0 ;
  319. for (int i = 0; i < start; i++)
  320. reader.Read ();
  321. int counter = 0;
  322. object [] values = new object [mapping.Length];
  323. while (reader.Read () &&
  324. (length == 0 || counter < length)) {
  325. for (int i = 0 ; i < mapping.Length; i++)
  326. values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
  327. table.BeginLoadData ();
  328. try {
  329. table.LoadDataRow (values, loadOption);
  330. } catch (Exception e) {
  331. FillErrorEventArgs args = new FillErrorEventArgs (table, values);
  332. args.Errors = e;
  333. args.Continue = false;
  334. errorHandler (table, args);
  335. // if args.Continue is not set to true or if a handler is not set, rethrow the error..
  336. if(!args.Continue)
  337. throw e;
  338. }
  339. table.EndLoadData ();
  340. counter++;
  341. }
  342. return counter;
  343. }
  344. #endif // NET_2_0
  345. public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType)
  346. {
  347. return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, DefaultSourceTableName, _behavior);
  348. }
  349. public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
  350. {
  351. return FillSchema (dataTable, schemaType, ((IDbDataAdapter) this).SelectCommand, _behavior);
  352. }
  353. public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
  354. {
  355. return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, srcTable, _behavior);
  356. }
  357. protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
  358. {
  359. if (dataTable == null)
  360. throw new ArgumentNullException ("DataTable");
  361. behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
  362. if (command.Connection.State == ConnectionState.Closed) {
  363. command.Connection.Open ();
  364. behavior |= CommandBehavior.CloseConnection;
  365. }
  366. IDataReader reader = command.ExecuteReader (behavior);
  367. try
  368. {
  369. string tableName = SetupSchema (schemaType, dataTable.TableName);
  370. if (tableName != null)
  371. {
  372. // FillSchema should add the KeyInfo unless MissingSchemaAction
  373. // is set to Ignore or Error.
  374. MissingSchemaAction schemaAction = MissingSchemaAction;
  375. if (!(schemaAction == MissingSchemaAction.Ignore ||
  376. schemaAction == MissingSchemaAction.Error))
  377. schemaAction = MissingSchemaAction.AddWithKey;
  378. BuildSchema (reader, dataTable, schemaType, schemaAction,
  379. MissingMappingAction, TableMappings);
  380. }
  381. }
  382. finally
  383. {
  384. reader.Close ();
  385. }
  386. return dataTable;
  387. }
  388. protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
  389. {
  390. if (dataSet == null)
  391. throw new ArgumentNullException ("DataSet");
  392. behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
  393. if (command.Connection.State == ConnectionState.Closed) {
  394. command.Connection.Open ();
  395. behavior |= CommandBehavior.CloseConnection;
  396. }
  397. IDataReader reader = command.ExecuteReader (behavior);
  398. ArrayList output = new ArrayList ();
  399. string tableName = srcTable;
  400. int index = 0;
  401. DataTable table;
  402. try
  403. {
  404. // FillSchema should add the KeyInfo unless MissingSchemaAction
  405. // is set to Ignore or Error.
  406. MissingSchemaAction schemaAction = MissingSchemaAction;
  407. if (!(MissingSchemaAction == MissingSchemaAction.Ignore ||
  408. MissingSchemaAction == MissingSchemaAction.Error))
  409. schemaAction = MissingSchemaAction.AddWithKey;
  410. do {
  411. tableName = SetupSchema (schemaType, tableName);
  412. if (tableName != null)
  413. {
  414. if (dataSet.Tables.Contains (tableName))
  415. table = dataSet.Tables [tableName];
  416. else
  417. {
  418. // Do not create schema if MissingSchemAction is set to Ignore
  419. if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
  420. continue;
  421. table = dataSet.Tables.Add (tableName);
  422. }
  423. BuildSchema (reader, table, schemaType, schemaAction,
  424. MissingMappingAction, TableMappings);
  425. output.Add (table);
  426. tableName = String.Format ("{0}{1}", srcTable, ++index);
  427. }
  428. }while (reader.NextResult ());
  429. }
  430. finally
  431. {
  432. reader.Close ();
  433. }
  434. return (DataTable[]) output.ToArray (typeof (DataTable));
  435. }
  436. [EditorBrowsable (EditorBrowsableState.Advanced)]
  437. public override IDataParameter[] GetFillParameters ()
  438. {
  439. IDataParameter[] parameters = new IDataParameter [SelectCommand.Parameters.Count];
  440. SelectCommand.Parameters.CopyTo (parameters, 0);
  441. return parameters;
  442. }
  443. [MonoTODO]
  444. [Obsolete ("use 'protected DbDataAdapter(DbDataAdapter)' ctor")]
  445. object ICloneable.Clone ()
  446. {
  447. throw new NotImplementedException ();
  448. }
  449. public int Update (DataRow[] dataRows)
  450. {
  451. if (dataRows == null)
  452. throw new ArgumentNullException("dataRows");
  453. if (dataRows.Length == 0)
  454. return 0;
  455. if (dataRows[0] == null)
  456. throw new ArgumentException("dataRows[0].");
  457. DataTable table = dataRows[0].Table;
  458. if (table == null)
  459. throw new ArgumentException("table is null reference.");
  460. // all rows must be in the same table
  461. for (int i = 0; i < dataRows.Length; i++)
  462. {
  463. if (dataRows[i] == null)
  464. throw new ArgumentException("dataRows[" + i + "].");
  465. if (dataRows[i].Table != table)
  466. throw new ArgumentException(
  467. " DataRow["
  468. + i
  469. + "] is from a different DataTable than DataRow[0].");
  470. }
  471. // get table mapping for this rows
  472. DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);
  473. if (tableMapping == null)
  474. {
  475. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(
  476. TableMappings,
  477. table.TableName,
  478. table.TableName,
  479. MissingMappingAction);
  480. if (tableMapping != null) {
  481. foreach (DataColumn col in table.Columns) {
  482. if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
  483. continue;
  484. DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
  485. if (columnMapping == null)
  486. columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
  487. tableMapping.ColumnMappings.Add (columnMapping);
  488. }
  489. } else {
  490. ArrayList cmc = new ArrayList ();
  491. foreach (DataColumn col in table.Columns)
  492. cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
  493. tableMapping =
  494. new DataTableMapping (
  495. table.TableName,
  496. table.TableName,
  497. cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
  498. }
  499. }
  500. DataRow[] copy = table.NewRowArray(dataRows.Length);
  501. Array.Copy(dataRows, 0, copy, 0, dataRows.Length);
  502. return Update(copy, tableMapping);
  503. }
  504. public override int Update (DataSet dataSet)
  505. {
  506. return Update (dataSet, DefaultSourceTableName);
  507. }
  508. public int Update (DataTable dataTable)
  509. {
  510. /*
  511. int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
  512. if (index < 0)
  513. throw new ArgumentException ();
  514. return Update (dataTable, TableMappings [index]);
  515. */
  516. DataTableMapping tableMapping = TableMappings.GetByDataSetTable (dataTable.TableName);
  517. if (tableMapping == null)
  518. {
  519. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (
  520. TableMappings,
  521. dataTable.TableName,
  522. dataTable.TableName,
  523. MissingMappingAction);
  524. if (tableMapping != null) {
  525. foreach (DataColumn col in dataTable.Columns) {
  526. if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
  527. continue;
  528. DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
  529. if (columnMapping == null)
  530. columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
  531. tableMapping.ColumnMappings.Add (columnMapping);
  532. }
  533. } else {
  534. ArrayList cmc = new ArrayList ();
  535. foreach (DataColumn col in dataTable.Columns)
  536. cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
  537. tableMapping =
  538. new DataTableMapping (
  539. dataTable.TableName,
  540. dataTable.TableName,
  541. cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
  542. }
  543. }
  544. return Update (dataTable, tableMapping);
  545. }
  546. private int Update (DataTable dataTable, DataTableMapping tableMapping)
  547. {
  548. DataRow[] rows = dataTable.NewRowArray(dataTable.Rows.Count);
  549. dataTable.Rows.CopyTo (rows, 0);
  550. return Update (rows, tableMapping);
  551. }
  552. protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping)
  553. {
  554. int updateCount = 0;
  555. foreach (DataRow row in dataRows) {
  556. StatementType statementType = StatementType.Update;
  557. IDbCommand command = null;
  558. string commandName = String.Empty;
  559. switch (row.RowState) {
  560. case DataRowState.Added:
  561. statementType = StatementType.Insert;
  562. command = ((IDbDataAdapter) this).InsertCommand;
  563. commandName = "Insert";
  564. break;
  565. case DataRowState.Deleted:
  566. statementType = StatementType.Delete;
  567. command = ((IDbDataAdapter) this).DeleteCommand;
  568. commandName = "Delete";
  569. break;
  570. case DataRowState.Modified:
  571. statementType = StatementType.Update;
  572. command = ((IDbDataAdapter) this).UpdateCommand;
  573. commandName = "Update";
  574. break;
  575. case DataRowState.Unchanged:
  576. case DataRowState.Detached:
  577. continue;
  578. }
  579. RowUpdatingEventArgs argsUpdating = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
  580. row.RowError = null;
  581. OnRowUpdating (argsUpdating);
  582. switch (argsUpdating.Status) {
  583. case UpdateStatus.Continue :
  584. //continue in update operation
  585. break;
  586. case UpdateStatus.ErrorsOccurred :
  587. if (argsUpdating.Errors == null) {
  588. argsUpdating.Errors = ExceptionHelper.RowUpdatedError();
  589. }
  590. row.RowError += argsUpdating.Errors.Message;
  591. if (!ContinueUpdateOnError) {
  592. throw argsUpdating.Errors;
  593. }
  594. continue;
  595. case UpdateStatus.SkipAllRemainingRows :
  596. return updateCount;
  597. case UpdateStatus.SkipCurrentRow :
  598. updateCount++;
  599. continue;
  600. default :
  601. throw ExceptionHelper.InvalidUpdateStatus (argsUpdating.Status);
  602. }
  603. command = argsUpdating.Command;
  604. try {
  605. if (command != null) {
  606. DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
  607. IDataParameter nullCheckParam = null;
  608. foreach (IDataParameter parameter in command.Parameters) {
  609. if ((parameter.Direction & ParameterDirection.Input) != 0) {
  610. string dsColumnName = parameter.SourceColumn;
  611. if (columnMappings.Contains(parameter.SourceColumn))
  612. dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
  613. if (dsColumnName == null || dsColumnName.Length <= 0) {
  614. nullCheckParam = parameter;
  615. continue;
  616. }
  617. DataRowVersion rowVersion = parameter.SourceVersion;
  618. // Parameter version is ignored for non-update commands
  619. if (statementType == StatementType.Delete)
  620. rowVersion = DataRowVersion.Original;
  621. parameter.Value = row [dsColumnName, rowVersion];
  622. if (nullCheckParam != null && (parameter.Value != null
  623. && parameter.Value != DBNull.Value)) {
  624. nullCheckParam.Value = 0;
  625. nullCheckParam = null;
  626. }
  627. }
  628. }
  629. }
  630. }
  631. catch (Exception e) {
  632. argsUpdating.Errors = e;
  633. argsUpdating.Status = UpdateStatus.ErrorsOccurred;
  634. }
  635. IDataReader reader = null;
  636. try {
  637. if (command == null) {
  638. throw ExceptionHelper.UpdateRequiresCommand (commandName);
  639. }
  640. CommandBehavior commandBehavior = CommandBehavior.Default;
  641. if (command.Connection.State == ConnectionState.Closed) {
  642. command.Connection.Open ();
  643. commandBehavior |= CommandBehavior.CloseConnection;
  644. }
  645. // use ExecuteReader because we want to use the commandbehavior parameter.
  646. // so the connection will be closed if needed.
  647. reader = command.ExecuteReader (commandBehavior);
  648. // update the current row, if the update command returns any resultset
  649. // ignore other than the first record.
  650. DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
  651. if (command.UpdatedRowSource == UpdateRowSource.Both ||
  652. command.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord) {
  653. if (reader.Read ()){
  654. DataTable retSchema = reader.GetSchemaTable ();
  655. foreach (DataRow dr in retSchema.Rows) {
  656. string columnName = dr ["ColumnName"].ToString ();
  657. string dstColumnName = columnName;
  658. if (columnMappings != null &&
  659. columnMappings.Contains(columnName))
  660. dstColumnName = columnMappings [dstColumnName].DataSetColumn;
  661. DataColumn dstColumn = row.Table.Columns [dstColumnName];
  662. if (dstColumn == null
  663. || (dstColumn.Expression != null
  664. && dstColumn.Expression.Length > 0))
  665. continue;
  666. // info from : http://www.error-bank.com/microsoft.public.dotnet.framework.windowsforms.databinding/
  667. // [email protected]_Thread.aspx
  668. // disable readonly for non-expression columns.
  669. bool readOnlyState = dstColumn.ReadOnly;
  670. dstColumn.ReadOnly = false;
  671. try {
  672. row [dstColumnName] = reader [columnName];
  673. } finally {
  674. dstColumn.ReadOnly = readOnlyState;
  675. }
  676. }
  677. }
  678. }
  679. reader.Close ();
  680. int tmp = reader.RecordsAffected; // records affected is valid only after closing reader
  681. // if the execute does not effect any rows we throw an exception.
  682. if (tmp == 0)
  683. throw new DBConcurrencyException("Concurrency violation: the " +
  684. commandName +"Command affected 0 records.");
  685. updateCount += tmp;
  686. if (command.UpdatedRowSource == UpdateRowSource.Both ||
  687. command.UpdatedRowSource == UpdateRowSource.OutputParameters) {
  688. // Update output parameters to row values
  689. foreach (IDataParameter parameter in command.Parameters) {
  690. if (parameter.Direction != ParameterDirection.InputOutput
  691. && parameter.Direction != ParameterDirection.Output
  692. && parameter.Direction != ParameterDirection.ReturnValue)
  693. continue;
  694. string dsColumnName = parameter.SourceColumn;
  695. if (columnMappings != null &&
  696. columnMappings.Contains(parameter.SourceColumn))
  697. dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
  698. DataColumn dstColumn = row.Table.Columns [dsColumnName];
  699. if (dstColumn == null
  700. || (dstColumn.Expression != null
  701. && dstColumn.Expression.Length > 0))
  702. continue;
  703. bool readOnlyState = dstColumn.ReadOnly;
  704. dstColumn.ReadOnly = false;
  705. try {
  706. row [dsColumnName] = parameter.Value;
  707. } finally {
  708. dstColumn.ReadOnly = readOnlyState;
  709. }
  710. }
  711. }
  712. RowUpdatedEventArgs updatedArgs = CreateRowUpdatedEvent (row, command, statementType, tableMapping);
  713. OnRowUpdated (updatedArgs);
  714. switch (updatedArgs.Status) {
  715. case UpdateStatus.Continue:
  716. break;
  717. case UpdateStatus.ErrorsOccurred:
  718. if (updatedArgs.Errors == null) {
  719. updatedArgs.Errors = ExceptionHelper.RowUpdatedError();
  720. }
  721. row.RowError += updatedArgs.Errors.Message;
  722. if (!ContinueUpdateOnError) {
  723. throw updatedArgs.Errors;
  724. }
  725. break;
  726. case UpdateStatus.SkipCurrentRow:
  727. continue;
  728. case UpdateStatus.SkipAllRemainingRows:
  729. return updateCount;
  730. }
  731. #if NET_2_0
  732. if (!AcceptChangesDuringUpdate)
  733. continue;
  734. #endif
  735. row.AcceptChanges ();
  736. } catch(Exception e) {
  737. row.RowError = e.Message;
  738. if (!ContinueUpdateOnError) {
  739. throw e;
  740. }
  741. } finally {
  742. if (reader != null && ! reader.IsClosed) {
  743. reader.Close ();
  744. }
  745. }
  746. }
  747. return updateCount;
  748. }
  749. public int Update (DataSet dataSet, string sourceTable)
  750. {
  751. MissingMappingAction mappingAction = MissingMappingAction;
  752. if (mappingAction == MissingMappingAction.Ignore)
  753. mappingAction = MissingMappingAction.Error;
  754. DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTable, sourceTable, mappingAction);
  755. DataTable dataTable = dataSet.Tables[tableMapping.DataSetTable];
  756. if (dataTable == null)
  757. throw new ArgumentException (String.Format ("Missing table {0}",
  758. sourceTable));
  759. return Update (dataTable, tableMapping);
  760. }
  761. #if NET_2_0
  762. // All the batch methods, should be implemented, if supported,
  763. // by individual providers
  764. protected virtual int AddToBatch (IDbCommand cmd)
  765. {
  766. throw new NotSupportedException ();
  767. }
  768. protected virtual void ClearBatch ()
  769. {
  770. throw new NotSupportedException ();
  771. }
  772. protected virtual int ExecuteBatch ()
  773. {
  774. throw new NotSupportedException ();
  775. }
  776. protected virtual IDataParameter GetBatchedParameter (int commandIdentifier, int parameterIdentifer)
  777. {
  778. throw new NotSupportedException ();
  779. }
  780. protected virtual void InitializeBatching ()
  781. {
  782. throw new NotSupportedException ();
  783. }
  784. protected virtual void TerminateBatching ()
  785. {
  786. throw new NotSupportedException ();
  787. }
  788. #endif
  789. #if ONLY_1_0 || ONLY_1_1
  790. internal override void OnFillErrorInternal (FillErrorEventArgs value)
  791. {
  792. OnFillError (value);
  793. }
  794. protected virtual void OnFillError (FillErrorEventArgs value)
  795. {
  796. if (FillError != null)
  797. FillError (this, value);
  798. }
  799. #endif
  800. #endregion // Methods
  801. }
  802. }