/Rhino.Etl.Core/DataReaders/EnumerableDataReader.cs
C# | 447 lines | 178 code | 40 blank | 229 comment | 8 complexity | f0edbddb56b33edbece088ec97c6a1df MD5 | raw file
1namespace Rhino.Etl.Core.DataReaders 2{ 3 using System; 4 using System.Collections; 5 using System.Collections.Generic; 6 using System.Data; 7 8 /// <summary> 9 /// Represent a data reader that is based on IEnumerable implementation. 10 /// This is important because we can now pass an in memory generated code to code 11 /// that requires this, such as the SqlBulkCopy class. 12 /// </summary> 13 public abstract class EnumerableDataReader : IDataReader 14 { 15 /// <summary> 16 /// The enumerator that we are iterating on. 17 /// Required so subclasses can access the current object. 18 /// </summary> 19 protected readonly IEnumerator enumerator; 20 private long rowCount = 0; 21 private bool isClosed = false; 22 23 /// <summary> 24 /// Initializes a new instance of the <see cref="EnumerableDataReader"/> class. 25 /// </summary> 26 /// <param name="enumerator">The enumerator.</param> 27 protected EnumerableDataReader(IEnumerator enumerator) 28 { 29 this.enumerator = enumerator; 30 } 31 32 /// <summary> 33 /// Gets the descriptors for the properties that this instance 34 /// is going to handle 35 /// </summary> 36 /// <value>The property descriptors.</value> 37 protected abstract IList<Descriptor> PropertyDescriptors { get; } 38 39 #region IDataReader Members 40 41 /// <summary> 42 /// Closes the <see cref="T:System.Data.IDataReader"/> Object. 43 /// </summary> 44 public void Close() 45 { 46 DoClose(); 47 isClosed = true; 48 } 49 50 /// <summary> 51 /// Perform the actual closing of the reader 52 /// </summary> 53 protected abstract void DoClose(); 54 55 /// <summary> 56 /// Returns a <see cref="T:System.Data.DataTable"/> that describes the column metadata of the <see cref="T:System.Data.IDataReader"/>. 57 /// </summary> 58 /// <remarks> 59 /// This is a very trivial implementation, anything that tries to do something really fancy with it 60 /// may need more information 61 /// </remarks> 62 /// <returns> 63 /// A <see cref="T:System.Data.DataTable"/> that describes the column metadata. 64 /// </returns> 65 public DataTable GetSchemaTable() 66 { 67 DataTable table = new DataTable("schema"); 68 table.Columns.Add("ColumnName", typeof(string)); 69 table.Columns.Add("ColumnOrdinal", typeof(int)); 70 table.Columns.Add("DataType", typeof(Type)); 71 72 for (int i = 0; i < PropertyDescriptors.Count; i++) 73 { 74 table.Rows.Add( 75 PropertyDescriptors[i].Name, 76 i, 77 PropertyDescriptors[i].Type 78 ); 79 } 80 return table; 81 } 82 83 /// <summary> 84 /// We do not support mutliply result set 85 /// </summary> 86 /// <returns> 87 /// true if there are more rows; otherwise, false. 88 /// </returns> 89 public bool NextResult() 90 { 91 return false; 92 } 93 94 /// <summary> 95 /// Advances the <see cref="T:System.Data.IDataReader"/> to the next record. 96 /// </summary> 97 /// <returns> 98 /// true if there are more rows; otherwise, false. 99 /// </returns> 100 public bool Read() 101 { 102 bool next = enumerator.MoveNext(); 103 if (next) 104 rowCount += 1; 105 return next; 106 } 107 108 /// <summary> 109 /// Gets a value indicating the depth of nesting for the current row. 110 /// We do not support nesting. 111 /// </summary> 112 /// <value></value> 113 /// <returns>The level of nesting.</returns> 114 public int Depth 115 { 116 get { return 0; } 117 } 118 119 /// <summary> 120 /// Gets a value indicating whether the data reader is closed. 121 /// </summary> 122 /// <value></value> 123 /// <returns>true if the data reader is closed; otherwise, false.</returns> 124 public bool IsClosed 125 { 126 get { return isClosed; } 127 } 128 129 /// <summary> 130 /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. 131 /// </summary> 132 /// <value></value> 133 /// <returns>The number of rows changed, inserted, or deleted; 0 if no rows were affected or the statement failed; and -1 for SELECT statements.</returns> 134 public int RecordsAffected 135 { 136 get { return -1; } 137 } 138 139 /// <summary> 140 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 141 /// </summary> 142 public void Dispose() 143 { 144 Close(); 145 } 146 147 /// <summary> 148 /// Gets the name for the field to find. 149 /// </summary> 150 /// <param name="i">The index of the field to find.</param> 151 /// <returns> 152 /// The name of the field or the empty string (""), if there is no value to return. 153 /// </returns> 154 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 155 public string GetName(int i) 156 { 157 return PropertyDescriptors[i].Name; 158 } 159 160 /// <summary> 161 /// Gets the data type information for the specified field. 162 /// </summary> 163 /// <param name="i">The index of the field to find.</param> 164 /// <returns> 165 /// The data type information for the specified field. 166 /// </returns> 167 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 168 public string GetDataTypeName(int i) 169 { 170 return PropertyDescriptors[i].Type.Name; 171 } 172 173 /// <summary> 174 /// Gets the <see cref="T:System.Type"/> information corresponding to the type of <see cref="T:System.Object"/> that would be returned from <see cref="M:System.Data.IDataRecord.GetValue(System.Int32)"/>. 175 /// </summary> 176 /// <param name="i">The index of the field to find.</param> 177 /// <returns> 178 /// The <see cref="T:System.Type"/> information corresponding to the type of <see cref="T:System.Object"/> that would be returned from <see cref="M:System.Data.IDataRecord.GetValue(System.Int32)"/>. 179 /// </returns> 180 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 181 public Type GetFieldType(int i) 182 { 183 return PropertyDescriptors[i].Type; 184 } 185 186 /// <summary> 187 /// Return the value of the specified field. 188 /// </summary> 189 /// <param name="i">The index of the field to find.</param> 190 /// <returns> 191 /// The <see cref="T:System.Object"/> which will contain the field value upon return. 192 /// </returns> 193 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 194 public object GetValue(int i) 195 { 196 return PropertyDescriptors[i].GetValue(enumerator.Current) ?? DBNull.Value; 197 } 198 199 /// <summary> 200 /// Gets all the attribute fields in the collection for the current record. 201 /// </summary> 202 /// <param name="values">An array of <see cref="T:System.Object"/> to copy the attribute fields into.</param> 203 /// <returns> 204 /// The number of instances of <see cref="T:System.Object"/> in the array. 205 /// </returns> 206 public int GetValues(object[] values) 207 { 208 for (int i = 0; i < PropertyDescriptors.Count; i++) 209 { 210 values[i] = PropertyDescriptors[i].GetValue(enumerator.Current); 211 } 212 return PropertyDescriptors.Count; 213 } 214 215 /// <summary> 216 /// Return the index of the named field. 217 /// </summary> 218 /// <param name="name">The name of the field to find.</param> 219 /// <returns>The index of the named field.</returns> 220 public int GetOrdinal(string name) 221 { 222 for (int i = 0; i < PropertyDescriptors.Count; i++) 223 { 224 if (string.Equals(PropertyDescriptors[i].Name, name, StringComparison.InvariantCultureIgnoreCase)) 225 return i; 226 } 227 throw new ArgumentException("There is not property with name: " + name); 228 } 229 230 /// <summary> 231 /// Gets the value of the specified column as a Boolean. 232 /// </summary> 233 /// <param name="i">The zero-based column ordinal.</param> 234 /// <returns>The value of the column.</returns> 235 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 236 public bool GetBoolean(int i) 237 { 238 return (bool)GetValue(i); 239 } 240 241 /// <summary> 242 /// Gets the 8-bit unsigned integer value of the specified column. 243 /// </summary> 244 /// <param name="i">The zero-based column ordinal.</param> 245 /// <returns> 246 /// The 8-bit unsigned integer value of the specified column. 247 /// </returns> 248 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 249 public byte GetByte(int i) 250 { 251 return (byte)GetValue(i); 252 } 253 254 /// <summary> 255 /// We do not support this operation 256 /// </summary> 257 public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) 258 { 259 throw new NotSupportedException(); 260 } 261 262 /// <summary> 263 /// Gets the character value of the specified column. 264 /// </summary> 265 /// <param name="i">The zero-based column ordinal.</param> 266 /// <returns> 267 /// The character value of the specified column. 268 /// </returns> 269 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 270 public char GetChar(int i) 271 { 272 return (char)GetValue(i); 273 } 274 275 /// <summary> 276 /// We do not support this operation 277 /// </summary> 278 public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) 279 { 280 throw new NotSupportedException(); 281 } 282 283 /// <summary> 284 /// Returns the GUID value of the specified field. 285 /// </summary> 286 /// <param name="i">The index of the field to find.</param> 287 /// <returns>The GUID value of the specified field.</returns> 288 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 289 public Guid GetGuid(int i) 290 { 291 return (Guid)GetValue(i); 292 } 293 294 /// <summary> 295 /// Gets the 16-bit signed integer value of the specified field. 296 /// </summary> 297 /// <param name="i">The index of the field to find.</param> 298 /// <returns> 299 /// The 16-bit signed integer value of the specified field. 300 /// </returns> 301 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 302 public short GetInt16(int i) 303 { 304 return (short)GetValue(i); 305 } 306 307 /// <summary> 308 /// Gets the 32-bit signed integer value of the specified field. 309 /// </summary> 310 /// <param name="i">The index of the field to find.</param> 311 /// <returns> 312 /// The 32-bit signed integer value of the specified field. 313 /// </returns> 314 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 315 public int GetInt32(int i) 316 { 317 return (int)GetValue(i); 318 } 319 320 /// <summary> 321 /// Gets the 64-bit signed integer value of the specified field. 322 /// </summary> 323 /// <param name="i">The index of the field to find.</param> 324 /// <returns> 325 /// The 64-bit signed integer value of the specified field. 326 /// </returns> 327 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 328 public long GetInt64(int i) 329 { 330 return (long)GetValue(i); 331 } 332 333 /// <summary> 334 /// Gets the single-precision floating point number of the specified field. 335 /// </summary> 336 /// <param name="i">The index of the field to find.</param> 337 /// <returns> 338 /// The single-precision floating point number of the specified field. 339 /// </returns> 340 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 341 public float GetFloat(int i) 342 { 343 return (float)GetValue(i); 344 } 345 346 /// <summary> 347 /// Gets the double-precision floating point number of the specified field. 348 /// </summary> 349 /// <param name="i">The index of the field to find.</param> 350 /// <returns> 351 /// The double-precision floating point number of the specified field. 352 /// </returns> 353 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 354 public double GetDouble(int i) 355 { 356 return (double)GetValue(i); 357 } 358 359 /// <summary> 360 /// Gets the string value of the specified field. 361 /// </summary> 362 /// <param name="i">The index of the field to find.</param> 363 /// <returns>The string value of the specified field.</returns> 364 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 365 public string GetString(int i) 366 { 367 return (string)GetValue(i); 368 } 369 370 /// <summary> 371 /// Gets the fixed-position numeric value of the specified field. 372 /// </summary> 373 /// <param name="i">The index of the field to find.</param> 374 /// <returns> 375 /// The fixed-position numeric value of the specified field. 376 /// </returns> 377 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 378 public decimal GetDecimal(int i) 379 { 380 return (decimal)GetValue(i); 381 } 382 383 /// <summary> 384 /// Gets the date and time data value of the specified field. 385 /// </summary> 386 /// <param name="i">The index of the field to find.</param> 387 /// <returns> 388 /// The date and time data value of the specified field. 389 /// </returns> 390 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 391 public DateTime GetDateTime(int i) 392 { 393 return (DateTime)GetValue(i); 394 } 395 396 /// <summary> 397 /// We do not support nesting 398 /// </summary> 399 public IDataReader GetData(int i) 400 { 401 throw new NotSupportedException(); 402 } 403 404 /// <summary> 405 /// Return whether the specified field is set to null. 406 /// </summary> 407 /// <param name="i">The index of the field to find.</param> 408 /// <returns> 409 /// true if the specified field is set to null; otherwise, false. 410 /// </returns> 411 /// <exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. </exception> 412 public bool IsDBNull(int i) 413 { 414 return GetValue(i) == null || GetValue(i) == DBNull.Value; 415 } 416 417 /// <summary> 418 /// Gets the number of columns in the current row. 419 /// </summary> 420 /// <value></value> 421 /// <returns>When not positioned in a valid recordset, 0; otherwise, the number of columns in the current record. The default is -1.</returns> 422 public int FieldCount 423 { 424 get { return PropertyDescriptors.Count; } 425 } 426 427 /// <summary> 428 /// Gets the <see cref="System.Object"/> with the specified i. 429 /// </summary> 430 /// <value></value> 431 public object this[int i] 432 { 433 get { return GetValue(i); } 434 } 435 436 /// <summary> 437 /// Gets the <see cref="System.Object"/> with the specified name. 438 /// </summary> 439 /// <value></value> 440 public object this[string name] 441 { 442 get { return GetValue(GetOrdinal(name)); } 443 } 444 445 #endregion 446 } 447}