PageRenderTime 41ms CodeModel.GetById 30ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/Spss/SpssCasesCollection.cs

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