2
0

DbDataAdapter.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. //
  2. // System.Data.Common.DbDataAdapter.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya ([email protected])
  6. // Tim Coleman ([email protected])
  7. //
  8. // (C) Ximian, Inc
  9. // Copyright (C) 2002 Tim Coleman
  10. //
  11. using System;
  12. using System.Collections;
  13. using System.Data;
  14. namespace System.Data.Common
  15. {
  16. /// <summary>
  17. /// Aids implementation of the IDbDataAdapter interface. Inheritors of DbDataAdapter implement a set of functions to provide strong typing, but inherit most of the functionality needed to fully implement a DataAdapter.
  18. /// </summary>
  19. public abstract class DbDataAdapter : DataAdapter, ICloneable
  20. {
  21. #region Fields
  22. public const string DefaultSourceTableName = "Table";
  23. const string DefaultSourceColumnName = "Column";
  24. #endregion
  25. #region Constructors
  26. protected DbDataAdapter()
  27. {
  28. }
  29. #endregion
  30. #region Properties
  31. IDbCommand DeleteCommand {
  32. get { return ((IDbDataAdapter)this).DeleteCommand; }
  33. }
  34. IDbCommand InsertCommand {
  35. get { return ((IDbDataAdapter)this).InsertCommand; }
  36. }
  37. IDbCommand SelectCommand {
  38. get { return ((IDbDataAdapter)this).SelectCommand; }
  39. }
  40. IDbCommand UpdateCommand {
  41. get { return ((IDbDataAdapter)this).UpdateCommand; }
  42. }
  43. #endregion
  44. #region Methods
  45. protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
  46. protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping);
  47. private FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e)
  48. {
  49. FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values);
  50. args.Errors = e;
  51. args.Continue = false;
  52. return args;
  53. }
  54. [MonoTODO]
  55. protected override void Dispose (bool disposing)
  56. {
  57. }
  58. public override int Fill (DataSet dataSet)
  59. {
  60. return Fill (dataSet, 0, 0, DefaultSourceTableName, SelectCommand, CommandBehavior.Default);
  61. }
  62. public int Fill (DataTable dataTable)
  63. {
  64. if (dataTable == null)
  65. throw new NullReferenceException ();
  66. return Fill (dataTable, SelectCommand, CommandBehavior.Default);
  67. }
  68. public int Fill (DataSet dataSet, string srcTable)
  69. {
  70. return Fill (dataSet, 0, 0, srcTable, SelectCommand, CommandBehavior.Default);
  71. }
  72. [MonoTODO ("Support filling after we have already filled.")]
  73. protected virtual int Fill (DataTable dataTable, IDataReader dataReader)
  74. {
  75. int count = 0;
  76. bool doContinue = true;
  77. object[] itemArray = new object [dataReader.FieldCount];
  78. GetSchema (dataReader, dataTable);
  79. while (doContinue && dataReader.Read ()) {
  80. dataReader.GetValues (itemArray);
  81. try {
  82. dataTable.BeginLoadData ();
  83. dataTable.LoadDataRow (itemArray, AcceptChangesDuringFill);
  84. dataTable.EndLoadData ();
  85. count += 1;
  86. }
  87. catch (Exception e) {
  88. FillErrorEventArgs args = CreateFillErrorEvent (dataTable, itemArray, e);
  89. OnFillError (args);
  90. doContinue = args.Continue;
  91. }
  92. }
  93. dataReader.Close ();
  94. return count;
  95. }
  96. protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
  97. {
  98. return Fill (dataTable, command.ExecuteReader (behavior));
  99. }
  100. public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
  101. {
  102. return this.Fill (dataSet, startRecord, maxRecords, srcTable, SelectCommand, CommandBehavior.Default);
  103. }
  104. [MonoTODO ("Support filling after we have already filled.")]
  105. protected virtual int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
  106. {
  107. if (startRecord < 0)
  108. throw new ArgumentException ("The startRecord parameter was less than 0.");
  109. if (maxRecords < 0)
  110. throw new ArgumentException ("The maxRecords parameter was less than 0.");
  111. DataTable dataTable;
  112. int resultIndex = 0;
  113. int count = 0;
  114. bool doContinue = true;
  115. string tableName = srcTable;
  116. object[] itemArray = new object [dataReader.FieldCount];
  117. do {
  118. if (dataSet.Tables.Contains (tableName))
  119. dataTable = dataSet.Tables[tableName];
  120. else
  121. dataTable = new DataTable (tableName);
  122. GetSchema (dataReader, dataTable);
  123. for (int k = 0; k < startRecord; k += 1)
  124. dataReader.Read ();
  125. while (doContinue && dataReader.Read () && !(maxRecords > 0 && count >= maxRecords))
  126. {
  127. dataReader.GetValues (itemArray);
  128. try {
  129. dataTable.BeginLoadData ();
  130. dataTable.LoadDataRow (itemArray, AcceptChangesDuringFill);
  131. dataTable.EndLoadData ();
  132. count += 1;
  133. }
  134. catch (Exception e) {
  135. FillErrorEventArgs args = CreateFillErrorEvent (dataTable, itemArray, e);
  136. OnFillError (args);
  137. doContinue = args.Continue;
  138. }
  139. }
  140. if (dataTable.Rows.Count > 0) {
  141. dataSet.Tables.Add (dataTable);
  142. tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
  143. }
  144. startRecord = 0;
  145. maxRecords = 0;
  146. } while (doContinue && dataReader.NextResult ());
  147. dataReader.Close ();
  148. return count;
  149. }
  150. protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
  151. {
  152. CommandBehavior commandBehavior = behavior;
  153. if (command.Connection.State == ConnectionState.Closed)
  154. {
  155. command.Connection.Open ();
  156. commandBehavior = behavior | CommandBehavior.CloseConnection;
  157. }
  158. return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
  159. }
  160. [MonoTODO]
  161. public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType)
  162. {
  163. throw new NotImplementedException ();
  164. }
  165. [MonoTODO]
  166. public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
  167. {
  168. throw new NotImplementedException ();
  169. }
  170. [MonoTODO]
  171. public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
  172. {
  173. throw new NotImplementedException ();
  174. }
  175. [MonoTODO]
  176. protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
  177. {
  178. throw new NotImplementedException ();
  179. }
  180. [MonoTODO]
  181. protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
  182. {
  183. throw new NotImplementedException ();
  184. }
  185. public override IDataParameter[] GetFillParameters ()
  186. {
  187. object[] parameters = new object [SelectCommand.Parameters.Count];
  188. SelectCommand.Parameters.CopyTo (parameters, 0);
  189. return (IDataParameter[]) parameters;
  190. }
  191. private void GetSchema (IDataReader reader, DataTable table)
  192. {
  193. string sourceColumnName;
  194. string sourceTableName;
  195. string dsColumnName;
  196. ArrayList primaryKey = new ArrayList ();
  197. DataTableMapping tableMapping;
  198. foreach (DataRow schemaRow in reader.GetSchemaTable ().Rows)
  199. {
  200. // generate a unique column name in the dataset table.
  201. if (schemaRow ["BaseColumnName"].Equals (DBNull.Value))
  202. sourceColumnName = DefaultSourceColumnName;
  203. else
  204. sourceColumnName = (string) schemaRow ["BaseColumnName"];
  205. dsColumnName = sourceColumnName;
  206. for (int i = 1; table.Columns.Contains (dsColumnName); i += 1)
  207. dsColumnName = String.Format ("{0}{1}", sourceColumnName, i);
  208. if (schemaRow ["BaseTableName"].Equals (DBNull.Value))
  209. sourceTableName = DefaultSourceTableName;
  210. else
  211. sourceTableName = (string) schemaRow ["BaseTableName"];
  212. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, table.TableName, MissingMappingAction);
  213. // check to see if the column mapping exists
  214. if (tableMapping.ColumnMappings.IndexOfDataSetColumn (dsColumnName) < 0)
  215. {
  216. if (MissingSchemaAction == MissingSchemaAction.Error)
  217. throw new SystemException ();
  218. table.Columns.Add (dsColumnName, (Type) schemaRow ["DataType"]);
  219. tableMapping.ColumnMappings.Add (dsColumnName, sourceColumnName);
  220. }
  221. if (!TableMappings.Contains (tableMapping))
  222. TableMappings.Add (tableMapping);
  223. if (!schemaRow["IsKey"].Equals (DBNull.Value))
  224. if ((bool) (schemaRow ["IsKey"]))
  225. primaryKey.Add (table.Columns [dsColumnName]);
  226. }
  227. if (MissingSchemaAction == MissingSchemaAction.AddWithKey && primaryKey.Count > 0)
  228. table.PrimaryKey = (DataColumn[])(primaryKey.ToArray());
  229. }
  230. [MonoTODO]
  231. object ICloneable.Clone ()
  232. {
  233. throw new NotImplementedException ();
  234. }
  235. [MonoTODO]
  236. public int Update (DataRow[] dataRows)
  237. {
  238. throw new NotImplementedException (); // FIXME: Which mapping?
  239. }
  240. public override int Update (DataSet dataSet)
  241. {
  242. int result = 0;
  243. foreach (DataTable table in dataSet.Tables)
  244. result += Update (table);
  245. return result;
  246. }
  247. public int Update (DataTable dataTable)
  248. {
  249. int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
  250. if (index < 0)
  251. throw new ArgumentException ();
  252. return Update ((DataRow[]) dataTable.Rows.List.ToArray (typeof (DataRow)), TableMappings[index]);
  253. }
  254. [MonoTODO]
  255. protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping)
  256. {
  257. int updateCount = 0;
  258. foreach (DataRow row in dataRows) {
  259. StatementType statementType = StatementType.Update;
  260. IDbCommand command = null;
  261. string commandName = String.Empty;
  262. bool useCommandBuilder = false;
  263. switch (row.RowState) {
  264. case DataRowState.Added:
  265. statementType = StatementType.Insert;
  266. command = InsertCommand;
  267. commandName = "Insert";
  268. break;
  269. case DataRowState.Deleted:
  270. statementType = StatementType.Delete;
  271. command = DeleteCommand;
  272. commandName = "Delete";
  273. break;
  274. case DataRowState.Modified:
  275. statementType = StatementType.Update;
  276. command = UpdateCommand;
  277. commandName = "Update";
  278. break;
  279. case DataRowState.Unchanged:
  280. continue;
  281. case DataRowState.Detached:
  282. throw new NotImplementedException ();
  283. }
  284. if (command == null)
  285. useCommandBuilder = true;
  286. RowUpdatingEventArgs args = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
  287. OnRowUpdating (args);
  288. if (args.Status == UpdateStatus.ErrorsOccurred)
  289. throw (args.Errors);
  290. if (command == null && args.Command != null)
  291. command = args.Command;
  292. else if (command == null)
  293. throw new InvalidOperationException (String.Format ("Update requires a valid {0}Command when passed a DataRow collection with modified rows.", commandName));
  294. if (!useCommandBuilder) {
  295. DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
  296. foreach (IDataParameter parameter in command.Parameters) {
  297. string dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
  298. DataRowVersion rowVersion = DataRowVersion.Proposed;
  299. // Parameter version is ignored for non-update commands
  300. if (statementType == StatementType.Update)
  301. rowVersion = parameter.SourceVersion;
  302. parameter.Value = row [dsColumnName, rowVersion];
  303. }
  304. row.AcceptChanges ();
  305. }
  306. updateCount += command.ExecuteNonQuery ();
  307. OnRowUpdated (CreateRowUpdatedEvent (row, command, statementType, tableMapping));
  308. }
  309. return updateCount;
  310. }
  311. public int Update (DataSet dataSet, string sourceTable)
  312. {
  313. int result = 0;
  314. DataTableMapping tableMapping = TableMappings [sourceTable];
  315. foreach (DataTable table in dataSet.Tables)
  316. result += Update ((DataRow[]) table.Rows.List.ToArray (typeof (DataRow)), tableMapping);
  317. return result;
  318. }
  319. protected virtual void OnFillError (FillErrorEventArgs value)
  320. {
  321. if (FillError != null)
  322. FillError (this, value);
  323. }
  324. protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
  325. protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
  326. #endregion // Methods
  327. #region Events
  328. public event FillErrorEventHandler FillError;
  329. #endregion // Events
  330. }
  331. }