DbDataAdapter.cs 30 KB

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