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