1 //--------------------------------------------------------------------- 2 // <copyright file="EntityDataReader.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 namespace System.Data.EntityClient 11 { 12 using System; 13 using System.Collections; 14 using System.ComponentModel; 15 using System.Data; 16 using System.Data.Common; 17 using System.Diagnostics; 18 19 /// <summary> 20 /// A data reader class for the entity client provider 21 /// </summary> 22 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] 23 public class EntityDataReader : DbDataReader, IExtendedDataRecord 24 { 25 // The command object that owns this reader 26 private EntityCommand _command; 27 28 private CommandBehavior _behavior; 29 30 // Store data reader, _storeExtendedDataRecord points to the same reader as _storeDataReader, it's here to just 31 // save the casting wherever it's used 32 private DbDataReader _storeDataReader; 33 private IExtendedDataRecord _storeExtendedDataRecord; 34 35 /// <summary> 36 /// The constructor for the data reader, each EntityDataReader must always be associated with a EntityCommand and an underlying 37 /// DbDataReader. It is expected that EntityDataReader only has a reference to EntityCommand and doesn't assume responsibility 38 /// of cleaning the command object, but it does assume responsibility of cleaning up the store data reader object. 39 /// </summary> EntityDataReader(EntityCommand command, DbDataReader storeDataReader, CommandBehavior behavior)40 internal EntityDataReader(EntityCommand command, DbDataReader storeDataReader, CommandBehavior behavior) 41 : base() 42 { 43 Debug.Assert(command != null && storeDataReader != null); 44 45 this._command = command; 46 this._storeDataReader = storeDataReader; 47 this._storeExtendedDataRecord = storeDataReader as IExtendedDataRecord; 48 this._behavior = behavior; 49 } 50 51 /// <summary> 52 /// Get the depth of nesting for the current row 53 /// </summary> 54 public override int Depth 55 { 56 get 57 { 58 return this._storeDataReader.Depth; 59 } 60 } 61 62 /// <summary> 63 /// Get the number of columns in the current row 64 /// </summary> 65 public override int FieldCount 66 { 67 get 68 { 69 return this._storeDataReader.FieldCount; 70 } 71 } 72 73 /// <summary> 74 /// Get whether the data reader has any rows 75 /// </summary> 76 public override bool HasRows 77 { 78 get 79 { 80 return this._storeDataReader.HasRows; 81 } 82 } 83 84 /// <summary> 85 /// Get whether the data reader has been closed 86 /// </summary> 87 public override bool IsClosed 88 { 89 get 90 { 91 return this._storeDataReader.IsClosed; 92 } 93 } 94 95 /// <summary> 96 /// Get whether the data reader has any rows 97 /// </summary> 98 public override int RecordsAffected 99 { 100 get 101 { 102 return this._storeDataReader.RecordsAffected; 103 } 104 } 105 106 /// <summary> 107 /// Get the value of a column with the given ordinal 108 /// </summary> 109 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 110 public override object this[int ordinal] 111 { 112 get 113 { 114 return this._storeDataReader[ordinal]; 115 } 116 } 117 118 /// <summary> 119 /// Get the value of a column with the given name 120 /// </summary> 121 /// <param name="name">The name of the column to retrieve the value</param> 122 public override object this[string name] 123 { 124 get 125 { 126 EntityUtil.CheckArgumentNull(name, "name"); 127 return this._storeDataReader[name]; 128 } 129 } 130 131 /// <summary> 132 /// Get the number of non-hidden fields in the reader 133 /// </summary> 134 public override int VisibleFieldCount 135 { 136 get 137 { 138 return this._storeDataReader.VisibleFieldCount; 139 } 140 } 141 142 /// <summary> 143 /// DataRecordInfo property describing the contents of the record. 144 /// </summary> 145 public DataRecordInfo DataRecordInfo 146 { 147 get 148 { 149 if (null == this._storeExtendedDataRecord) 150 { 151 // if a command has no results (e.g. FunctionImport with no return type), 152 // there is nothing to report. 153 return null; 154 } 155 return this._storeExtendedDataRecord.DataRecordInfo; 156 } 157 } 158 159 /// <summary> 160 /// Close this data reader 161 /// </summary> Close()162 public override void Close() 163 { 164 if (this._command != null) 165 { 166 this._storeDataReader.Close(); 167 168 // Notify the command object that we are closing, so clean up operations such as copying output parameters can be done 169 this._command.NotifyDataReaderClosing(); 170 if ((this._behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection) 171 { 172 Debug.Assert(this._command.Connection != null); 173 this._command.Connection.Close(); 174 } 175 this._command = null; 176 } 177 } 178 179 /// <summary> 180 /// Releases the resources used by this data reader 181 /// </summary> 182 /// <param name="disposing">true to release both managed and unmanaged resources, false to release only unmanaged resources</param> Dispose(bool disposing)183 protected override void Dispose(bool disposing) 184 { 185 base.Dispose(disposing); 186 if (disposing) 187 { 188 this._storeDataReader.Dispose(); 189 } 190 } 191 192 /// <summary> 193 /// Get the boolean value of a column with the given ordinal 194 /// </summary> 195 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 196 /// <returns>The boolean value</returns> GetBoolean(int ordinal)197 public override bool GetBoolean(int ordinal) 198 { 199 return this._storeDataReader.GetBoolean(ordinal); 200 } 201 202 /// <summary> 203 /// Get the byte value of a column with the given ordinal 204 /// </summary> 205 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 206 /// <returns>The byte value</returns> GetByte(int ordinal)207 public override byte GetByte(int ordinal) 208 { 209 return this._storeDataReader.GetByte(ordinal); 210 } 211 212 /// <summary> 213 /// Get the byte array value of a column with the given ordinal 214 /// </summary> 215 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 216 /// <param name="dataOffset">The index within the row to start reading</param> 217 /// <param name="buffer">The buffer to copy into</param> 218 /// <param name="bufferOffset">The index in the buffer indicating where the data is copied into</param> 219 /// <param name="length">The maximum number of bytes to read</param> 220 /// <returns>The actual number of bytes read</returns> GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)221 public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) 222 { 223 return this._storeDataReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); 224 } 225 226 /// <summary> 227 /// Get the char value of a column with the given ordinal 228 /// </summary> 229 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 230 /// <returns>The char value</returns> GetChar(int ordinal)231 public override char GetChar(int ordinal) 232 { 233 return this._storeDataReader.GetChar(ordinal); 234 } 235 236 /// <summary> 237 /// Get the char array value of a column with the given ordinal 238 /// </summary> 239 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 240 /// <param name="dataOffset">The index within the row to start reading</param> 241 /// <param name="buffer">The buffer to copy into</param> 242 /// <param name="bufferOffset">The index in the buffer indicating where the data is copied into</param> 243 /// <param name="length">The maximum number of bytes to read</param> 244 /// <returns>The actual number of characters read</returns> GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)245 public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) 246 { 247 return this._storeDataReader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); 248 } 249 250 /// <summary> 251 /// Get the name of the data type of the column with the given ordinal 252 /// </summary> 253 /// <param name="ordinal">The ordinal of the column to retrieve the name of the data type</param> 254 /// <returns>The name of the data type of the column</returns> GetDataTypeName(int ordinal)255 public override string GetDataTypeName(int ordinal) 256 { 257 return this._storeDataReader.GetDataTypeName(ordinal); 258 } 259 260 /// <summary> 261 /// Get the datetime value of a column with the given ordinal 262 /// </summary> 263 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 264 /// <returns>The datetime value</returns> GetDateTime(int ordinal)265 public override DateTime GetDateTime(int ordinal) 266 { 267 return this._storeDataReader.GetDateTime(ordinal); 268 } 269 270 /// <summary> 271 /// Get the data reader of a column with the given ordinal 272 /// </summary> 273 /// <param name="ordinal">The ordinal of the column to retrieve the reader</param> 274 /// <returns>The data reader</returns> GetDbDataReader(int ordinal)275 protected override DbDataReader GetDbDataReader(int ordinal) 276 { 277 return this._storeDataReader.GetData(ordinal); 278 } 279 280 /// <summary> 281 /// Get the decimal value of a column with the given ordinal 282 /// </summary> 283 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 284 /// <returns>The decimal value</returns> GetDecimal(int ordinal)285 public override decimal GetDecimal(int ordinal) 286 { 287 return this._storeDataReader.GetDecimal(ordinal); 288 } 289 290 /// <summary> 291 /// Get the double value of a column with the given ordinal 292 /// </summary> 293 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 294 /// <returns>The double value</returns> GetDouble(int ordinal)295 public override double GetDouble(int ordinal) 296 { 297 return this._storeDataReader.GetDouble(ordinal); 298 } 299 300 /// <summary> 301 /// Get the data type of the column with the given ordinal 302 /// </summary> 303 /// <param name="ordinal">The ordinal of the column to retrieve the data type</param> 304 /// <returns>The data type of the column</returns> GetFieldType(int ordinal)305 public override Type GetFieldType(int ordinal) 306 { 307 return this._storeDataReader.GetFieldType(ordinal); 308 } 309 310 /// <summary> 311 /// Get the float value of a column with the given ordinal 312 /// </summary> 313 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 314 /// <returns>The float value</returns> GetFloat(int ordinal)315 public override float GetFloat(int ordinal) 316 { 317 return this._storeDataReader.GetFloat(ordinal); 318 } 319 320 /// <summary> 321 /// Get the guid value of a column with the given ordinal 322 /// </summary> 323 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 324 /// <returns>The guid value</returns> GetGuid(int ordinal)325 public override Guid GetGuid(int ordinal) 326 { 327 return this._storeDataReader.GetGuid(ordinal); 328 } 329 330 /// <summary> 331 /// Get the int16 value of a column with the given ordinal 332 /// </summary> 333 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 334 /// <returns>The int16 value</returns> GetInt16(int ordinal)335 public override short GetInt16(int ordinal) 336 { 337 return this._storeDataReader.GetInt16(ordinal); 338 } 339 340 /// <summary> 341 /// Get the int32 value of a column with the given ordinal 342 /// </summary> 343 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 344 /// <returns>The int32 value</returns> GetInt32(int ordinal)345 public override int GetInt32(int ordinal) 346 { 347 return this._storeDataReader.GetInt32(ordinal); 348 } 349 350 /// <summary> 351 /// Get the int64 value of a column with the given ordinal 352 /// </summary> 353 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 354 /// <returns>The int64 value</returns> GetInt64(int ordinal)355 public override long GetInt64(int ordinal) 356 { 357 return this._storeDataReader.GetInt64(ordinal); 358 } 359 360 /// <summary> 361 /// Get the name of a column with the given ordinal 362 /// </summary> 363 /// <param name="ordinal">The ordinal of the column to retrieve the name</param> 364 /// <returns>The name</returns> GetName(int ordinal)365 public override string GetName(int ordinal) 366 { 367 return this._storeDataReader.GetName(ordinal); 368 } 369 370 /// <summary> 371 /// Get the ordinal of a column with the given name 372 /// </summary> 373 /// <param name="name">The name of the column to retrieve the ordinal</param> 374 /// <returns>The ordinal of the column</returns> GetOrdinal(string name)375 public override int GetOrdinal(string name) 376 { 377 EntityUtil.CheckArgumentNull(name, "name"); 378 return this._storeDataReader.GetOrdinal(name); 379 } 380 381 /// <summary> 382 /// implementation for DbDataReader.GetProviderSpecificFieldType() method 383 /// </summary> 384 /// <param name="ordinal"></param> 385 /// <returns></returns> 386 [EditorBrowsableAttribute(EditorBrowsableState.Never)] GetProviderSpecificFieldType(int ordinal)387 override public Type GetProviderSpecificFieldType(int ordinal) 388 { 389 return _storeDataReader.GetProviderSpecificFieldType(ordinal); 390 } 391 392 /// <summary> 393 /// implementation for DbDataReader.GetProviderSpecificValue() method 394 /// </summary> 395 /// <param name="ordinal"></param> 396 /// <returns></returns> 397 [EditorBrowsableAttribute(EditorBrowsableState.Never)] GetProviderSpecificValue(int ordinal)398 public override object GetProviderSpecificValue(int ordinal) 399 { 400 return _storeDataReader.GetProviderSpecificValue(ordinal); 401 } 402 403 /// <summary> 404 /// implementation for DbDataReader.GetProviderSpecificValues() method 405 /// </summary> 406 /// <param name="values"></param> 407 /// <returns></returns> 408 [EditorBrowsableAttribute(EditorBrowsableState.Never)] GetProviderSpecificValues(object[] values)409 public override int GetProviderSpecificValues(object[] values) 410 { 411 return _storeDataReader.GetProviderSpecificValues(values); 412 } 413 414 /// <summary> 415 /// Get the DataTable that describes the columns of this data reader 416 /// </summary> 417 /// <returns>The DataTable describing the columns</returns> GetSchemaTable()418 public override DataTable GetSchemaTable() 419 { 420 return this._storeDataReader.GetSchemaTable(); 421 } 422 423 /// <summary> 424 /// Get the string value of a column with the given ordinal 425 /// </summary> 426 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 427 /// <returns>The string value</returns> GetString(int ordinal)428 public override string GetString(int ordinal) 429 { 430 return this._storeDataReader.GetString(ordinal); 431 } 432 433 /// <summary> 434 /// Get the value of a column with the given ordinal 435 /// </summary> 436 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 437 /// <returns>The value</returns> GetValue(int ordinal)438 public override object GetValue(int ordinal) 439 { 440 return this._storeDataReader.GetValue(ordinal); 441 } 442 443 /// <summary> 444 /// Get the values for all the columns and for the current row 445 /// </summary> 446 /// <param name="values">The array where values are copied into</param> 447 /// <returns>The number of System.Object instances in the array</returns> GetValues(object[] values)448 public override int GetValues(object[] values) 449 { 450 return this._storeDataReader.GetValues(values); 451 } 452 453 /// <summary> 454 /// Get whether the value of a column is DBNull 455 /// </summary> 456 /// <param name="ordinal">The ordinal of the column to retrieve the value</param> 457 /// <returns>true if the column value is DBNull</returns> IsDBNull(int ordinal)458 public override bool IsDBNull(int ordinal) 459 { 460 return this._storeDataReader.IsDBNull(ordinal); 461 } 462 463 /// <summary> 464 /// Move the reader to the next result set when reading a batch of statements 465 /// </summary> 466 /// <returns>true if there are more result sets</returns> NextResult()467 public override bool NextResult() 468 { 469 try 470 { 471 return this._storeDataReader.NextResult(); 472 } 473 catch (Exception e) 474 { 475 if (EntityUtil.IsCatchableExceptionType(e)) 476 { 477 throw EntityUtil.CommandExecution(System.Data.Entity.Strings.EntityClient_StoreReaderFailed, e); 478 } 479 throw; 480 } 481 } 482 483 /// <summary> 484 /// Move the reader to the next row of the current result set 485 /// </summary> 486 /// <returns>true if there are more rows</returns> Read()487 public override bool Read() 488 { 489 return this._storeDataReader.Read(); 490 } 491 492 /// <summary> 493 /// Get an enumerator for enumerating results over this data reader 494 /// </summary> 495 /// <returns>An enumerator for this data reader</returns> GetEnumerator()496 public override IEnumerator GetEnumerator() 497 { 498 return this._storeDataReader.GetEnumerator(); 499 } 500 501 /// <summary> 502 /// Used to return a nested DbDataRecord. 503 /// </summary> GetDataRecord(int i)504 public DbDataRecord GetDataRecord(int i) 505 { 506 if (null == this._storeExtendedDataRecord) 507 { 508 Debug.Assert(this.FieldCount == 0, "we have fields but no metadata?"); 509 // for a query with no results, any request is out of range... 510 EntityUtil.ThrowArgumentOutOfRangeException("i"); 511 } 512 return this._storeExtendedDataRecord.GetDataRecord(i); 513 } 514 515 /// <summary> 516 /// Used to return a nested result 517 /// </summary> GetDataReader(int i)518 public DbDataReader GetDataReader(int i) 519 { 520 return this.GetDbDataReader(i); 521 } 522 } 523 } 524