1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.ComponentModel; 6 using System.Data.ProviderBase; 7 using System.Diagnostics; 8 using System.Globalization; 9 10 namespace System.Data.Common 11 { 12 public class DataAdapter : Component, IDataAdapter 13 { 14 private static readonly object s_eventFillError = new object(); 15 16 private bool _acceptChangesDuringUpdate = true; 17 private bool _acceptChangesDuringUpdateAfterInsert = true; 18 private bool _continueUpdateOnError = false; 19 private bool _hasFillErrorHandler = false; 20 private bool _returnProviderSpecificTypes = false; 21 22 private bool _acceptChangesDuringFill = true; 23 private LoadOption _fillLoadOption; 24 25 private MissingMappingAction _missingMappingAction = System.Data.MissingMappingAction.Passthrough; 26 private MissingSchemaAction _missingSchemaAction = System.Data.MissingSchemaAction.Add; 27 private DataTableMappingCollection _tableMappings; 28 29 private static int s_objectTypeCount; // Bid counter 30 internal readonly int _objectID = System.Threading.Interlocked.Increment(ref s_objectTypeCount); 31 32 #if DEBUG 33 // if true, we are asserting that the caller has provided a select command 34 // which should not return an empty result set 35 private bool _debugHookNonEmptySelectCommand = false; 36 #endif 37 38 [Conditional("DEBUG")] AssertReaderHandleFieldCount(DataReaderContainer readerHandler)39 private void AssertReaderHandleFieldCount(DataReaderContainer readerHandler) 40 { 41 #if DEBUG 42 Debug.Assert(!_debugHookNonEmptySelectCommand || readerHandler.FieldCount > 0, "Scenario expects non-empty results but no fields reported by reader"); 43 #endif 44 } 45 46 [Conditional("DEBUG")] AssertSchemaMapping(SchemaMapping mapping)47 private void AssertSchemaMapping(SchemaMapping mapping) 48 { 49 #if DEBUG 50 if (_debugHookNonEmptySelectCommand) 51 { 52 Debug.Assert(mapping != null && mapping.DataValues != null && mapping.DataTable != null, "Debug hook specifies that non-empty results are not expected"); 53 } 54 #endif 55 } 56 DataAdapter()57 protected DataAdapter() : base() 58 { 59 GC.SuppressFinalize(this); 60 } 61 DataAdapter(DataAdapter from)62 protected DataAdapter(DataAdapter from) : base() 63 { 64 CloneFrom(from); 65 } 66 67 [DefaultValue(true)] 68 public bool AcceptChangesDuringFill 69 { 70 get 71 { 72 return _acceptChangesDuringFill; 73 } 74 set 75 { 76 _acceptChangesDuringFill = value; 77 } 78 } 79 80 [EditorBrowsable(EditorBrowsableState.Never)] ShouldSerializeAcceptChangesDuringFill()81 public virtual bool ShouldSerializeAcceptChangesDuringFill() 82 { 83 return (0 == _fillLoadOption); 84 } 85 86 [DefaultValue(true)] 87 public bool AcceptChangesDuringUpdate 88 { 89 get { return _acceptChangesDuringUpdate; } 90 set { _acceptChangesDuringUpdate = value; } 91 } 92 93 [DefaultValue(false)] 94 public bool ContinueUpdateOnError 95 { 96 get { return _continueUpdateOnError; } 97 set { _continueUpdateOnError = value; } 98 } 99 100 [RefreshProperties(RefreshProperties.All)] 101 public LoadOption FillLoadOption 102 { 103 get 104 { 105 LoadOption fillLoadOption = _fillLoadOption; 106 return ((0 != fillLoadOption) ? _fillLoadOption : LoadOption.OverwriteChanges); 107 } 108 set 109 { 110 switch (value) 111 { 112 case 0: // to allow simple resetting 113 case LoadOption.OverwriteChanges: 114 case LoadOption.PreserveChanges: 115 case LoadOption.Upsert: 116 _fillLoadOption = value; 117 break; 118 default: 119 throw ADP.InvalidLoadOption(value); 120 } 121 } 122 } 123 124 [EditorBrowsable(EditorBrowsableState.Never)] ResetFillLoadOption()125 public void ResetFillLoadOption() 126 { 127 _fillLoadOption = 0; 128 } 129 130 [EditorBrowsable(EditorBrowsableState.Never)] ShouldSerializeFillLoadOption()131 public virtual bool ShouldSerializeFillLoadOption() => 0 != _fillLoadOption; 132 133 [DefaultValue(System.Data.MissingMappingAction.Passthrough)] 134 public MissingMappingAction MissingMappingAction 135 { 136 get { return _missingMappingAction; } 137 set 138 { 139 switch (value) 140 { 141 case MissingMappingAction.Passthrough: 142 case MissingMappingAction.Ignore: 143 case MissingMappingAction.Error: 144 _missingMappingAction = value; 145 break; 146 default: 147 throw ADP.InvalidMissingMappingAction(value); 148 } 149 } 150 } 151 152 [DefaultValue(Data.MissingSchemaAction.Add)] 153 public MissingSchemaAction MissingSchemaAction 154 { 155 get { return _missingSchemaAction; } 156 set 157 { 158 switch (value) 159 { 160 case MissingSchemaAction.Add: 161 case MissingSchemaAction.Ignore: 162 case MissingSchemaAction.Error: 163 case MissingSchemaAction.AddWithKey: 164 _missingSchemaAction = value; 165 break; 166 default: 167 throw ADP.InvalidMissingSchemaAction(value); 168 } 169 } 170 } 171 172 internal int ObjectID => _objectID; 173 174 [DefaultValue(false)] 175 public virtual bool ReturnProviderSpecificTypes 176 { 177 get { return _returnProviderSpecificTypes; } 178 set { _returnProviderSpecificTypes = value; } 179 } 180 181 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 182 public DataTableMappingCollection TableMappings 183 { 184 get 185 { 186 DataTableMappingCollection mappings = _tableMappings; 187 if (null == mappings) 188 { 189 mappings = CreateTableMappings(); 190 if (null == mappings) 191 { 192 mappings = new DataTableMappingCollection(); 193 } 194 _tableMappings = mappings; 195 } 196 return mappings; // constructed by base class 197 } 198 } 199 200 ITableMappingCollection IDataAdapter.TableMappings => TableMappings; 201 ShouldSerializeTableMappings()202 protected virtual bool ShouldSerializeTableMappings() => true; 203 HasTableMappings()204 protected bool HasTableMappings() => ((null != _tableMappings) && (0 < TableMappings.Count)); 205 206 public event FillErrorEventHandler FillError 207 { 208 add 209 { 210 _hasFillErrorHandler = true; 211 Events.AddHandler(s_eventFillError, value); 212 } 213 remove 214 { 215 Events.RemoveHandler(s_eventFillError, value); 216 } 217 } 218 219 [Obsolete("CloneInternals() has been deprecated. Use the DataAdapter(DataAdapter from) constructor. http://go.microsoft.com/fwlink/?linkid=14202")] CloneInternals()220 protected virtual DataAdapter CloneInternals() 221 { 222 DataAdapter clone = (DataAdapter)Activator.CreateInstance(GetType(), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null); 223 clone.CloneFrom(this); 224 return clone; 225 } 226 CloneFrom(DataAdapter from)227 private void CloneFrom(DataAdapter from) 228 { 229 _acceptChangesDuringUpdate = from._acceptChangesDuringUpdate; 230 _acceptChangesDuringUpdateAfterInsert = from._acceptChangesDuringUpdateAfterInsert; 231 _continueUpdateOnError = from._continueUpdateOnError; 232 _returnProviderSpecificTypes = from._returnProviderSpecificTypes; 233 _acceptChangesDuringFill = from._acceptChangesDuringFill; 234 _fillLoadOption = from._fillLoadOption; 235 _missingMappingAction = from._missingMappingAction; 236 _missingSchemaAction = from._missingSchemaAction; 237 238 if ((null != from._tableMappings) && (0 < from.TableMappings.Count)) 239 { 240 DataTableMappingCollection parameters = TableMappings; 241 foreach (object parameter in from.TableMappings) 242 { 243 parameters.Add((parameter is ICloneable) ? ((ICloneable)parameter).Clone() : parameter); 244 } 245 } 246 } 247 CreateTableMappings()248 protected virtual DataTableMappingCollection CreateTableMappings() 249 { 250 DataCommonEventSource.Log.Trace("<comm.DataAdapter.CreateTableMappings|API> {0}", ObjectID); 251 return new DataTableMappingCollection(); 252 } 253 Dispose(bool disposing)254 protected override void Dispose(bool disposing) 255 { 256 if (disposing) 257 { 258 // release mananged objects 259 _tableMappings = null; 260 } 261 // release unmanaged objects 262 263 base.Dispose(disposing); // notify base classes 264 } 265 FillSchema(DataSet dataSet, SchemaType schemaType)266 public virtual DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType) 267 { 268 throw ADP.NotSupported(); 269 } 270 FillSchema(DataSet dataSet, SchemaType schemaType, string srcTable, IDataReader dataReader)271 protected virtual DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType, string srcTable, IDataReader dataReader) 272 { 273 long logScopeId = DataCommonEventSource.Log.EnterScope("<comm.DataAdapter.FillSchema|API> {0}, dataSet, schemaType={1}, srcTable, dataReader", ObjectID, schemaType); 274 try 275 { 276 if (null == dataSet) 277 { 278 throw ADP.ArgumentNull(nameof(dataSet)); 279 } 280 if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) 281 { 282 throw ADP.InvalidSchemaType(schemaType); 283 } 284 if (string.IsNullOrEmpty(srcTable)) 285 { 286 throw ADP.FillSchemaRequiresSourceTableName(nameof(srcTable)); 287 } 288 if ((null == dataReader) || dataReader.IsClosed) 289 { 290 throw ADP.FillRequires(nameof(dataReader)); 291 } 292 // user must Close/Dispose of the dataReader 293 object value = FillSchemaFromReader(dataSet, null, schemaType, srcTable, dataReader); 294 return (DataTable[])value; 295 } 296 finally 297 { 298 DataCommonEventSource.Log.ExitScope(logScopeId); 299 } 300 } 301 FillSchema(DataTable dataTable, SchemaType schemaType, IDataReader dataReader)302 protected virtual DataTable FillSchema(DataTable dataTable, SchemaType schemaType, IDataReader dataReader) 303 { 304 long logScopeId = DataCommonEventSource.Log.EnterScope("<comm.DataAdapter.FillSchema|API> {0}, dataTable, schemaType, dataReader", ObjectID); 305 try 306 { 307 if (null == dataTable) 308 { 309 throw ADP.ArgumentNull(nameof(dataTable)); 310 } 311 if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) 312 { 313 throw ADP.InvalidSchemaType(schemaType); 314 } 315 if ((null == dataReader) || dataReader.IsClosed) 316 { 317 throw ADP.FillRequires(nameof(dataReader)); 318 } 319 // user must Close/Dispose of the dataReader 320 // user will have to call NextResult to access remaining results 321 object value = FillSchemaFromReader(null, dataTable, schemaType, null, dataReader); 322 return (DataTable)value; 323 } 324 finally 325 { 326 DataCommonEventSource.Log.ExitScope(logScopeId); 327 } 328 } 329 FillSchemaFromReader(DataSet dataset, DataTable datatable, SchemaType schemaType, string srcTable, IDataReader dataReader)330 internal object FillSchemaFromReader(DataSet dataset, DataTable datatable, SchemaType schemaType, string srcTable, IDataReader dataReader) 331 { 332 DataTable[] dataTables = null; 333 int schemaCount = 0; 334 do 335 { 336 DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes); 337 338 AssertReaderHandleFieldCount(readerHandler); 339 if (0 >= readerHandler.FieldCount) 340 { 341 continue; 342 } 343 string tmp = null; 344 if (null != dataset) 345 { 346 tmp = DataAdapter.GetSourceTableName(srcTable, schemaCount); 347 schemaCount++; // don't increment if no SchemaTable ( a non-row returning result ) 348 } 349 350 SchemaMapping mapping = new SchemaMapping(this, dataset, datatable, readerHandler, true, schemaType, tmp, false, null, null); 351 352 if (null != datatable) 353 { 354 // do not read remaining results in single DataTable case 355 return mapping.DataTable; 356 } 357 else if (null != mapping.DataTable) 358 { 359 if (null == dataTables) 360 { 361 dataTables = new DataTable[1] { mapping.DataTable }; 362 } 363 else 364 { 365 dataTables = DataAdapter.AddDataTableToArray(dataTables, mapping.DataTable); 366 } 367 } 368 } while (dataReader.NextResult()); // FillSchema does not capture errors for FillError event 369 370 object value = dataTables; 371 if ((null == value) && (null == datatable)) 372 { 373 value = Array.Empty<DataTable>(); 374 } 375 return value; // null if datatable had no results 376 } 377 Fill(DataSet dataSet)378 public virtual int Fill(DataSet dataSet) 379 { 380 throw ADP.NotSupported(); 381 } 382 Fill(DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)383 protected virtual int Fill(DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords) 384 { 385 long logScopeId = DataCommonEventSource.Log.EnterScope("<comm.DataAdapter.Fill|API> {0}, dataSet, srcTable, dataReader, startRecord, maxRecords", ObjectID); 386 try 387 { 388 if (null == dataSet) 389 { 390 throw ADP.FillRequires(nameof(dataSet)); 391 } 392 if (string.IsNullOrEmpty(srcTable)) 393 { 394 throw ADP.FillRequiresSourceTableName(nameof(srcTable)); 395 } 396 if (null == dataReader) 397 { 398 throw ADP.FillRequires(nameof(dataReader)); 399 } 400 if (startRecord < 0) 401 { 402 throw ADP.InvalidStartRecord(nameof(startRecord), startRecord); 403 } 404 if (maxRecords < 0) 405 { 406 throw ADP.InvalidMaxRecords(nameof(maxRecords), maxRecords); 407 } 408 if (dataReader.IsClosed) 409 { 410 return 0; 411 } 412 // user must Close/Dispose of the dataReader 413 DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes); 414 return FillFromReader(dataSet, null, srcTable, readerHandler, startRecord, maxRecords, null, null); 415 } 416 finally 417 { 418 DataCommonEventSource.Log.ExitScope(logScopeId); 419 } 420 } 421 Fill(DataTable dataTable, IDataReader dataReader)422 protected virtual int Fill(DataTable dataTable, IDataReader dataReader) 423 { 424 DataTable[] dataTables = new DataTable[] { dataTable }; 425 return Fill(dataTables, dataReader, 0, 0); 426 } 427 Fill(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords)428 protected virtual int Fill(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords) 429 { 430 long logScopeId = DataCommonEventSource.Log.EnterScope("<comm.DataAdapter.Fill|API> {0}, dataTables[], dataReader, startRecord, maxRecords", ObjectID); 431 try 432 { 433 ADP.CheckArgumentLength(dataTables, nameof(dataTables)); 434 if ((null == dataTables) || (0 == dataTables.Length) || (null == dataTables[0])) 435 { 436 throw ADP.FillRequires("dataTable"); 437 } 438 if (null == dataReader) 439 { 440 throw ADP.FillRequires(nameof(dataReader)); 441 } 442 if ((1 < dataTables.Length) && ((0 != startRecord) || (0 != maxRecords))) 443 { 444 throw ADP.NotSupported(); // FillChildren is not supported with FillPage 445 } 446 447 int result = 0; 448 bool enforceContraints = false; 449 DataSet commonDataSet = dataTables[0].DataSet; 450 try 451 { 452 if (null != commonDataSet) 453 { 454 enforceContraints = commonDataSet.EnforceConstraints; 455 commonDataSet.EnforceConstraints = false; 456 } 457 for (int i = 0; i < dataTables.Length; ++i) 458 { 459 Debug.Assert(null != dataTables[i], "null DataTable Fill"); 460 461 if (dataReader.IsClosed) 462 { 463 #if DEBUG 464 Debug.Assert(!_debugHookNonEmptySelectCommand, "Debug hook asserts data reader should be open"); 465 #endif 466 break; 467 } 468 DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes); 469 AssertReaderHandleFieldCount(readerHandler); 470 if (readerHandler.FieldCount <= 0) 471 { 472 if (i == 0) 473 { 474 bool lastFillNextResult; 475 do 476 { 477 lastFillNextResult = FillNextResult(readerHandler); 478 } 479 while (lastFillNextResult && readerHandler.FieldCount <= 0); 480 if (!lastFillNextResult) 481 { 482 break; 483 } 484 } 485 else 486 { 487 continue; 488 } 489 } 490 if ((0 < i) && !FillNextResult(readerHandler)) 491 { 492 break; 493 } 494 // user must Close/Dispose of the dataReader 495 // user will have to call NextResult to access remaining results 496 int count = FillFromReader(null, dataTables[i], null, readerHandler, startRecord, maxRecords, null, null); 497 if (0 == i) 498 { 499 result = count; 500 } 501 } 502 } 503 catch (ConstraintException) 504 { 505 enforceContraints = false; 506 throw; 507 } 508 finally 509 { 510 if (enforceContraints) 511 { 512 commonDataSet.EnforceConstraints = true; 513 } 514 } 515 return result; 516 } 517 finally 518 { 519 DataCommonEventSource.Log.ExitScope(logScopeId); 520 } 521 } 522 FillFromReader(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int startRecord, int maxRecords, DataColumn parentChapterColumn, object parentChapterValue)523 internal int FillFromReader(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int startRecord, int maxRecords, DataColumn parentChapterColumn, object parentChapterValue) 524 { 525 int rowsAddedToDataSet = 0; 526 int schemaCount = 0; 527 do 528 { 529 AssertReaderHandleFieldCount(dataReader); 530 if (0 >= dataReader.FieldCount) 531 { 532 continue; // loop to next result 533 } 534 535 SchemaMapping mapping = FillMapping(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue); 536 schemaCount++; // don't increment if no SchemaTable ( a non-row returning result ) 537 538 AssertSchemaMapping(mapping); 539 540 if (null == mapping) 541 { 542 continue; // loop to next result 543 } 544 if (null == mapping.DataValues) 545 { 546 continue; // loop to next result 547 } 548 if (null == mapping.DataTable) 549 { 550 continue; // loop to next result 551 } 552 mapping.DataTable.BeginLoadData(); 553 try 554 { 555 // startRecord and maxRecords only apply to the first resultset 556 if ((1 == schemaCount) && ((0 < startRecord) || (0 < maxRecords))) 557 { 558 rowsAddedToDataSet = FillLoadDataRowChunk(mapping, startRecord, maxRecords); 559 } 560 else 561 { 562 int count = FillLoadDataRow(mapping); 563 564 if (1 == schemaCount) 565 { 566 // only return LoadDataRow count for first resultset 567 // not secondary or chaptered results 568 rowsAddedToDataSet = count; 569 } 570 } 571 } 572 finally 573 { 574 mapping.DataTable.EndLoadData(); 575 } 576 if (null != datatable) 577 { 578 break; // do not read remaining results in single DataTable case 579 } 580 } while (FillNextResult(dataReader)); 581 582 return rowsAddedToDataSet; 583 } 584 FillLoadDataRowChunk(SchemaMapping mapping, int startRecord, int maxRecords)585 private int FillLoadDataRowChunk(SchemaMapping mapping, int startRecord, int maxRecords) 586 { 587 DataReaderContainer dataReader = mapping.DataReader; 588 589 while (0 < startRecord) 590 { 591 if (!dataReader.Read()) 592 { 593 // there are no more rows on first resultset 594 return 0; 595 } 596 --startRecord; 597 } 598 599 int rowsAddedToDataSet = 0; 600 if (0 < maxRecords) 601 { 602 while ((rowsAddedToDataSet < maxRecords) && dataReader.Read()) 603 { 604 if (_hasFillErrorHandler) 605 { 606 try 607 { 608 mapping.LoadDataRowWithClear(); 609 rowsAddedToDataSet++; 610 } 611 catch (Exception e) when (ADP.IsCatchableExceptionType(e)) 612 { 613 ADP.TraceExceptionForCapture(e); 614 OnFillErrorHandler(e, mapping.DataTable, mapping.DataValues); 615 } 616 } 617 else 618 { 619 mapping.LoadDataRow(); 620 rowsAddedToDataSet++; 621 } 622 } 623 // skip remaining rows of the first resultset 624 } 625 else 626 { 627 rowsAddedToDataSet = FillLoadDataRow(mapping); 628 } 629 return rowsAddedToDataSet; 630 } 631 FillLoadDataRow(SchemaMapping mapping)632 private int FillLoadDataRow(SchemaMapping mapping) 633 { 634 int rowsAddedToDataSet = 0; 635 DataReaderContainer dataReader = mapping.DataReader; 636 if (_hasFillErrorHandler) 637 { 638 while (dataReader.Read()) 639 { // read remaining rows of first and subsequent resultsets 640 try 641 { 642 // only try-catch if a FillErrorEventHandler is registered so that 643 // in the default case we get the full callstack from users 644 mapping.LoadDataRowWithClear(); 645 rowsAddedToDataSet++; 646 } 647 catch (Exception e) when (ADP.IsCatchableExceptionType(e)) 648 { 649 ADP.TraceExceptionForCapture(e); 650 OnFillErrorHandler(e, mapping.DataTable, mapping.DataValues); 651 } 652 } 653 } 654 else 655 { 656 while (dataReader.Read()) 657 { 658 // read remaining rows of first and subsequent resultset 659 mapping.LoadDataRow(); 660 rowsAddedToDataSet++; 661 } 662 } 663 return rowsAddedToDataSet; 664 } 665 FillMappingInternal(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue)666 private SchemaMapping FillMappingInternal(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) 667 { 668 bool withKeyInfo = (Data.MissingSchemaAction.AddWithKey == MissingSchemaAction); 669 string tmp = null; 670 if (null != dataset) 671 { 672 tmp = DataAdapter.GetSourceTableName(srcTable, schemaCount); 673 } 674 return new SchemaMapping(this, dataset, datatable, dataReader, withKeyInfo, SchemaType.Mapped, tmp, true, parentChapterColumn, parentChapterValue); 675 } 676 FillMapping(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue)677 private SchemaMapping FillMapping(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) 678 { 679 SchemaMapping mapping = null; 680 if (_hasFillErrorHandler) 681 { 682 try 683 { 684 // only try-catch if a FillErrorEventHandler is registered so that 685 // in the default case we get the full callstack from users 686 mapping = FillMappingInternal(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue); 687 } 688 catch (Exception e) when (ADP.IsCatchableExceptionType(e)) 689 { 690 ADP.TraceExceptionForCapture(e); 691 OnFillErrorHandler(e, null, null); 692 } 693 } 694 else 695 { 696 mapping = FillMappingInternal(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue); 697 } 698 return mapping; 699 } 700 FillNextResult(DataReaderContainer dataReader)701 private bool FillNextResult(DataReaderContainer dataReader) 702 { 703 bool result = true; 704 if (_hasFillErrorHandler) 705 { 706 try 707 { 708 // only try-catch if a FillErrorEventHandler is registered so that 709 // in the default case we get the full callstack from users 710 result = dataReader.NextResult(); 711 } 712 catch (Exception e) when (ADP.IsCatchableExceptionType(e)) 713 { 714 ADP.TraceExceptionForCapture(e); 715 OnFillErrorHandler(e, null, null); 716 } 717 } 718 else 719 { 720 result = dataReader.NextResult(); 721 } 722 return result; 723 } 724 725 [EditorBrowsable(EditorBrowsableState.Advanced)] GetFillParameters()726 public virtual IDataParameter[] GetFillParameters() => Array.Empty<IDataParameter>(); 727 GetTableMappingBySchemaAction(string sourceTableName, string dataSetTableName, MissingMappingAction mappingAction)728 internal DataTableMapping GetTableMappingBySchemaAction(string sourceTableName, string dataSetTableName, MissingMappingAction mappingAction) 729 { 730 return DataTableMappingCollection.GetTableMappingBySchemaAction(_tableMappings, sourceTableName, dataSetTableName, mappingAction); 731 } 732 IndexOfDataSetTable(string dataSetTable)733 internal int IndexOfDataSetTable(string dataSetTable) 734 { 735 if (null != _tableMappings) 736 { 737 return TableMappings.IndexOfDataSetTable(dataSetTable); 738 } 739 return -1; 740 } 741 OnFillError(FillErrorEventArgs value)742 protected virtual void OnFillError(FillErrorEventArgs value) 743 { 744 ((FillErrorEventHandler)Events[s_eventFillError])?.Invoke(this, value); 745 } 746 OnFillErrorHandler(Exception e, DataTable dataTable, object[] dataValues)747 private void OnFillErrorHandler(Exception e, DataTable dataTable, object[] dataValues) 748 { 749 FillErrorEventArgs fillErrorEvent = new FillErrorEventArgs(dataTable, dataValues); 750 fillErrorEvent.Errors = e; 751 OnFillError(fillErrorEvent); 752 753 if (!fillErrorEvent.Continue) 754 { 755 if (null != fillErrorEvent.Errors) 756 { 757 throw fillErrorEvent.Errors; 758 } 759 throw e; 760 } 761 } 762 Update(DataSet dataSet)763 public virtual int Update(DataSet dataSet) 764 { 765 throw ADP.NotSupported(); 766 } 767 768 // used by FillSchema which returns an array of datatables added to the dataset AddDataTableToArray(DataTable[] tables, DataTable newTable)769 private static DataTable[] AddDataTableToArray(DataTable[] tables, DataTable newTable) 770 { 771 for (int i = 0; i < tables.Length; ++i) 772 { // search for duplicates 773 if (tables[i] == newTable) 774 { 775 return tables; // duplicate found 776 } 777 } 778 DataTable[] newTables = new DataTable[tables.Length + 1]; // add unique data table 779 for (int i = 0; i < tables.Length; ++i) 780 { 781 newTables[i] = tables[i]; 782 } 783 newTables[tables.Length] = newTable; 784 return newTables; 785 } 786 787 // dynamically generate source table names GetSourceTableName(string srcTable, int index)788 private static string GetSourceTableName(string srcTable, int index) 789 { 790 //if ((null != srcTable) && (0 <= index) && (index < srcTable.Length)) { 791 if (0 == index) 792 { 793 return srcTable; //[index]; 794 } 795 return srcTable + index.ToString(System.Globalization.CultureInfo.InvariantCulture); 796 } 797 } 798 799 internal sealed class LoadAdapter : DataAdapter 800 { LoadAdapter()801 internal LoadAdapter() { } 802 FillFromReader(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords)803 internal int FillFromReader(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords) 804 { 805 return Fill(dataTables, dataReader, startRecord, maxRecords); 806 } 807 } 808 } 809