PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Spss/SpssCasesCollection.cs

#
C# | 268 lines | 132 code | 31 blank | 105 comment | 21 complexity | da5fc831d1a003f731e82cb6ab2e30f1 MD5 | raw file
Possible License(s): LGPL-2.1
  1. namespace Spss {
  2. using System;
  3. using System.Collections;
  4. using System.Data;
  5. /// <summary>
  6. /// Manages the cases in an SPSS data file.
  7. /// Supports reading, writing, and appending data.
  8. /// </summary>
  9. public sealed class SpssCasesCollection : IEnumerable {
  10. private int position = -1;
  11. private int caseCountInWriteMode;
  12. /// <summary>
  13. /// Initializes a new instance of the <see cref="SpssCasesCollection"/> class.
  14. /// </summary>
  15. /// <param name="document">The hosting document.</param>
  16. internal SpssCasesCollection(SpssDataDocument document) {
  17. if (document == null) {
  18. throw new ArgumentNullException("document");
  19. }
  20. this.Document = document;
  21. }
  22. /// <summary>
  23. /// Gets a value indicating whether the set of cases is read only.
  24. /// If no cases can be added, changed or removed, IsReadOnly is true.
  25. /// <seealso cref="IsAppendOnly"/>
  26. /// </summary>
  27. public bool IsReadOnly {
  28. get {
  29. return Document.AccessMode == SpssFileAccess.Read;
  30. }
  31. }
  32. /// <summary>
  33. /// Gets a value indicating whether the set of cases can only be appended to.
  34. /// If no cases can be removed or changed, IsAppendOnly is true.
  35. /// <seealso cref="IsReadOnly"/>
  36. /// </summary>
  37. public bool IsAppendOnly {
  38. get {
  39. return this.Document.AccessMode != SpssFileAccess.Read; // Create or Append
  40. }
  41. }
  42. /// <summary>
  43. /// Gets the SPSS data document whose cases are being managed.
  44. /// </summary>
  45. public SpssDataDocument Document { get; private set; }
  46. /// <summary>
  47. /// Gets the file handle of the SPSS data document whose cases are being managed.
  48. /// </summary>
  49. internal Int32 FileHandle {
  50. get { return this.Document.Handle; }
  51. }
  52. /// <summary>
  53. /// The number of cases in the document.
  54. /// </summary>
  55. public int Count {
  56. get {
  57. Int32 casecount = 0;
  58. // New documents aren't allowed to query cases count, and appended docs
  59. // report the # of cases there were when the file was first opened.
  60. if (this.Document.AccessMode != SpssFileAccess.Create) {
  61. SpssException.ThrowOnFailure(SpssSafeWrapper.spssGetNumberofCasesImpl(this.FileHandle, out casecount), "spssGetNumberofCases");
  62. }
  63. return casecount + this.caseCountInWriteMode;
  64. }
  65. }
  66. /// <summary>
  67. /// Gets or sets the case that SPSS is pointing at to get/set variable data on.
  68. /// </summary>
  69. internal int Position {
  70. get {
  71. return this.position;
  72. }
  73. set {
  74. if (IsAppendOnly) {
  75. throw new InvalidOperationException("Not available while in Append mode.");
  76. }
  77. if (value < 0) {
  78. throw new ArgumentOutOfRangeException("Position", value, "Must be a non-negative integer.");
  79. }
  80. if (value >= Count) {
  81. throw new ArgumentOutOfRangeException("Position", value, "Must be less than the number of cases in the file.");
  82. }
  83. if (value == position) {
  84. return; // nothing to do!
  85. }
  86. SpssException.ThrowOnFailure(SpssSafeWrapper.spssSeekNextCase(this.FileHandle, value), "spssSeekNextCase");
  87. SpssException.ThrowOnFailure(SpssSafeWrapper.spssReadCaseRecord(this.FileHandle), "spssReadCaseRecord");
  88. this.position = value;
  89. }
  90. }
  91. /// <summary>
  92. /// Gets the case record at a specific 0-based index.
  93. /// </summary>
  94. public SpssCase this[int index] {
  95. get { return new SpssCase(this, index); }
  96. }
  97. /// <summary>
  98. /// Creates a new SPSS case to assign values to.
  99. /// </summary>
  100. /// <returns>
  101. /// The <see cref="SpssCase"/> object used to access the new row.
  102. /// </returns>
  103. /// <remarks>
  104. /// This call must be followed (eventually) with a call to
  105. /// <see cref="SpssCase.Commit"/> or no new row will actually be added.
  106. /// </remarks>
  107. /// <example>
  108. /// To add a case to an existing SPSS file called mydata.sav, the following code could apply:
  109. /// <code>
  110. /// using( SpssDataDocument doc = SpssDataDocument.Open("mydata.sav", SpssFileAccess.Append) )
  111. /// {
  112. /// SpssCase Case = doc.Cases.New();
  113. /// Case["var1"] = 5;
  114. /// Case["var2"] = 3;
  115. /// Case["name"] = "Andrew";
  116. /// Case.Commit();
  117. /// }
  118. /// </code>
  119. /// </example>
  120. public SpssCase New() {
  121. if (!IsAppendOnly) {
  122. throw new InvalidOperationException("Only available in append mode.");
  123. }
  124. position = Count;
  125. return new SpssCase(this, position);
  126. }
  127. /// <summary>
  128. /// Creates a <see cref="DataTable"/> filled with all the data in the SPSS document.
  129. /// </summary>
  130. /// <returns>
  131. /// The created DataTable.
  132. /// </returns>
  133. public DataTable ToDataTable() {
  134. DataTable dt = new DataTable();
  135. foreach (SpssVariable var in this.Document.Variables) {
  136. DataColumn dc = new DataColumn(var.Name);
  137. if (var is SpssStringVariable) {
  138. dc.DataType = typeof(string);
  139. } else if (var is SpssNumericVariable) {
  140. dc.DataType = typeof(double);
  141. } else if (var is SpssDateVariable) {
  142. dc.DataType = typeof(DateTime);
  143. } else {
  144. throw new NotSupportedException("SPSS variable type " + var.GetType().Name + " is not supported.");
  145. }
  146. dt.Columns.Add(dc);
  147. }
  148. foreach (SpssCase spssCase in this) {
  149. DataRow row = dt.NewRow();
  150. foreach (SpssVariable var in this.Document.Variables) {
  151. row[var.Name] = spssCase.GetDBValue(var.Name);
  152. }
  153. dt.Rows.Add(row);
  154. }
  155. return dt;
  156. }
  157. /// <summary>
  158. /// Gets the enumerator that will iterate over all cases in the data file.
  159. /// </summary>
  160. IEnumerator IEnumerable.GetEnumerator() {
  161. if (IsAppendOnly) {
  162. throw new InvalidOperationException("Not available in append-only mode.");
  163. }
  164. return new SpssCasesCollectionEnumerator(this);
  165. }
  166. private class SpssCasesCollectionEnumerator : IEnumerator {
  167. SpssCasesCollection Cases;
  168. int position;
  169. /// <summary>
  170. /// Initializes a new instance of the <see cref="SpssCasesCollectionEnumerator"/> class.
  171. /// </summary>
  172. /// <param name="cases">The cases.</param>
  173. internal SpssCasesCollectionEnumerator(SpssCasesCollection cases) {
  174. if (cases == null) {
  175. throw new ArgumentNullException("cases");
  176. }
  177. this.Cases = cases;
  178. this.Reset();
  179. }
  180. /// <summary>
  181. /// Gets the current element in the collection.
  182. /// </summary>
  183. /// <returns>
  184. /// The current element in the collection.
  185. /// </returns>
  186. /// <exception cref="T:System.InvalidOperationException">
  187. /// The enumerator is positioned before the first element of the collection or after the last element.
  188. /// </exception>
  189. public SpssCase Current {
  190. get {
  191. return this.Cases[position];
  192. }
  193. }
  194. #region IEnumerator Members
  195. /// <summary>
  196. /// Advances the enumerator to the next element of the collection.
  197. /// </summary>
  198. /// <returns>
  199. /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
  200. /// </returns>
  201. /// <exception cref="T:System.InvalidOperationException">
  202. /// The collection was modified after the enumerator was created.
  203. /// </exception>
  204. public bool MoveNext() {
  205. return ++position < Cases.Count;
  206. }
  207. /// <summary>
  208. /// Sets the enumerator to its initial position, which is before the first element in the collection.
  209. /// </summary>
  210. /// <exception cref="T:System.InvalidOperationException">
  211. /// The collection was modified after the enumerator was created.
  212. /// </exception>
  213. public void Reset() {
  214. position = -1;
  215. }
  216. /// <summary>
  217. /// Gets the current element in the collection.
  218. /// </summary>
  219. /// <value></value>
  220. /// <returns>
  221. /// The current element in the collection.
  222. /// </returns>
  223. /// <exception cref="T:System.InvalidOperationException">
  224. /// The enumerator is positioned before the first element of the collection or after the last element.
  225. /// </exception>
  226. object System.Collections.IEnumerator.Current {
  227. get {
  228. return this.Current;
  229. }
  230. }
  231. #endregion
  232. }
  233. internal void OnCaseCommitted() {
  234. this.caseCountInWriteMode++;
  235. }
  236. }
  237. }