DataSet.cs 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  1. //
  2. // System.Data/DataSet.cs
  3. //
  4. // Author:
  5. // Christopher Podurgiel <[email protected]>
  6. // Daniel Morgan <[email protected]>
  7. // Rodrigo Moya <[email protected]>
  8. // Stuart Caborn <[email protected]>
  9. // Tim Coleman ([email protected])
  10. // Ville Palo <[email protected]>
  11. // Atsushi Enomoto <[email protected]>
  12. // Konstantin Triger <[email protected]>
  13. //
  14. // (C) Ximian, Inc. 2002
  15. // Copyright (C) Tim Coleman, 2002, 2003
  16. //
  17. //
  18. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  19. //
  20. // Permission is hereby granted, free of charge, to any person obtaining
  21. // a copy of this software and associated documentation files (the
  22. // "Software"), to deal in the Software without restriction, including
  23. // without limitation the rights to use, copy, modify, merge, publish,
  24. // distribute, sublicense, and/or sell copies of the Software, and to
  25. // permit persons to whom the Software is furnished to do so, subject to
  26. // the following conditions:
  27. //
  28. // The above copyright notice and this permission notice shall be
  29. // included in all copies or substantial portions of the Software.
  30. //
  31. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  32. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  33. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  34. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  35. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  36. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  37. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  38. //
  39. using System;
  40. using System.Collections;
  41. using System.ComponentModel;
  42. using System.Globalization;
  43. using System.Threading;
  44. using System.IO;
  45. using System.Runtime.Serialization;
  46. using System.Xml;
  47. using System.Xml.Schema;
  48. using System.Xml.Serialization;
  49. using System.Data.Common;
  50. namespace System.Data {
  51. [ToolboxItem ("Microsoft.VSDesigner.Data.VS.DataSetToolboxItem, " + Consts.AssemblyMicrosoft_VSDesigner)]
  52. [DefaultProperty ("DataSetName")]
  53. [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataSetDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
  54. #if NET_2_0
  55. [XmlSchemaProvider ("GetDataSetSchema")]
  56. [XmlRootAttribute ("DataSet")]
  57. #endif
  58. [Serializable]
  59. public class DataSet : MarshalByValueComponent, IListSource,
  60. ISupportInitialize, ISerializable, IXmlSerializable
  61. {
  62. private string dataSetName;
  63. private string _namespace = "";
  64. private string prefix;
  65. private bool caseSensitive;
  66. private bool enforceConstraints = true;
  67. private DataTableCollection tableCollection;
  68. private DataRelationCollection relationCollection;
  69. private PropertyCollection properties;
  70. private DataViewManager defaultView;
  71. private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
  72. internal XmlDataDocument _xmlDataDocument = null;
  73. bool initInProgress = false;
  74. #region Constructors
  75. public DataSet () : this ("NewDataSet")
  76. {
  77. }
  78. public DataSet (string name)
  79. {
  80. dataSetName = name;
  81. tableCollection = new DataTableCollection (this);
  82. relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
  83. properties = new PropertyCollection ();
  84. this.prefix = String.Empty;
  85. this.Locale = CultureInfo.CurrentCulture;
  86. }
  87. protected DataSet (SerializationInfo info, StreamingContext context) : this ()
  88. {
  89. GetSerializationData (info, context);
  90. }
  91. #if NET_2_0
  92. [MonoTODO]
  93. protected DataSet (SerializationInfo info, StreamingContext context, bool constructSchema)
  94. : this (info, context)
  95. {
  96. }
  97. #endif
  98. #endregion // Constructors
  99. #region Public Properties
  100. [DataCategory ("Data")]
  101. #if !NET_2_0
  102. [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
  103. #endif
  104. [DefaultValue (false)]
  105. public bool CaseSensitive {
  106. get {
  107. return caseSensitive;
  108. }
  109. set {
  110. caseSensitive = value;
  111. if (!caseSensitive) {
  112. foreach (DataTable table in Tables) {
  113. table.ResetCaseSensitiveIndexes();
  114. foreach (Constraint c in table.Constraints)
  115. c.AssertConstraint ();
  116. }
  117. }
  118. else {
  119. foreach (DataTable table in Tables) {
  120. table.ResetCaseSensitiveIndexes();
  121. }
  122. }
  123. }
  124. }
  125. [DataCategory ("Data")]
  126. #if !NET_2_0
  127. [DataSysDescription ("The name of this DataSet.")]
  128. #endif
  129. [DefaultValue ("")]
  130. public string DataSetName {
  131. get { return dataSetName; }
  132. set { dataSetName = value; }
  133. }
  134. #if !NET_2_0
  135. [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
  136. #endif
  137. [Browsable (false)]
  138. public DataViewManager DefaultViewManager {
  139. get {
  140. if (defaultView == null)
  141. defaultView = new DataViewManager (this);
  142. return defaultView;
  143. }
  144. }
  145. #if !NET_2_0
  146. [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
  147. #endif
  148. [DefaultValue (true)]
  149. public bool EnforceConstraints {
  150. get { return enforceConstraints; }
  151. set {
  152. InternalEnforceConstraints(value,true);
  153. }
  154. }
  155. [Browsable (false)]
  156. [DataCategory ("Data")]
  157. #if !NET_2_0
  158. [DataSysDescription ("The collection that holds custom user information.")]
  159. #endif
  160. public PropertyCollection ExtendedProperties {
  161. get { return properties; }
  162. }
  163. [Browsable (false)]
  164. #if !NET_2_0
  165. [DataSysDescription ("Indicates that the DataSet has errors.")]
  166. #endif
  167. public bool HasErrors {
  168. [MonoTODO]
  169. get {
  170. for (int i = 0; i < Tables.Count; i++) {
  171. if (Tables[i].HasErrors)
  172. return true;
  173. }
  174. return false;
  175. }
  176. }
  177. [DataCategory ("Data")]
  178. #if !NET_2_0
  179. [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
  180. #endif
  181. public CultureInfo Locale {
  182. get {
  183. return locale;
  184. }
  185. set {
  186. if (locale == null || !locale.Equals (value)) {
  187. // TODO: check if the new locale is valid
  188. // TODO: update locale of all tables
  189. locale = value;
  190. }
  191. }
  192. }
  193. internal void InternalEnforceConstraints(bool value,bool resetIndexes)
  194. {
  195. if (value == enforceConstraints)
  196. return;
  197. if (value) {
  198. if (resetIndexes) {
  199. // FIXME : is that correct?
  200. // By design the indexes should be updated at this point.
  201. // In Fill from BeginLoadData till EndLoadData indexes are not updated (reset in EndLoadData)
  202. // In DataRow.EndEdit indexes are always updated.
  203. foreach (DataTable table in Tables)
  204. table.ResetIndexes();
  205. }
  206. // TODO : Need to take care of Error handling and settting of RowErrors
  207. bool constraintViolated = false;
  208. foreach (DataTable table in Tables) {
  209. foreach (Constraint constraint in table.Constraints)
  210. constraint.AssertConstraint();
  211. table.AssertNotNullConstraints ();
  212. if (!constraintViolated && table.HasErrors)
  213. constraintViolated = true;
  214. }
  215. if (constraintViolated)
  216. Constraint.ThrowConstraintException ();
  217. }
  218. enforceConstraints = value;
  219. }
  220. public void Merge (DataRow[] rows)
  221. {
  222. Merge (rows, false, MissingSchemaAction.Add);
  223. }
  224. public void Merge (DataSet dataSet)
  225. {
  226. Merge (dataSet, false, MissingSchemaAction.Add);
  227. }
  228. public void Merge (DataTable table)
  229. {
  230. Merge (table, false, MissingSchemaAction.Add);
  231. }
  232. public void Merge (DataSet dataSet, bool preserveChanges)
  233. {
  234. Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
  235. }
  236. [MonoTODO]
  237. public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
  238. {
  239. if (rows == null)
  240. throw new ArgumentNullException ("rows");
  241. if (!IsLegalSchemaAction (missingSchemaAction))
  242. throw new ArgumentOutOfRangeException ("missingSchemaAction");
  243. MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
  244. }
  245. [MonoTODO]
  246. public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
  247. {
  248. if (dataSet == null)
  249. throw new ArgumentNullException ("dataSet");
  250. if (!IsLegalSchemaAction (missingSchemaAction))
  251. throw new ArgumentOutOfRangeException ("missingSchemaAction");
  252. MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
  253. }
  254. [MonoTODO]
  255. public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
  256. {
  257. if (table == null)
  258. throw new ArgumentNullException ("table");
  259. if (!IsLegalSchemaAction (missingSchemaAction))
  260. throw new ArgumentOutOfRangeException ("missingSchemaAction");
  261. MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
  262. }
  263. private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
  264. {
  265. if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
  266. || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
  267. return true;
  268. return false;
  269. }
  270. [DataCategory ("Data")]
  271. #if !NET_2_0
  272. [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
  273. #endif
  274. [DefaultValue ("")]
  275. public string Namespace {
  276. get { return _namespace; }
  277. set {
  278. //TODO - trigger an event if this happens?
  279. if (value == null)
  280. value = String.Empty;
  281. if (value != this._namespace)
  282. RaisePropertyChanging ("Namespace");
  283. _namespace = value;
  284. }
  285. }
  286. [DataCategory ("Data")]
  287. #if !NET_2_0
  288. [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
  289. #endif
  290. [DefaultValue ("")]
  291. public string Prefix {
  292. get { return prefix; }
  293. set {
  294. if (value == null)
  295. value = String.Empty;
  296. // Prefix cannot contain any special characters other than '_' and ':'
  297. for (int i = 0; i < value.Length; i++) {
  298. if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
  299. throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
  300. }
  301. if (value == null)
  302. value = string.Empty;
  303. if (value != this.prefix)
  304. RaisePropertyChanging ("Prefix");
  305. prefix = value;
  306. }
  307. }
  308. [DataCategory ("Data")]
  309. #if !NET_2_0
  310. [DataSysDescription ("The collection that holds the relations for this DatSet.")]
  311. #endif
  312. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  313. public DataRelationCollection Relations {
  314. get {
  315. return relationCollection;
  316. }
  317. }
  318. [Browsable (false)]
  319. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  320. public override ISite Site {
  321. [MonoTODO]
  322. get {
  323. return base.Site;
  324. }
  325. [MonoTODO]
  326. set {
  327. base.Site = value;
  328. }
  329. }
  330. [DataCategory ("Data")]
  331. #if !NET_2_0
  332. [DataSysDescription ("The collection that holds the tables for this DataSet.")]
  333. #endif
  334. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  335. public DataTableCollection Tables {
  336. get { return tableCollection; }
  337. }
  338. #if NET_2_0
  339. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  340. [Browsable (false)]
  341. public virtual SchemaSerializationMode SchemaSerializationMode {
  342. get {
  343. return SchemaSerializationMode.IncludeSchema;
  344. }
  345. set {
  346. if (value != SchemaSerializationMode.IncludeSchema)
  347. throw new InvalidOperationException (
  348. "Only IncludeSchema Mode can be set for Untyped DataSet");
  349. }
  350. }
  351. #endif
  352. #endregion // Public Properties
  353. #region Public Methods
  354. [MonoTODO]
  355. public void AcceptChanges ()
  356. {
  357. foreach (DataTable tempTable in tableCollection)
  358. tempTable.AcceptChanges ();
  359. }
  360. /// <summary>
  361. /// Clears all the tables
  362. /// </summary>
  363. public void Clear ()
  364. {
  365. if (_xmlDataDocument != null)
  366. throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
  367. bool enforceConstraints = this.EnforceConstraints;
  368. this.EnforceConstraints = false;
  369. for (int t = 0; t < tableCollection.Count; t++) {
  370. tableCollection[t].Clear ();
  371. }
  372. this.EnforceConstraints = enforceConstraints;
  373. }
  374. public virtual DataSet Clone ()
  375. {
  376. // need to return the same type as this...
  377. DataSet Copy = (DataSet) Activator.CreateInstance(GetType(), true);
  378. CopyProperties (Copy);
  379. foreach (DataTable Table in Tables) {
  380. // tables are often added in no-args constructor, don't add them
  381. // twice.
  382. if (!Copy.Tables.Contains(Table.TableName)) {
  383. Copy.Tables.Add (Table.Clone ());
  384. }
  385. }
  386. //Copy Relationships between tables after existance of tables
  387. //and setting properties correctly
  388. CopyRelations (Copy);
  389. return Copy;
  390. }
  391. // Copies both the structure and data for this DataSet.
  392. public DataSet Copy ()
  393. {
  394. // need to return the same type as this...
  395. DataSet Copy = (DataSet) Activator.CreateInstance(GetType(), true);
  396. CopyProperties (Copy);
  397. // Copy DatSet's tables
  398. foreach (DataTable Table in Tables) {
  399. if (! Copy.Tables.Contains (Table.TableName)) {
  400. Copy.Tables.Add (Table.Copy ());
  401. continue;
  402. }
  403. foreach (DataRow row in Table.Rows)
  404. Copy.Tables [Table.TableName].ImportRow (row);
  405. }
  406. //Copy Relationships between tables after existance of tables
  407. //and setting properties correctly
  408. CopyRelations (Copy);
  409. return Copy;
  410. }
  411. private void CopyProperties (DataSet Copy)
  412. {
  413. Copy.CaseSensitive = CaseSensitive;
  414. //Copy.Container = Container
  415. Copy.DataSetName = DataSetName;
  416. //Copy.DefaultViewManager
  417. //Copy.DesignMode
  418. Copy.EnforceConstraints = EnforceConstraints;
  419. if(ExtendedProperties.Count > 0) {
  420. // Cannot copy extended properties directly as the property does not have a set accessor
  421. Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
  422. ExtendedProperties.Keys.CopyTo (tgtArray, 0);
  423. for (int i=0; i < ExtendedProperties.Count; i++)
  424. Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
  425. }
  426. Copy.Locale = Locale;
  427. Copy.Namespace = Namespace;
  428. Copy.Prefix = Prefix;
  429. //Copy.Site = Site; // FIXME : Not sure of this.
  430. }
  431. private void CopyRelations (DataSet Copy)
  432. {
  433. //Creation of the relation contains some of the properties, and the constructor
  434. //demands these values. instead changing the DataRelation constructor and behaviour the
  435. //parameters are pre-configured and sent to the most general constructor
  436. foreach (DataRelation MyRelation in this.Relations) {
  437. // typed datasets create relations through ctor.
  438. if (Copy.Relations.Contains (MyRelation.RelationName))
  439. continue;
  440. string pTable = MyRelation.ParentTable.TableName;
  441. string cTable = MyRelation.ChildTable.TableName;
  442. DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
  443. DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
  444. int i = 0;
  445. foreach (DataColumn DC in MyRelation.ParentColumns) {
  446. P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
  447. i++;
  448. }
  449. i = 0;
  450. foreach (DataColumn DC in MyRelation.ChildColumns) {
  451. C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
  452. i++;
  453. }
  454. DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC, false);
  455. Copy.Relations.Add (cRel);
  456. }
  457. // Foreign Key constraints are not cloned in DataTable.Clone
  458. // so, these constraints should be cloned when copying the relations.
  459. foreach (DataTable table in this.Tables) {
  460. foreach (Constraint c in table.Constraints) {
  461. if (!(c is ForeignKeyConstraint)
  462. || Copy.Tables[table.TableName].Constraints.Contains (c.ConstraintName))
  463. continue;
  464. ForeignKeyConstraint fc = (ForeignKeyConstraint)c;
  465. DataTable parentTable = Copy.Tables [fc.RelatedTable.TableName];
  466. DataTable currTable = Copy.Tables [table.TableName];
  467. DataColumn[] parentCols = new DataColumn [fc.RelatedColumns.Length];
  468. DataColumn[] childCols = new DataColumn [fc.Columns.Length];
  469. for (int j=0; j < parentCols.Length; ++j)
  470. parentCols [j] = parentTable.Columns[fc.RelatedColumns[j].ColumnName];
  471. for (int j=0; j < childCols.Length; ++j)
  472. childCols [j] = currTable.Columns[fc.Columns[j].ColumnName];
  473. currTable.Constraints.Add (fc.ConstraintName, parentCols, childCols);
  474. }
  475. }
  476. }
  477. public DataSet GetChanges ()
  478. {
  479. return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
  480. }
  481. public DataSet GetChanges (DataRowState rowStates)
  482. {
  483. if (!HasChanges (rowStates))
  484. return null;
  485. DataSet copySet = Clone ();
  486. bool prev = copySet.EnforceConstraints;
  487. copySet.EnforceConstraints = false;
  488. Hashtable addedRows = new Hashtable ();
  489. for (int i = 0; i < Tables.Count; i++) {
  490. DataTable origTable = Tables [i];
  491. DataTable copyTable = copySet.Tables[origTable.TableName];
  492. for (int j = 0; j < origTable.Rows.Count; j++) {
  493. DataRow row = origTable.Rows [j];
  494. if (!row.IsRowChanged (rowStates)
  495. || addedRows.Contains (row))
  496. continue;
  497. AddChangedRow (addedRows, copyTable, row);
  498. }
  499. }
  500. copySet.EnforceConstraints = prev;
  501. return copySet;
  502. }
  503. private void AddChangedRow (Hashtable addedRows, DataTable copyTable, DataRow row)
  504. {
  505. if (addedRows.ContainsKey (row)) return;
  506. foreach (DataRelation relation in row.Table.ParentRelations) {
  507. DataRow parent = ( row.RowState != DataRowState.Deleted ?
  508. row.GetParentRow (relation) :
  509. row.GetParentRow (relation, DataRowVersion.Original)
  510. );
  511. if (parent == null)
  512. continue;
  513. // add the parent row
  514. DataTable parentCopyTable = copyTable.DataSet.Tables [parent.Table.TableName];
  515. AddChangedRow (addedRows, parentCopyTable, parent);
  516. }
  517. // add the current row
  518. DataRow newRow = copyTable.NewNotInitializedRow();
  519. copyTable.Rows.AddInternal(newRow);
  520. row.CopyValuesToRow (newRow);
  521. newRow.XmlRowID = row.XmlRowID;
  522. addedRows.Add (row, row);
  523. }
  524. #if NET_2_0
  525. [MonoTODO]
  526. public DataTableReader CreateDataReader (DataTable[] dataTables)
  527. {
  528. return new DataTableReader (dataTables);
  529. }
  530. [MonoTODO]
  531. public DataTableReader CreateDataReader ()
  532. {
  533. return new DataTableReader ((DataTable[])Tables.ToArray (typeof (DataTable)));
  534. }
  535. #endif
  536. public string GetXml ()
  537. {
  538. StringWriter Writer = new StringWriter ();
  539. WriteXml (Writer, XmlWriteMode.IgnoreSchema);
  540. return Writer.ToString ();
  541. }
  542. public string GetXmlSchema ()
  543. {
  544. StringWriter Writer = new StringWriter ();
  545. WriteXmlSchema (Writer);
  546. return Writer.ToString ();
  547. }
  548. [MonoTODO]
  549. public bool HasChanges ()
  550. {
  551. return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
  552. }
  553. [MonoTODO]
  554. public bool HasChanges (DataRowState rowState)
  555. {
  556. if (((int)rowState & 0xffffffe0) != 0)
  557. throw new ArgumentOutOfRangeException ("rowState");
  558. DataTableCollection tableCollection = Tables;
  559. DataTable table;
  560. DataRowCollection rowCollection;
  561. DataRow row;
  562. for (int i = 0; i < tableCollection.Count; i++) {
  563. table = tableCollection[i];
  564. rowCollection = table.Rows;
  565. for (int j = 0; j < rowCollection.Count; j++) {
  566. row = rowCollection[j];
  567. if ((row.RowState & rowState) != 0)
  568. return true;
  569. }
  570. }
  571. return false;
  572. }
  573. public void InferXmlSchema (XmlReader reader, string[] nsArray)
  574. {
  575. if (reader == null)
  576. return;
  577. XmlDocument doc = new XmlDocument ();
  578. doc.Load (reader);
  579. InferXmlSchema (doc, nsArray);
  580. }
  581. private void InferXmlSchema (XmlDocument doc, string [] nsArray)
  582. {
  583. XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, nsArray);
  584. }
  585. public void InferXmlSchema (Stream stream, string[] nsArray)
  586. {
  587. InferXmlSchema (new XmlTextReader (stream), nsArray);
  588. }
  589. public void InferXmlSchema (TextReader reader, string[] nsArray)
  590. {
  591. InferXmlSchema (new XmlTextReader (reader), nsArray);
  592. }
  593. public void InferXmlSchema (string fileName, string[] nsArray)
  594. {
  595. XmlTextReader reader = new XmlTextReader (fileName);
  596. try {
  597. InferXmlSchema (reader, nsArray);
  598. } finally {
  599. reader.Close ();
  600. }
  601. }
  602. #if NET_2_0
  603. [MonoTODO]
  604. public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
  605. {
  606. throw new NotImplementedException ();
  607. }
  608. [MonoTODO]
  609. public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
  610. {
  611. throw new NotImplementedException ();
  612. }
  613. #endif
  614. public virtual void RejectChanges ()
  615. {
  616. int i;
  617. bool oldEnforceConstraints = this.EnforceConstraints;
  618. this.EnforceConstraints = false;
  619. for (i = 0; i < this.Tables.Count;i++)
  620. this.Tables[i].RejectChanges ();
  621. this.EnforceConstraints = oldEnforceConstraints;
  622. }
  623. public virtual void Reset ()
  624. {
  625. IEnumerator constraintEnumerator;
  626. // first we remove all ForeignKeyConstraints (if we will not do that
  627. // we will get an exception when clearing the tables).
  628. for (int i = 0; i < Tables.Count; i++) {
  629. ConstraintCollection cc = Tables[i].Constraints;
  630. for (int j = 0; j < cc.Count; j++) {
  631. if (cc[j] is ForeignKeyConstraint)
  632. cc.Remove (cc[j]);
  633. }
  634. }
  635. Clear ();
  636. Relations.Clear ();
  637. Tables.Clear ();
  638. }
  639. public void WriteXml (Stream stream)
  640. {
  641. XmlTextWriter writer = new XmlTextWriter (stream, null);
  642. writer.Formatting = Formatting.Indented;
  643. WriteXml (writer);
  644. }
  645. ///<summary>
  646. /// Writes the current data for the DataSet to the specified file.
  647. /// </summary>
  648. /// <param name="filename">Fully qualified filename to write to</param>
  649. public void WriteXml (string fileName)
  650. {
  651. XmlTextWriter writer = new XmlTextWriter (fileName, null);
  652. writer.Formatting = Formatting.Indented;
  653. writer.WriteStartDocument (true);
  654. try {
  655. WriteXml (writer);
  656. }
  657. finally {
  658. writer.WriteEndDocument ();
  659. writer.Close ();
  660. }
  661. }
  662. public void WriteXml (TextWriter writer)
  663. {
  664. XmlTextWriter xwriter = new XmlTextWriter (writer);
  665. xwriter.Formatting = Formatting.Indented;
  666. WriteXml (xwriter);
  667. }
  668. public void WriteXml (XmlWriter writer)
  669. {
  670. WriteXml (writer, XmlWriteMode.IgnoreSchema);
  671. }
  672. public void WriteXml (string filename, XmlWriteMode mode)
  673. {
  674. XmlTextWriter writer = new XmlTextWriter (filename, null);
  675. writer.Formatting = Formatting.Indented;
  676. writer.WriteStartDocument (true);
  677. try {
  678. WriteXml (writer, mode);
  679. }
  680. finally {
  681. writer.WriteEndDocument ();
  682. writer.Close ();
  683. }
  684. }
  685. public void WriteXml (Stream stream, XmlWriteMode mode)
  686. {
  687. XmlTextWriter writer = new XmlTextWriter (stream, null);
  688. writer.Formatting = Formatting.Indented;
  689. WriteXml (writer, mode);
  690. }
  691. public void WriteXml (TextWriter writer, XmlWriteMode mode)
  692. {
  693. XmlTextWriter xwriter = new XmlTextWriter (writer);
  694. xwriter.Formatting = Formatting.Indented;
  695. WriteXml (xwriter, mode);
  696. }
  697. public void WriteXml (XmlWriter writer, XmlWriteMode mode)
  698. {
  699. if (mode == XmlWriteMode.DiffGram) {
  700. SetRowsID();
  701. WriteDiffGramElement(writer);
  702. }
  703. // It should not write when there is no content to be written
  704. bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
  705. for (int n = 0; n < tableCollection.Count && !shouldOutputContent; n++)
  706. shouldOutputContent = tableCollection [n].Rows.Count > 0;
  707. if (shouldOutputContent) {
  708. WriteStartElement (writer, mode, Namespace, Prefix, XmlHelper.Encode (DataSetName));
  709. if (mode == XmlWriteMode.WriteSchema)
  710. DoWriteXmlSchema (writer);
  711. WriteTables (writer, mode, Tables, DataRowVersion.Default);
  712. writer.WriteEndElement ();
  713. }
  714. if (mode == XmlWriteMode.DiffGram) {
  715. if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
  716. DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
  717. WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
  718. WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
  719. writer.WriteEndElement ();
  720. }
  721. }
  722. if (mode == XmlWriteMode.DiffGram)
  723. writer.WriteEndElement (); // diffgr:diffgram
  724. writer.Flush ();
  725. }
  726. public void WriteXmlSchema (Stream stream)
  727. {
  728. XmlTextWriter writer = new XmlTextWriter (stream, null );
  729. writer.Formatting = Formatting.Indented;
  730. WriteXmlSchema (writer);
  731. }
  732. public void WriteXmlSchema (string fileName)
  733. {
  734. XmlTextWriter writer = new XmlTextWriter (fileName, null);
  735. try {
  736. writer.Formatting = Formatting.Indented;
  737. writer.WriteStartDocument (true);
  738. WriteXmlSchema (writer);
  739. } finally {
  740. writer.WriteEndDocument ();
  741. writer.Close ();
  742. }
  743. }
  744. public void WriteXmlSchema (TextWriter writer)
  745. {
  746. XmlTextWriter xwriter = new XmlTextWriter (writer);
  747. try {
  748. xwriter.Formatting = Formatting.Indented;
  749. WriteXmlSchema (xwriter);
  750. } finally {
  751. xwriter.Close ();
  752. }
  753. }
  754. public void WriteXmlSchema (XmlWriter writer)
  755. {
  756. //Create a skeleton doc and then write the schema
  757. //proper which is common to the WriteXml method in schema mode
  758. DoWriteXmlSchema (writer);
  759. }
  760. public void ReadXmlSchema (Stream stream)
  761. {
  762. XmlReader reader = new XmlTextReader (stream, null);
  763. ReadXmlSchema (reader);
  764. }
  765. public void ReadXmlSchema (string str)
  766. {
  767. XmlReader reader = new XmlTextReader (str);
  768. try {
  769. ReadXmlSchema (reader);
  770. }
  771. finally {
  772. reader.Close ();
  773. }
  774. }
  775. public void ReadXmlSchema (TextReader treader)
  776. {
  777. XmlReader reader = new XmlTextReader (treader);
  778. ReadXmlSchema (reader);
  779. }
  780. public void ReadXmlSchema (XmlReader reader)
  781. {
  782. #if true
  783. new XmlSchemaDataImporter (this, reader).Process ();
  784. #else
  785. XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
  786. SchemaMapper.Read (reader);
  787. #endif
  788. }
  789. public XmlReadMode ReadXml (Stream stream)
  790. {
  791. return ReadXml (new XmlTextReader (stream));
  792. }
  793. public XmlReadMode ReadXml (string str)
  794. {
  795. XmlTextReader reader = new XmlTextReader (str);
  796. try {
  797. return ReadXml (reader);
  798. }
  799. finally {
  800. reader.Close ();
  801. }
  802. }
  803. public XmlReadMode ReadXml (TextReader reader)
  804. {
  805. return ReadXml (new XmlTextReader (reader));
  806. }
  807. public XmlReadMode ReadXml (XmlReader r)
  808. {
  809. return ReadXml (r, XmlReadMode.Auto);
  810. }
  811. public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
  812. {
  813. return ReadXml (new XmlTextReader (stream), mode);
  814. }
  815. public XmlReadMode ReadXml (string str, XmlReadMode mode)
  816. {
  817. XmlTextReader reader = new XmlTextReader (str);
  818. try {
  819. return ReadXml (reader, mode);
  820. }
  821. finally {
  822. reader.Close ();
  823. }
  824. }
  825. public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
  826. {
  827. return ReadXml (new XmlTextReader (reader), mode);
  828. }
  829. // LAMESPEC: XmlReadMode.Fragment is far from presisely
  830. // documented. MS.NET infers schema against this mode.
  831. public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
  832. {
  833. if (reader == null)
  834. return mode;
  835. switch (reader.ReadState) {
  836. case ReadState.EndOfFile:
  837. case ReadState.Error:
  838. case ReadState.Closed:
  839. return mode;
  840. }
  841. // Skip XML declaration and prolog
  842. reader.MoveToContent ();
  843. if (reader.EOF)
  844. return mode;
  845. if (reader is XmlTextReader) {
  846. // we dont need whitespace
  847. ((XmlTextReader) reader).WhitespaceHandling = WhitespaceHandling.None;
  848. }
  849. XmlReadMode Result = mode;
  850. XmlDiffLoader DiffLoader = null;
  851. // If diffgram, then read the first element as diffgram
  852. if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
  853. switch (mode) {
  854. case XmlReadMode.Auto:
  855. case XmlReadMode.DiffGram:
  856. if (DiffLoader == null)
  857. DiffLoader = new XmlDiffLoader (this);
  858. DiffLoader.Load (reader);
  859. // (and leave rest of the reader as is)
  860. return XmlReadMode.DiffGram;
  861. case XmlReadMode.Fragment:
  862. reader.Skip ();
  863. // (and continue to read)
  864. break;
  865. default:
  866. reader.Skip ();
  867. // (and leave rest of the reader as is)
  868. return mode;
  869. }
  870. }
  871. // If schema, then read the first element as schema
  872. if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
  873. switch (mode) {
  874. case XmlReadMode.IgnoreSchema:
  875. case XmlReadMode.InferSchema:
  876. reader.Skip ();
  877. // (and break up read)
  878. return mode;
  879. case XmlReadMode.Fragment:
  880. ReadXmlSchema (reader);
  881. // (and continue to read)
  882. break;
  883. case XmlReadMode.Auto:
  884. if (Tables.Count == 0) {
  885. ReadXmlSchema (reader);
  886. return XmlReadMode.ReadSchema;
  887. } else {
  888. // otherwise just ignore and return IgnoreSchema
  889. reader.Skip ();
  890. return XmlReadMode.IgnoreSchema;
  891. }
  892. default:
  893. ReadXmlSchema (reader);
  894. // (and leave rest of the reader as is)
  895. return mode; // When DiffGram, return DiffGram
  896. }
  897. }
  898. if (reader.EOF)
  899. return mode;
  900. int depth = (reader.NodeType == XmlNodeType.Element) ? reader.Depth : -1;
  901. XmlDocument doc = new XmlDocument ();
  902. XmlElement root = doc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
  903. if (reader.HasAttributes) {
  904. for (int i = 0; i < reader.AttributeCount; i++) {
  905. reader.MoveToAttribute(i);
  906. if (reader.NamespaceURI == XmlConstants.XmlnsNS)
  907. root.SetAttribute(reader.Name, reader.GetAttribute(i));
  908. else {
  909. XmlAttribute attr = root.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
  910. attr.Prefix = reader.Prefix;
  911. attr.Value = reader.GetAttribute(i);
  912. }
  913. }
  914. }
  915. reader.Read();
  916. XmlReadMode retMode = mode;
  917. bool schemaLoaded = false;
  918. for (;;) {
  919. if( reader.Depth == depth ||
  920. reader.NodeType == XmlNodeType.EndElement)
  921. break;
  922. if (reader.NodeType != XmlNodeType.Element) {
  923. if (!reader.Read())
  924. break;
  925. continue;
  926. }
  927. if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
  928. switch (mode) {
  929. case XmlReadMode.IgnoreSchema:
  930. case XmlReadMode.InferSchema:
  931. reader.Skip ();
  932. break;
  933. default:
  934. ReadXmlSchema (reader);
  935. retMode = XmlReadMode.ReadSchema;
  936. schemaLoaded = true;
  937. // (and leave rest of the reader as is)
  938. break;
  939. }
  940. continue;
  941. }
  942. if ((reader.LocalName == "diffgram") && (reader.NamespaceURI == XmlConstants.DiffgrNamespace)) {
  943. if ((mode == XmlReadMode.DiffGram) || (mode == XmlReadMode.IgnoreSchema)
  944. || mode == XmlReadMode.Auto) {
  945. if (DiffLoader == null)
  946. DiffLoader = new XmlDiffLoader (this);
  947. DiffLoader.Load (reader);
  948. // (and leave rest of the reader as is)
  949. retMode = XmlReadMode.DiffGram;
  950. }
  951. else
  952. reader.Skip();
  953. continue;
  954. }
  955. //collect data
  956. XmlNode n = doc.ReadNode(reader);
  957. root.AppendChild(n);
  958. }
  959. if (reader.NodeType == XmlNodeType.EndElement)
  960. reader.Read ();
  961. reader.MoveToContent();
  962. if (mode == XmlReadMode.DiffGram) {
  963. return retMode;
  964. }
  965. doc.AppendChild(root);
  966. if (!schemaLoaded &&
  967. retMode != XmlReadMode.ReadSchema &&
  968. mode != XmlReadMode.IgnoreSchema &&
  969. mode != XmlReadMode.Fragment &&
  970. Tables.Count == 0) {
  971. InferXmlSchema(doc, null);
  972. if (mode == XmlReadMode.Auto)
  973. retMode = XmlReadMode.InferSchema;
  974. }
  975. reader = new XmlNodeReader (doc);
  976. XmlDataReader.ReadXml (this, reader, mode);
  977. return retMode == XmlReadMode.Auto ?
  978. XmlReadMode.IgnoreSchema : retMode;
  979. }
  980. #endregion // Public Methods
  981. #region Public Events
  982. [DataCategory ("Action")]
  983. #if !NET_2_0
  984. [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
  985. #endif
  986. public event MergeFailedEventHandler MergeFailed;
  987. #endregion // Public Events
  988. #region IListSource methods
  989. IList IListSource.GetList ()
  990. {
  991. return DefaultViewManager;
  992. }
  993. bool IListSource.ContainsListCollection {
  994. get {
  995. return true;
  996. }
  997. }
  998. #endregion IListSource methods
  999. #region ISupportInitialize methods
  1000. internal bool InitInProgress {
  1001. get { return initInProgress; }
  1002. set { initInProgress = value; }
  1003. }
  1004. public void BeginInit ()
  1005. {
  1006. InitInProgress = true;
  1007. }
  1008. public void EndInit ()
  1009. {
  1010. // Finsh the init'ing the tables only after adding all the
  1011. // tables to the collection.
  1012. Tables.PostAddRange ();
  1013. for (int i=0; i < Tables.Count; ++i) {
  1014. if (!Tables [i].InitInProgress)
  1015. continue;
  1016. Tables [i].FinishInit ();
  1017. }
  1018. Relations.PostAddRange ();
  1019. InitInProgress = false;
  1020. }
  1021. #endregion
  1022. #region ISerializable
  1023. void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
  1024. {
  1025. StringWriter sw = new StringWriter ();
  1026. XmlTextWriter writer = new XmlTextWriter (sw);
  1027. DoWriteXmlSchema (writer);
  1028. writer.Flush ();
  1029. si.AddValue ("XmlSchema", sw.ToString ());
  1030. sw = new StringWriter ();
  1031. writer = new XmlTextWriter (sw);
  1032. WriteXml (writer, XmlWriteMode.DiffGram);
  1033. writer.Flush ();
  1034. si.AddValue ("XmlDiffGram", sw.ToString ());
  1035. }
  1036. #endregion
  1037. #region Protected Methods
  1038. protected void GetSerializationData (SerializationInfo info, StreamingContext context)
  1039. {
  1040. string s = info.GetValue ("XmlSchema", typeof (String)) as String;
  1041. XmlTextReader reader = new XmlTextReader (new StringReader (s));
  1042. ReadXmlSchema (reader);
  1043. reader.Close ();
  1044. s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
  1045. reader = new XmlTextReader (new StringReader (s));
  1046. ReadXml (reader, XmlReadMode.DiffGram);
  1047. reader.Close ();
  1048. }
  1049. protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
  1050. {
  1051. return null;
  1052. }
  1053. protected virtual void ReadXmlSerializable (XmlReader reader)
  1054. {
  1055. ReadXml (reader, XmlReadMode.DiffGram);
  1056. }
  1057. void IXmlSerializable.ReadXml (XmlReader reader)
  1058. {
  1059. ReadXmlSerializable(reader);
  1060. }
  1061. void IXmlSerializable.WriteXml (XmlWriter writer)
  1062. {
  1063. DoWriteXmlSchema (writer);
  1064. WriteXml (writer, XmlWriteMode.DiffGram);
  1065. }
  1066. XmlSchema IXmlSerializable.GetSchema ()
  1067. {
  1068. if (GetType() == typeof(DataSet))
  1069. return null;
  1070. MemoryStream stream = new MemoryStream();
  1071. XmlTextWriter writer = new XmlTextWriter(stream, null);
  1072. WriteXmlSchema(writer);
  1073. stream.Position = 0;
  1074. return XmlSchema.Read(new XmlTextReader(stream), (ValidationEventHandler)null);
  1075. }
  1076. protected virtual bool ShouldSerializeRelations ()
  1077. {
  1078. return true;
  1079. }
  1080. protected virtual bool ShouldSerializeTables ()
  1081. {
  1082. return true;
  1083. }
  1084. [MonoTODO]
  1085. protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
  1086. {
  1087. }
  1088. [MonoTODO]
  1089. protected virtual void OnRemoveRelation (DataRelation relation)
  1090. {
  1091. }
  1092. [MonoTODO]
  1093. protected virtual void OnRemoveTable (DataTable table)
  1094. {
  1095. }
  1096. internal virtual void OnMergeFailed (MergeFailedEventArgs e)
  1097. {
  1098. if (MergeFailed != null)
  1099. MergeFailed (this, e);
  1100. else
  1101. throw new DataException (e.Conflict);
  1102. }
  1103. [MonoTODO]
  1104. protected internal void RaisePropertyChanging (string name)
  1105. {
  1106. }
  1107. #if NET_2_0
  1108. [MonoTODO]
  1109. protected SchemaSerializationMode DetermineSchemaSerializationMode (XmlReader reader)
  1110. {
  1111. return SchemaSerializationMode.IncludeSchema;
  1112. }
  1113. [MonoTODO]
  1114. protected SchemaSerializationMode DetermineSchemaSerializationMode (SerializationInfo info, StreamingContext context)
  1115. {
  1116. return SchemaSerializationMode.IncludeSchema;
  1117. }
  1118. [MonoTODO]
  1119. protected bool IsBinarySerialized (SerializationInfo info, StreamingContext context)
  1120. {
  1121. return false;
  1122. }
  1123. #endif
  1124. #endregion
  1125. #region Private Methods
  1126. internal static string WriteObjectXml (object o)
  1127. {
  1128. switch (Type.GetTypeCode (o.GetType ())) {
  1129. case TypeCode.Boolean:
  1130. return XmlConvert.ToString ((Boolean) o);
  1131. case TypeCode.Byte:
  1132. return XmlConvert.ToString ((Byte) o);
  1133. case TypeCode.Char:
  1134. return XmlConvert.ToString ((Char) o);
  1135. case TypeCode.DateTime:
  1136. return XmlConvert.ToString ((DateTime) o);
  1137. case TypeCode.Decimal:
  1138. return XmlConvert.ToString ((Decimal) o);
  1139. case TypeCode.Double:
  1140. return XmlConvert.ToString ((Double) o);
  1141. case TypeCode.Int16:
  1142. return XmlConvert.ToString ((Int16) o);
  1143. case TypeCode.Int32:
  1144. return XmlConvert.ToString ((Int32) o);
  1145. case TypeCode.Int64:
  1146. return XmlConvert.ToString ((Int64) o);
  1147. case TypeCode.SByte:
  1148. return XmlConvert.ToString ((SByte) o);
  1149. case TypeCode.Single:
  1150. return XmlConvert.ToString ((Single) o);
  1151. case TypeCode.UInt16:
  1152. return XmlConvert.ToString ((UInt16) o);
  1153. case TypeCode.UInt32:
  1154. return XmlConvert.ToString ((UInt32) o);
  1155. case TypeCode.UInt64:
  1156. return XmlConvert.ToString ((UInt64) o);
  1157. }
  1158. if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
  1159. if (o is Guid) return XmlConvert.ToString ((Guid) o);
  1160. if (o is byte[]) return Convert.ToBase64String ((byte[])o);
  1161. return o.ToString ();
  1162. }
  1163. private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
  1164. {
  1165. //WriteTable takes care of skipping a table if it has a
  1166. //Nested Parent Relationship
  1167. foreach (DataTable table in tableCollection)
  1168. WriteTable ( writer, table, mode, version);
  1169. }
  1170. private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
  1171. {
  1172. DataRow[] rows = table.NewRowArray(table.Rows.Count);
  1173. table.Rows.CopyTo (rows, 0);
  1174. WriteTable (writer, rows, mode, version, true);
  1175. }
  1176. private void WriteTable (XmlWriter writer,
  1177. DataRow [] rows,
  1178. XmlWriteMode mode,
  1179. DataRowVersion version, bool skipIfNested)
  1180. {
  1181. //The columns can be attributes, hidden, elements, or simple content
  1182. //There can be 0-1 simple content cols or 0-* elements
  1183. System.Collections.ArrayList atts;
  1184. System.Collections.ArrayList elements;
  1185. DataColumn simple = null;
  1186. if (rows.Length == 0) return;
  1187. DataTable table = rows[0].Table;
  1188. SplitColumns (table, out atts, out elements, out simple);
  1189. //sort out the namespacing
  1190. string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
  1191. int relationCount = table.ParentRelations.Count;
  1192. DataRelation oneRel = relationCount == 1 ? table.ParentRelations [0] : null;
  1193. foreach (DataRow row in rows) {
  1194. if (skipIfNested) {
  1195. // Skip rows that is a child of any tables.
  1196. bool skip = false;
  1197. for (int i = 0; i < table.ParentRelations.Count; i++) {
  1198. DataRelation prel = table.ParentRelations [i];
  1199. if (!prel.Nested)
  1200. continue;
  1201. if (row.GetParentRow (prel) != null) {
  1202. skip = true;
  1203. continue;
  1204. }
  1205. }
  1206. if (skip)
  1207. continue;
  1208. }
  1209. if (!row.HasVersion(version) ||
  1210. (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
  1211. && version == DataRowVersion.Original))
  1212. continue;
  1213. // First check are all the rows null. If they are we just write empty element
  1214. bool AllNulls = true;
  1215. foreach (DataColumn dc in table.Columns) {
  1216. if (row [dc.ColumnName, version] != DBNull.Value) {
  1217. AllNulls = false;
  1218. break;
  1219. }
  1220. }
  1221. // If all of the columns were null, we have to write empty element
  1222. if (AllNulls) {
  1223. writer.WriteElementString (XmlHelper.Encode (table.TableName), "");
  1224. continue;
  1225. }
  1226. WriteTableElement (writer, mode, table, row, version);
  1227. foreach (DataColumn col in atts) {
  1228. WriteColumnAsAttribute (writer, mode, col, row, version);
  1229. }
  1230. if (simple != null) {
  1231. writer.WriteString (WriteObjectXml (row[simple, version]));
  1232. }
  1233. else {
  1234. foreach (DataColumn col in elements) {
  1235. WriteColumnAsElement (writer, mode, col, row, version);
  1236. }
  1237. }
  1238. foreach (DataRelation relation in table.ChildRelations) {
  1239. if (relation.Nested) {
  1240. WriteTable (writer, row.GetChildRows (relation), mode, version, false);
  1241. }
  1242. }
  1243. writer.WriteEndElement ();
  1244. }
  1245. }
  1246. private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
  1247. {
  1248. string colnspc = null;
  1249. object rowObject = row [col, version];
  1250. if (rowObject == null || rowObject == DBNull.Value)
  1251. return;
  1252. if (col.Namespace != String.Empty)
  1253. colnspc = col.Namespace;
  1254. //TODO check if I can get away with write element string
  1255. WriteStartElement (writer, mode, colnspc, col.Prefix, XmlHelper.Encode (col.ColumnName));
  1256. writer.WriteString (WriteObjectXml (rowObject));
  1257. writer.WriteEndElement ();
  1258. }
  1259. private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
  1260. {
  1261. if (!row.IsNull (col))
  1262. WriteAttributeString (writer, mode, col.Namespace, col.Prefix, XmlHelper.Encode (col.ColumnName), WriteObjectXml (row[col, version]));
  1263. }
  1264. private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
  1265. {
  1266. //sort out the namespacing
  1267. string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
  1268. WriteStartElement (writer, mode, nspc, table.Prefix, XmlHelper.Encode (table.TableName));
  1269. if (mode == XmlWriteMode.DiffGram) {
  1270. WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
  1271. WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", XmlConvert.ToString (row.XmlRowID));
  1272. string modeName = null;
  1273. if (row.RowState == DataRowState.Modified)
  1274. modeName = "modified";
  1275. else if (row.RowState == DataRowState.Added)
  1276. modeName = "inserted";
  1277. if (version != DataRowVersion.Original && modeName != null)
  1278. WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
  1279. }
  1280. }
  1281. private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
  1282. {
  1283. writer.WriteStartElement (prefix, name, nspc);
  1284. }
  1285. private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
  1286. {
  1287. switch ( mode) {
  1288. case XmlWriteMode.WriteSchema:
  1289. writer.WriteAttributeString (prefix, name, nspc);
  1290. break;
  1291. case XmlWriteMode.DiffGram:
  1292. writer.WriteAttributeString (prefix, name, nspc,stringValue);
  1293. break;
  1294. default:
  1295. writer.WriteAttributeString (name, stringValue);
  1296. break;
  1297. };
  1298. }
  1299. internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
  1300. {
  1301. if (mode == XmlWriteMode.DiffGram) {
  1302. SetTableRowsID (table);
  1303. WriteDiffGramElement (writer);
  1304. }
  1305. WriteStartElement (writer, mode, Namespace, Prefix, XmlHelper.Encode (DataSetName));
  1306. WriteTable (writer, table, mode, DataRowVersion.Default);
  1307. if (mode == XmlWriteMode.DiffGram) {
  1308. writer.WriteEndElement (); //DataSet name
  1309. if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
  1310. DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
  1311. WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
  1312. WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
  1313. writer.WriteEndElement ();
  1314. }
  1315. }
  1316. writer.WriteEndElement (); // DataSet name or diffgr:diffgram
  1317. }
  1318. private void DoWriteXmlSchema (XmlWriter writer)
  1319. {
  1320. if (writer.WriteState == WriteState.Start)
  1321. writer.WriteStartDocument ();
  1322. XmlSchemaWriter.WriteXmlSchema (this, writer);
  1323. }
  1324. ///<summary>
  1325. /// Helper function to split columns into attributes elements and simple
  1326. /// content
  1327. /// </summary>
  1328. internal static void SplitColumns (DataTable table,
  1329. out ArrayList atts,
  1330. out ArrayList elements,
  1331. out DataColumn simple)
  1332. {
  1333. //The columns can be attributes, hidden, elements, or simple content
  1334. //There can be 0-1 simple content cols or 0-* elements
  1335. atts = new System.Collections.ArrayList ();
  1336. elements = new System.Collections.ArrayList ();
  1337. simple = null;
  1338. //Sort out the columns
  1339. foreach (DataColumn col in table.Columns) {
  1340. switch (col.ColumnMapping) {
  1341. case MappingType.Attribute:
  1342. atts.Add (col);
  1343. break;
  1344. case MappingType.Element:
  1345. elements.Add (col);
  1346. break;
  1347. case MappingType.SimpleContent:
  1348. if (simple != null) {
  1349. throw new System.InvalidOperationException ("There may only be one simple content element");
  1350. }
  1351. simple = col;
  1352. break;
  1353. default:
  1354. //ignore Hidden elements
  1355. break;
  1356. }
  1357. }
  1358. }
  1359. private void WriteDiffGramElement(XmlWriter writer)
  1360. {
  1361. WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
  1362. WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
  1363. }
  1364. private void SetRowsID()
  1365. {
  1366. foreach (DataTable Table in Tables)
  1367. SetTableRowsID (Table);
  1368. }
  1369. private void SetTableRowsID (DataTable Table)
  1370. {
  1371. int dataRowID = 0;
  1372. foreach (DataRow Row in Table.Rows) {
  1373. Row.XmlRowID = dataRowID;
  1374. dataRowID++;
  1375. }
  1376. }
  1377. #endregion //Private Xml Serialisation
  1378. }
  1379. }