/Rhino.Etl.Core/DataReaders/EnumerableDataReader.cs

http://github.com/ayende/rhino-etl · C# · 447 lines · 178 code · 40 blank · 229 comment · 8 complexity · f0edbddb56b33edbece088ec97c6a1df MD5 · raw file

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