This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / System.Data / System.Data / DataSet.cs
1 // 
2 // System.Data/DataSet.cs
3 //
4 // Author:
5 //   Christopher Podurgiel <cpodurgiel@msn.com>
6 //   Daniel Morgan <danmorg@sc.rr.com>
7 //   Rodrigo Moya <rodrigo@ximian.com>
8 //   Stuart Caborn <stuart.caborn@virgin.net>
9 //   Tim Coleman (tim@timcoleman.com)
10 //   Ville Palo <vi64pa@koti.soon.fi>
11 //   Atsushi Enomoto <atsushi@ximian.com>
12 //
13 // (C) Ximian, Inc. 2002
14 // Copyright (C) Tim Coleman, 2002, 2003
15 //
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
40 using System;
41 using System.Collections;
42 using System.ComponentModel;
43 using System.Globalization;
44 using System.Threading;
45 using System.IO;
46 using System.Runtime.Serialization;
47 using System.Xml;
48 using System.Xml.Schema;
49 using System.Xml.Serialization;
50 using System.Data.Common;
51
52 namespace System.Data {
53
54         [ToolboxItem (false)]
55         [DefaultProperty ("DataSetName")]
56         [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataSetDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
57
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                 
74                 #region Constructors
75
76                 public DataSet () : this ("NewDataSet") 
77                 {               
78                 }
79                 
80                 public DataSet (string name)
81                 {
82                         dataSetName = name;
83                         tableCollection = new DataTableCollection (this);
84                         relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
85                         properties = new PropertyCollection ();
86                         this.prefix = String.Empty;
87                         
88                         this.Locale = CultureInfo.CurrentCulture;
89                 }
90
91                 protected DataSet (SerializationInfo info, StreamingContext context) : this ()
92                 {
93                         GetSerializationData (info, context);
94                 }
95
96                 #endregion // Constructors
97
98                 #region Public Properties
99
100                 [DataCategory ("Data")]
101                 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
102                 [DefaultValue (false)]
103                 public bool CaseSensitive {
104                         get {
105                                 return caseSensitive;
106                         } 
107                         set {
108                                 caseSensitive = value; 
109                                 if (!caseSensitive) {
110                                         foreach (DataTable table in Tables) {
111                                                 foreach (Constraint c in table.Constraints)
112                                                         c.AssertConstraint ();
113                                         }
114                                 }
115                         }
116                 }
117
118                 [DataCategory ("Data")]
119                 [DataSysDescription ("The name of this DataSet.")]
120                 [DefaultValue ("")]
121                 public string DataSetName {
122                         get { return dataSetName; } 
123                         set { dataSetName = value; }
124                 }
125
126                 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
127                 [Browsable (false)]
128                 public DataViewManager DefaultViewManager {
129                         get {
130                                 if (defaultView == null)
131                                         defaultView = new DataViewManager (this);
132                                 return defaultView;
133                         } 
134                 }
135
136                 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
137                 [DefaultValue (true)]
138                 public bool EnforceConstraints {
139                         get { return enforceConstraints; } 
140                         set { 
141                                 if (value != enforceConstraints) {
142                                         enforceConstraints = value; 
143                                         if (value) {
144                                                 foreach (DataTable table in Tables) {
145                                                         // first assert all unique constraints
146                                                         foreach (UniqueConstraint uc in table.Constraints.UniqueConstraints)
147                                                                 uc.AssertConstraint ();
148                                                         // then assert all foreign keys
149                                                         foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
150                                                                 fk.AssertConstraint ();
151                                                 }
152                                         }
153                                 }
154                         }
155                 }
156
157                 [Browsable (false)]
158                 [DataCategory ("Data")]
159                 [DataSysDescription ("The collection that holds custom user information.")]
160                 public PropertyCollection ExtendedProperties {
161                         get { return properties; }
162                 }
163
164                 [Browsable (false)]
165                 [DataSysDescription ("Indicates that the DataSet has errors.")]
166                 public bool HasErrors {
167                         [MonoTODO]
168                         get {
169                                 for (int i = 0; i < Tables.Count; i++) {
170                                         if (Tables[i].HasErrors)
171                                                 return true;
172                                 }
173                                 return false;
174                         }
175                 }
176
177                 [DataCategory ("Data")]
178                 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
179                 public CultureInfo Locale {
180                         get {
181                                 return locale;
182                         }
183                         set {
184                                 if (locale == null || !locale.Equals (value)) {
185                                         // TODO: check if the new locale is valid
186                                         // TODO: update locale of all tables
187                                         locale = value;
188                                 }
189                         }
190                 }
191
192                 public void Merge (DataRow[] rows)
193                 {
194                         Merge (rows, false, MissingSchemaAction.Add);
195                 }
196                 
197                 public void Merge (DataSet dataSet)
198                 {
199                         Merge (dataSet, false, MissingSchemaAction.Add);
200                 }
201                 
202                 public void Merge (DataTable table)
203                 {
204                         Merge (table, false, MissingSchemaAction.Add);
205                 }
206                 
207                 public void Merge (DataSet dataSet, bool preserveChanges)
208                 {
209                         Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
210                 }
211                 
212                 [MonoTODO]
213                 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
214                 {
215                         if (rows == null)
216                                 throw new ArgumentNullException ("rows");
217                         if (!IsLegalSchemaAction (missingSchemaAction))
218                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
219                         
220                         MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
221                 }
222                 
223                 [MonoTODO]
224                 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
225                 {
226                         if (dataSet == null)
227                                 throw new ArgumentNullException ("dataSet");
228                         if (!IsLegalSchemaAction (missingSchemaAction))
229                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
230                         
231                         MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
232                 }
233                 
234                 [MonoTODO]
235                 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
236                 {
237                         if (table == null)
238                                 throw new ArgumentNullException ("table");
239                         if (!IsLegalSchemaAction (missingSchemaAction))
240                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
241                         
242                         MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
243                 }
244
245                 private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
246                 {
247                         if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
248                                 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
249                                 return true;
250                         return false;
251                 }
252                 
253                 [DataCategory ("Data")]
254                 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
255                 [DefaultValue ("")]
256                 public string Namespace {
257                         get { return _namespace; } 
258                         set {
259                                 //TODO - trigger an event if this happens?
260                                 if (value == null)
261                                         value = String.Empty;
262                                  if (value != this._namespace)
263                                         RaisePropertyChanging ("Namespace");
264                                 _namespace = value;
265                         }
266                 }
267
268                 [DataCategory ("Data")]
269                 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
270                 [DefaultValue ("")]
271                 public string Prefix {
272                         get { return prefix; } 
273                         set {
274                                 if (value == null)
275                                         value = String.Empty;
276                               // Prefix cannot contain any special characters other than '_' and ':'
277                                for (int i = 0; i < value.Length; i++) {
278                                        if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
279                                                throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
280                                }
281
282
283                                 if (value == null)
284                                         value = string.Empty;
285                                 
286                                 if (value != this.prefix) 
287                                         RaisePropertyChanging ("Prefix");
288                                 prefix = value;
289                         }
290                 }
291
292                 [DataCategory ("Data")]
293                 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
294                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
295                 public DataRelationCollection Relations {
296                         get {
297                                 return relationCollection;              
298                         }
299                 }
300
301                 [Browsable (false)]
302                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
303                 public override ISite Site {
304                         [MonoTODO]
305                         get {
306                                 throw new NotImplementedException ();
307                         } 
308                         
309                         [MonoTODO]
310                         set {
311                                 throw new NotImplementedException ();
312                         }
313                 }
314
315                 [DataCategory ("Data")]
316                 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
317                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
318                 public DataTableCollection Tables {
319                         get { return tableCollection; }
320                 }
321
322                 #endregion // Public Properties
323
324                 #region Public Methods
325
326                 [MonoTODO]
327                 public void AcceptChanges ()
328                 {
329                         foreach (DataTable tempTable in tableCollection)
330                                 tempTable.AcceptChanges ();
331                 }
332
333                 public void Clear ()
334                 {
335                         if (_xmlDataDocument != null)
336                                 throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
337                         for (int t = 0; t < tableCollection.Count; t++) {
338                                 tableCollection[t].Clear ();
339                         }
340                 }
341
342                 public virtual DataSet Clone ()
343                 {
344                         DataSet Copy = new DataSet ();
345                         CopyProperties (Copy);
346
347                         foreach (DataTable Table in Tables) {
348                                 Copy.Tables.Add (Table.Clone ());
349                         }
350
351                         //Copy Relationships between tables after existance of tables
352                         //and setting properties correctly
353                         CopyRelations (Copy);
354                         
355                         return Copy;
356                 }
357
358                 // Copies both the structure and data for this DataSet.
359                 public DataSet Copy ()
360                 {
361                         DataSet Copy = new DataSet ();
362                         CopyProperties (Copy);
363
364                         // Copy DatSet's tables
365                         foreach (DataTable Table in Tables) 
366                                 Copy.Tables.Add (Table.Copy ());
367
368                         //Copy Relationships between tables after existance of tables
369                         //and setting properties correctly
370                         CopyRelations (Copy);
371
372                         return Copy;
373                 }
374
375                 private void CopyProperties (DataSet Copy)
376                 {
377                         Copy.CaseSensitive = CaseSensitive;
378                         //Copy.Container = Container
379                         Copy.DataSetName = DataSetName;
380                         //Copy.DefaultViewManager
381                         //Copy.DesignMode
382                         Copy.EnforceConstraints = EnforceConstraints;
383                         if(ExtendedProperties.Count > 0) {
384                                 //  Cannot copy extended properties directly as the property does not have a set accessor
385                 Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
386                 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
387                 for (int i=0; i < ExtendedProperties.Count; i++)
388                                         Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
389                         }
390             Copy.Locale = Locale;
391                         Copy.Namespace = Namespace;
392                         Copy.Prefix = Prefix;                   
393                         //Copy.Site = Site; // FIXME : Not sure of this.
394
395                 }
396                 
397                 
398                 private void CopyRelations (DataSet Copy)
399                 {
400
401                         //Creation of the relation contains some of the properties, and the constructor
402                         //demands these values. instead changing the DataRelation constructor and behaviour the
403                         //parameters are pre-configured and sent to the most general constructor
404
405                         foreach (DataRelation MyRelation in this.Relations) {
406                                 string pTable = MyRelation.ParentTable.TableName;
407                                 string cTable = MyRelation.ChildTable.TableName;
408                                 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length]; 
409                                 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
410                                 int i = 0;
411                                 
412                                 foreach (DataColumn DC in MyRelation.ParentColumns) {
413                                         P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
414                                         i++;
415                                 }
416
417                                 i = 0;
418
419                                 foreach (DataColumn DC in MyRelation.ChildColumns) {
420                                         C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
421                                         i++;
422                                 }
423                                 
424                                 DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
425                                 //cRel.ChildColumns = MyRelation.ChildColumns;
426                                 //cRel.ChildTable = MyRelation.ChildTable;
427                                 //cRel.ExtendedProperties = cRel.ExtendedProperties; 
428                                 //cRel.Nested = MyRelation.Nested;
429                                 //cRel.ParentColumns = MyRelation.ParentColumns;
430                                 //cRel.ParentTable = MyRelation.ParentTable;
431                                                                 
432                                 Copy.Relations.Add (cRel);
433                         }
434                 }
435
436                 
437
438
439                 public DataSet GetChanges ()
440                 {
441                         return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
442                 }
443
444                 
445                 public DataSet GetChanges (DataRowState rowStates)
446                 {
447                         if (!HasChanges (rowStates))
448                                 return null;
449                         
450                         DataSet copySet = Clone ();
451                         Hashtable addedRows = new Hashtable ();
452
453                         IEnumerator tableEnumerator = Tables.GetEnumerator ();
454                         DataTable origTable;
455                         DataTable copyTable;
456                         while (tableEnumerator.MoveNext ()) {
457                                 origTable = (DataTable)tableEnumerator.Current;
458                                 copyTable = copySet.Tables[origTable.TableName];
459                                 
460                                 // Look for relations that have this table as child
461                                 IEnumerator relations = origTable.ParentRelations.GetEnumerator ();
462
463                                 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
464                                 while (rowEnumerator.MoveNext ()) {
465                                         DataRow row = (DataRow)rowEnumerator.Current;
466                                         
467                                         if (row.IsRowChanged (rowStates))
468                                                 AddChangedRow (addedRows, copySet, copyTable, relations, row);
469                                 }
470                         }
471                         return copySet;
472                 }
473                 
474                 void AddChangedRow (Hashtable addedRows, DataSet copySet, DataTable copyTable, IEnumerator relations, DataRow row)
475                 {
476                         if (addedRows.ContainsKey (row)) return;
477                         
478                         relations.Reset ();
479                         while (relations.MoveNext ()) {
480                                 DataRow parentRow = row.GetParentRow ((DataRelation) relations.Current);
481                                 if (parentRow == null || addedRows.ContainsKey (parentRow)) continue;
482                                 DataTable parentCopyTable = copySet.Tables [parentRow.Table.TableName];
483                                 AddChangedRow (addedRows, copySet, parentCopyTable, parentRow.Table.ParentRelations.GetEnumerator (), parentRow);
484                         }
485                 
486                         DataRow newRow = copyTable.NewRow ();
487                         copyTable.Rows.Add (newRow);
488                         row.CopyValuesToRow (newRow);
489                         newRow.XmlRowID = row.XmlRowID;
490                         addedRows.Add (row,row);
491                 }
492
493 #if NET_2_0
494                 [MonoTODO]
495                 public DataTableReader GetDataReader (DataTable[] dataTables)
496                 {
497                         throw new NotImplementedException ();
498                 }
499
500                 [MonoTODO]
501                 public DataTableReader GetDataReader ()
502                 {
503                         throw new NotImplementedException ();
504                 }
505 #endif
506                 
507                 public string GetXml ()
508                 {
509                         StringWriter Writer = new StringWriter ();
510                         WriteXml (Writer, XmlWriteMode.IgnoreSchema);
511                         return Writer.ToString ();
512                 }
513
514                 public string GetXmlSchema ()
515                 {
516                         StringWriter Writer = new StringWriter ();
517                         WriteXmlSchema (Writer);
518                         return Writer.ToString ();
519                 }
520
521                 [MonoTODO]
522                 public bool HasChanges ()
523                 {
524                         return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
525                 }
526
527                 [MonoTODO]
528                 public bool HasChanges (DataRowState rowState)
529                 {
530                         if (((int)rowState & 0xffffffe0) != 0)
531                                 throw new ArgumentOutOfRangeException ("rowState");
532
533                         DataTableCollection tableCollection = Tables;
534                         DataTable table;
535                         DataRowCollection rowCollection;
536                         DataRow row;
537
538                         for (int i = 0; i < tableCollection.Count; i++) {
539                                 table = tableCollection[i];
540                                 rowCollection = table.Rows;
541                                 for (int j = 0; j < rowCollection.Count; j++) {
542                                         row = rowCollection[j];
543                                         if ((row.RowState & rowState) != 0)
544                                                 return true;
545                                 }
546                         }
547
548                         return false;           
549                 }
550
551                 public void InferXmlSchema (XmlReader reader, string[] nsArray)
552                 {
553                         if (reader == null)
554                                 return;
555                         XmlDocument doc = new XmlDocument ();
556                         doc.Load (reader);
557                         InferXmlSchema (doc, nsArray);
558                 }
559
560                 private void InferXmlSchema (XmlDocument doc, string [] nsArray)
561                 {
562                         XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, nsArray);
563                 }
564
565                 public void InferXmlSchema (Stream stream, string[] nsArray)
566                 {
567                         InferXmlSchema (new XmlTextReader (stream), nsArray);
568                 }
569
570                 public void InferXmlSchema (TextReader reader, string[] nsArray)
571                 {
572                         InferXmlSchema (new XmlTextReader (reader), nsArray);
573                 }
574
575                 public void InferXmlSchema (string fileName, string[] nsArray)
576                 {
577                         XmlTextReader reader = new XmlTextReader (fileName);
578                         try {
579                                 InferXmlSchema (reader, nsArray);
580                         } finally {
581                                 reader.Close ();
582                         }
583                 }
584
585 #if NET_2_0
586                 [MonoTODO]
587                 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
588                 {
589                         throw new NotImplementedException ();
590                 }
591
592                 [MonoTODO]
593                 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
594                 {
595                         throw new NotImplementedException ();
596                 }
597 #endif
598
599                 public virtual void RejectChanges ()
600                 {
601                         int i;
602                         bool oldEnforceConstraints = this.EnforceConstraints;
603                         this.EnforceConstraints = false;
604                         
605                         for (i = 0; i < this.Tables.Count;i++) 
606                                 this.Tables[i].RejectChanges ();
607
608                         this.EnforceConstraints = oldEnforceConstraints;
609                 }
610
611                 public virtual void Reset ()
612                 {
613                         IEnumerator constraintEnumerator;
614
615                         // first we remove all ForeignKeyConstraints (if we will not do that
616                         // we will get an exception when clearing the tables).
617                         for (int i = 0; i < Tables.Count; i++) {
618                                 ConstraintCollection cc = Tables[i].Constraints;
619                                 for (int j = 0; j < cc.Count; j++) {
620                                         if (cc[j] is ForeignKeyConstraint)
621                                                 cc.Remove (cc[j]);
622                                 }
623                         }
624
625                         Clear ();
626                         Relations.Clear ();
627                         Tables.Clear ();
628                 }
629
630                 public void WriteXml (Stream stream)
631                 {
632                         XmlTextWriter writer = new XmlTextWriter (stream, null);
633                         writer.Formatting = Formatting.Indented;
634                         WriteXml (writer);
635                 }
636
637                 ///<summary>
638                 /// Writes the current data for the DataSet to the specified file.
639                 /// </summary>
640                 /// <param name="filename">Fully qualified filename to write to</param>
641                 public void WriteXml (string fileName)
642                 {
643                         XmlTextWriter writer = new XmlTextWriter (fileName, null);
644                         writer.Formatting = Formatting.Indented;
645                         writer.WriteStartDocument (true);
646                         try {
647                                 WriteXml (writer);
648                         }
649                         finally {
650                                 writer.WriteEndDocument ();
651                                 writer.Close ();
652                         }
653                 }
654
655                 public void WriteXml (TextWriter writer)
656                 {
657                         XmlTextWriter xwriter = new XmlTextWriter (writer);
658                         xwriter.Formatting = Formatting.Indented;
659                         WriteXml (xwriter);
660                 }
661
662                 public void WriteXml (XmlWriter writer)
663                 {
664                         WriteXml (writer, XmlWriteMode.IgnoreSchema);
665                 }
666
667                 public void WriteXml (string filename, XmlWriteMode mode)
668                 {
669                         XmlTextWriter writer = new XmlTextWriter (filename, null);
670                         writer.Formatting = Formatting.Indented;
671                         writer.WriteStartDocument (true);
672                         
673                         try {
674                                 WriteXml (writer, mode);
675                         }
676                         finally {
677                                 writer.WriteEndDocument ();
678                                 writer.Close ();
679                         }
680                 }
681
682                 public void WriteXml (Stream stream, XmlWriteMode mode)
683                 {
684                         XmlTextWriter writer = new XmlTextWriter (stream, null);
685                         writer.Formatting = Formatting.Indented;
686                         WriteXml (writer, mode);
687                 }
688
689                 public void WriteXml (TextWriter writer, XmlWriteMode mode)
690                 {
691                         XmlTextWriter xwriter = new XmlTextWriter (writer);
692                         xwriter.Formatting = Formatting.Indented;
693                         WriteXml (xwriter, mode);
694                 }
695
696                 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
697                 {
698                         if (mode == XmlWriteMode.DiffGram) {
699                                 SetRowsID();
700                                 WriteDiffGramElement(writer);
701                         }
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                                 
708                         if (shouldOutputContent) {
709                                 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
710                                 
711                                 if (mode == XmlWriteMode.WriteSchema)
712                                         DoWriteXmlSchema (writer);
713                                 
714                                 WriteTables (writer, mode, Tables, DataRowVersion.Default);
715                                 writer.WriteEndElement ();
716                         }
717                         
718                         if (mode == XmlWriteMode.DiffGram) {
719                                 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
720
721                                         DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
722                                         WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
723                                         WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
724                                         writer.WriteEndElement ();
725                                 }
726                         }
727                         
728                         if (mode == XmlWriteMode.DiffGram)
729                                 writer.WriteEndElement (); // diffgr:diffgram
730
731                         writer.Flush ();
732                 }
733
734                 public void WriteXmlSchema (Stream stream)
735                 {
736                         XmlTextWriter writer = new XmlTextWriter (stream, null );
737                         writer.Formatting = Formatting.Indented;
738                         WriteXmlSchema (writer);        
739                 }
740
741                 public void WriteXmlSchema (string fileName)
742                 {
743                         XmlTextWriter writer = new XmlTextWriter (fileName, null);
744                         try {
745                                 writer.Formatting = Formatting.Indented;
746                                 writer.WriteStartDocument (true);
747                                 WriteXmlSchema (writer);
748                         } finally {
749                                 writer.WriteEndDocument ();
750                                 writer.Close ();
751                         }
752                 }
753
754                 public void WriteXmlSchema (TextWriter writer)
755                 {
756                         XmlTextWriter xwriter = new XmlTextWriter (writer);
757                         try {
758                                 xwriter.Formatting = Formatting.Indented;
759 //                              xwriter.WriteStartDocument ();
760                                 WriteXmlSchema (xwriter);
761                         } finally {
762 //                              xwriter.WriteEndDocument ();
763                                 xwriter.Close ();
764                         }
765                 }
766
767                 public void WriteXmlSchema (XmlWriter writer)
768                 {
769                         //Create a skeleton doc and then write the schema 
770                         //proper which is common to the WriteXml method in schema mode
771                         DoWriteXmlSchema (writer);
772                 }
773
774                 public void ReadXmlSchema (Stream stream)
775                 {
776                         XmlReader reader = new XmlTextReader (stream, null);
777                         ReadXmlSchema (reader);
778                 }
779
780                 public void ReadXmlSchema (string str)
781                 {
782                         XmlReader reader = new XmlTextReader (str);
783                         try {
784                                 ReadXmlSchema (reader);
785                         }
786                         finally {
787                                 reader.Close ();
788                         }
789                 }
790
791                 public void ReadXmlSchema (TextReader treader)
792                 {
793                         XmlReader reader = new XmlTextReader (treader);
794                         ReadXmlSchema (reader);                 
795                 }
796
797                 public void ReadXmlSchema (XmlReader reader)
798                 {
799 #if true
800                         new XmlSchemaDataImporter (this, reader).Process ();
801 #else
802                         XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
803                         SchemaMapper.Read (reader);
804 #endif
805                 }
806
807                 public XmlReadMode ReadXml (Stream stream)
808                 {
809                         return ReadXml (new XmlTextReader (stream));
810                 }
811
812                 public XmlReadMode ReadXml (string str)
813                 {
814                         XmlTextReader reader = new XmlTextReader (str);
815                         try {
816                                 return ReadXml (reader);
817                         }
818                         finally {
819                                 reader.Close ();
820                         }
821                 }
822
823                 public XmlReadMode ReadXml (TextReader reader)
824                 {
825                         return ReadXml (new XmlTextReader (reader));
826                 }
827
828                 public XmlReadMode ReadXml (XmlReader r)
829                 {
830                         return ReadXml (r, XmlReadMode.Auto);
831                 }
832
833                 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
834                 {
835                         return ReadXml (new XmlTextReader (stream), mode);
836                 }
837
838                 public XmlReadMode ReadXml (string str, XmlReadMode mode)
839                 {
840                         XmlTextReader reader = new XmlTextReader (str);
841                         try {
842                                 return ReadXml (reader, mode);
843                         }
844                         finally {
845                                 reader.Close ();
846                         }
847                 }
848
849                 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
850                 {
851                         return ReadXml (new XmlTextReader (reader), mode);
852                 }
853
854                 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
855                 {
856                         switch (reader.ReadState) {
857                         case ReadState.EndOfFile:
858                         case ReadState.Error:
859                         case ReadState.Closed:
860                                 return mode;
861                         }
862                         // Skip XML declaration and prolog
863                         reader.MoveToContent();
864                         if (reader.EOF)
865                                 return mode;
866
867                         XmlReadMode Result = mode;
868
869                         // If diffgram, then read the first element as diffgram 
870                         if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
871                                 switch (mode) {
872                                 case XmlReadMode.Auto:
873                                 case XmlReadMode.DiffGram:
874                                         XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
875                                         DiffLoader.Load (reader);
876                                         // (and leave rest of the reader as is)
877                                         return  XmlReadMode.DiffGram;
878                                 case XmlReadMode.Fragment:
879                                         reader.Skip ();
880                                         // (and continue to read)
881                                         break;
882                                 default:
883                                         reader.Skip ();
884                                         // (and leave rest of the reader as is)
885                                         return mode;
886                                 }
887                         }
888                         // If schema, then read the first element as schema 
889                         if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
890                                 switch (mode) {
891                                 case XmlReadMode.IgnoreSchema:
892                                 case XmlReadMode.InferSchema:
893                                         reader.Skip ();
894                                         // (and break up read)
895                                         return mode;
896                                 case XmlReadMode.Fragment:
897                                         ReadXmlSchema (reader);
898                                         // (and continue to read)
899                                         break;
900                                 case XmlReadMode.Auto:
901                                         if (Tables.Count == 0) {
902                                                 ReadXmlSchema (reader);
903                                                 return XmlReadMode.ReadSchema;
904                                         } else {
905                                         // otherwise just ignore and return IgnoreSchema
906                                                 reader.Skip ();
907                                                 return XmlReadMode.IgnoreSchema;
908                                         }
909                                 default:
910                                         ReadXmlSchema (reader);
911                                         // (and leave rest of the reader as is)
912                                         return mode; // When DiffGram, return DiffGram
913                                 }
914                         }
915                         // Otherwise, read as dataset... but only when required.
916                         XmlReadMode explicitReturnMode = XmlReadMode.Auto;
917                         XmlDocument doc;
918                         switch (mode) {
919                         case XmlReadMode.Auto:
920                                 if (Tables.Count > 0)
921                                         goto case XmlReadMode.IgnoreSchema;
922                                 else
923                                         goto case XmlReadMode.InferSchema;
924                         case XmlReadMode.InferSchema:
925                                 doc = new XmlDocument ();
926                                 do {
927                                         doc.AppendChild (doc.ReadNode (reader));
928                                         reader.MoveToContent ();
929                                         if (doc.DocumentElement != null)
930                                                 break;
931                                 } while (!reader.EOF);
932                                 InferXmlSchema (doc, null);
933                                 reader = new XmlNodeReader (doc);
934                                 explicitReturnMode = XmlReadMode.InferSchema;
935                                 break;
936                         case XmlReadMode.ReadSchema:
937                                 doc = new XmlDocument ();
938                                 do {
939                                         doc.AppendChild (doc.ReadNode (reader));
940                                         reader.MoveToContent ();
941                                         if (doc.DocumentElement != null)
942                                                 break;
943                                 } while (!reader.EOF);
944                                 if (doc.DocumentElement != null) {
945                                         XmlElement schema = doc.DocumentElement ["schema", XmlSchema.Namespace] as XmlElement;
946                                         if (schema != null) {
947                                                 ReadXmlSchema (new XmlNodeReader (schema));
948                                                 explicitReturnMode = XmlReadMode.ReadSchema;
949                                         }
950                                 }
951                                 reader = new XmlNodeReader (doc);
952                                 break;
953                         case XmlReadMode.IgnoreSchema:
954                         case XmlReadMode.Fragment:
955                                 break;
956                         default:
957                                 reader.Skip ();
958                                 return mode;
959                         }
960
961                         XmlDataReader.ReadXml (this, reader, mode);
962                         if (explicitReturnMode != XmlReadMode.Auto)
963                                 return explicitReturnMode;
964                         return mode == XmlReadMode.Auto ? XmlReadMode.IgnoreSchema : mode;
965                 }
966                 #endregion // Public Methods
967
968                 #region Public Events
969
970                 [DataCategory ("Action")]
971                 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
972                 public event MergeFailedEventHandler MergeFailed;
973
974                 #endregion // Public Events
975
976                 #region IListSource methods
977                 IList IListSource.GetList ()
978                 {
979                         return DefaultViewManager;
980                 }
981                 
982                 bool IListSource.ContainsListCollection {
983                         get {
984                                 return true;
985                         }
986                 }
987                 #endregion IListSource methods
988                 
989                 #region ISupportInitialize methods
990                 public void BeginInit ()
991                 {
992                 }
993                 
994                 public void EndInit ()
995                 {
996                 }
997                 #endregion
998
999                 #region ISerializable
1000                 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
1001                 {
1002                         StringWriter sw = new StringWriter ();
1003                         XmlTextWriter writer = new XmlTextWriter (sw);
1004                         DoWriteXmlSchema (writer);
1005                         writer.Flush ();
1006                         si.AddValue ("XmlSchema", sw.ToString ());
1007                         
1008                         sw = new StringWriter ();
1009                         writer = new XmlTextWriter (sw);
1010                         WriteXml (writer, XmlWriteMode.DiffGram);
1011                         writer.Flush ();
1012                         si.AddValue ("XmlDiffGram", sw.ToString ());
1013                 }
1014                 #endregion
1015                 
1016                 #region Protected Methods
1017                 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
1018                 {
1019                         string s = info.GetValue ("XmlSchema", typeof (String)) as String;
1020                         XmlTextReader reader = new XmlTextReader (new StringReader (s));
1021                         ReadXmlSchema (reader);
1022                         reader.Close ();
1023                         
1024                         s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
1025                         reader = new XmlTextReader (new StringReader (s));
1026                         ReadXml (reader, XmlReadMode.DiffGram);
1027                         reader.Close ();
1028                 }
1029                 
1030                 
1031                 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
1032                 {
1033                         return null;
1034                 }
1035                 
1036                 protected virtual void ReadXmlSerializable (XmlReader reader)
1037                 {
1038                         reader.MoveToContent ();
1039                         reader.ReadStartElement ();
1040                         reader.MoveToContent ();
1041                         ReadXmlSchema (reader);
1042                         reader.MoveToContent ();
1043                         ReadXml (reader, XmlReadMode.DiffGram);
1044                         reader.MoveToContent ();
1045                         reader.ReadEndElement ();
1046                 }
1047
1048                 void IXmlSerializable.ReadXml (XmlReader reader)
1049                 {
1050                         ReadXmlSerializable(reader);
1051                 }
1052                 
1053                 void IXmlSerializable.WriteXml (XmlWriter writer)
1054                 {
1055                         DoWriteXmlSchema (writer);
1056                         WriteXml (writer, XmlWriteMode.DiffGram);
1057                 }
1058
1059                 XmlSchema IXmlSerializable.GetSchema ()
1060                 {
1061                         return BuildSchema ();
1062                 }
1063
1064                 protected virtual bool ShouldSerializeRelations ()
1065                 {
1066                         return true;
1067                 }
1068                 
1069                 protected virtual bool ShouldSerializeTables ()
1070                 {
1071                         return true;
1072                 }
1073
1074                 [MonoTODO]
1075                 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
1076                 {
1077                 }
1078
1079                 [MonoTODO]
1080                 protected virtual void OnRemoveRelation (DataRelation relation)
1081                 {
1082                 }
1083
1084                 [MonoTODO]
1085                 protected virtual void OnRemoveTable (DataTable table)
1086                 {
1087                 }
1088
1089                 internal virtual void OnMergeFailed (MergeFailedEventArgs e)
1090                 {
1091                         if (MergeFailed != null)
1092                                 MergeFailed (this, e);
1093                 }
1094
1095                 [MonoTODO]
1096                 protected internal void RaisePropertyChanging (string name)
1097                 {
1098                 }
1099                 #endregion
1100
1101                 #region Private Xml Serialisation
1102
1103                 private string WriteObjectXml (object o)
1104                 {
1105                         switch (Type.GetTypeCode (o.GetType ())) {
1106                                 case TypeCode.Boolean:
1107                                         return XmlConvert.ToString ((Boolean) o);
1108                                 case TypeCode.Byte:
1109                                         return XmlConvert.ToString ((Byte) o);
1110                                 case TypeCode.Char:
1111                                         return XmlConvert.ToString ((Char) o);
1112                                 case TypeCode.DateTime:
1113                                         return XmlConvert.ToString ((DateTime) o);
1114                                 case TypeCode.Decimal:
1115                                         return XmlConvert.ToString ((Decimal) o);
1116                                 case TypeCode.Double:
1117                                         return XmlConvert.ToString ((Double) o);
1118                                 case TypeCode.Int16:
1119                                         return XmlConvert.ToString ((Int16) o);
1120                                 case TypeCode.Int32:
1121                                         return XmlConvert.ToString ((Int32) o);
1122                                 case TypeCode.Int64:
1123                                         return XmlConvert.ToString ((Int64) o);
1124                                 case TypeCode.SByte:
1125                                         return XmlConvert.ToString ((SByte) o);
1126                                 case TypeCode.Single:
1127                                         return XmlConvert.ToString ((Single) o);
1128                                 case TypeCode.UInt16:
1129                                         return XmlConvert.ToString ((UInt16) o);
1130                                 case TypeCode.UInt32:
1131                                         return XmlConvert.ToString ((UInt32) o);
1132                                 case TypeCode.UInt64:
1133                                         return XmlConvert.ToString ((UInt64) o);
1134                         }
1135                         if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1136                         if (o is Guid) return XmlConvert.ToString ((Guid) o);
1137                         if (o is byte[]) return Convert.ToBase64String ((byte[])o);
1138                         return o.ToString ();
1139                 }
1140                 
1141                 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1142                 {
1143                         //Write out each table in order, providing it is not
1144                         //part of another table structure via a nested parent relationship
1145                         foreach (DataTable table in tableCollection) {
1146                                 bool isTopLevel = true;
1147                                 /*
1148                                 foreach (DataRelation rel in table.ParentRelations) {
1149                                         if (rel.Nested) {
1150                                                 isTopLevel = false;
1151                                                 break;
1152                                         }
1153                                 }
1154                                 */
1155                                 if (isTopLevel) {
1156                                         WriteTable ( writer, table, mode, version);
1157                                 }
1158                         }
1159                 }
1160
1161                 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1162                 {
1163                         DataRow[] rows = new DataRow [table.Rows.Count];
1164                         table.Rows.CopyTo (rows, 0);
1165                         WriteTable (writer, rows, mode, version, true);
1166                 }
1167
1168                 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version, bool skipIfNested)
1169                 {
1170                         //The columns can be attributes, hidden, elements, or simple content
1171                         //There can be 0-1 simple content cols or 0-* elements
1172                         System.Collections.ArrayList atts;
1173                         System.Collections.ArrayList elements;
1174                         DataColumn simple = null;
1175
1176                         if (rows.Length == 0) return;
1177                         DataTable table = rows[0].Table;
1178                         SplitColumns (table, out atts, out elements, out simple);
1179                         //sort out the namespacing
1180                         string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1181                         int relationCount = table.ParentRelations.Count;
1182                         DataRelation oneRel = relationCount == 1 ? table.ParentRelations [0] : null;
1183
1184                         foreach (DataRow row in rows) {
1185                                 if (skipIfNested) {
1186                                         // Skip rows that is a child of any tables.
1187                                         switch (relationCount) {
1188                                         case 0:
1189                                                 break;
1190                                         case 1:
1191                                                 if (row.GetParentRow (oneRel) != null)
1192                                                         continue;
1193                                                 break;
1194                                         case 2:
1195                                                 bool skip = false;
1196                                                 for (int i = 0; i < table.ParentRelations.Count; i++)
1197                                                         if (row.GetParentRow (table.ParentRelations [i]) != null) {
1198                                                                 skip = true;
1199                                                                 continue;
1200                                                         }
1201                                                 if (skip)
1202                                                         continue;
1203                                                 break;
1204                                         }
1205                                 }
1206
1207                                 if (!row.HasVersion(version) || 
1208                                    (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged 
1209                                       && version == DataRowVersion.Original))
1210                                         continue;
1211                                 
1212                                 // First check are all the rows null. If they are we just write empty element
1213                                 bool AllNulls = true;
1214                                 foreach (DataColumn dc in table.Columns) {
1215                                 
1216                                         if (row [dc.ColumnName, version] != DBNull.Value) {
1217                                                 AllNulls = false;
1218                                                 break;
1219                                         } 
1220                                 }
1221
1222                                 // If all of the columns were null, we have to write empty element
1223                                 if (AllNulls) {
1224                                         writer.WriteElementString (XmlConvert.EncodeLocalName (table.TableName), "");
1225                                         continue;
1226                                 }
1227                                 
1228                                 WriteTableElement (writer, mode, table, row, version);
1229                                 
1230                                 foreach (DataColumn col in atts) {                                      
1231                                         WriteColumnAsAttribute (writer, mode, col, row, version);
1232                                 }
1233                                 
1234                                 if (simple != null) {
1235                                         writer.WriteString (WriteObjectXml (row[simple, version]));
1236                                 }
1237                                 else {                                  
1238                                         foreach (DataColumn col in elements) {
1239                                                 WriteColumnAsElement (writer, mode, col, row, version);
1240                                         }
1241                                 }
1242                                 
1243                                 foreach (DataRelation relation in table.ChildRelations) {
1244                                         if (relation.Nested) {
1245                                                 WriteTable (writer, row.GetChildRows (relation), mode, version, false);
1246                                         }
1247                                 }
1248                                 
1249                                 writer.WriteEndElement ();
1250                         }
1251
1252                 }
1253
1254                 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1255                 {
1256                         string colnspc = null;
1257                         object rowObject = row [col, version];
1258                                                                         
1259                         if (rowObject == null || rowObject == DBNull.Value)
1260                                 return;
1261
1262                         if (col.Namespace != String.Empty)
1263                                 colnspc = col.Namespace;
1264         
1265                         //TODO check if I can get away with write element string
1266                         WriteStartElement (writer, mode, colnspc, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName));
1267                         writer.WriteString (WriteObjectXml (rowObject));
1268                         writer.WriteEndElement ();
1269                 }
1270
1271                 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1272                 {
1273                         WriteAttributeString (writer, mode, col.Namespace, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName), WriteObjectXml (row[col, version]));
1274                 }
1275
1276                 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1277                 {
1278                         //sort out the namespacing
1279                         string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1280
1281                         WriteStartElement (writer, mode, nspc, table.Prefix, XmlConvert.EncodeLocalName (table.TableName));
1282
1283                         if (mode == XmlWriteMode.DiffGram) {
1284                                 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
1285                                 WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", XmlConvert.ToString (row.XmlRowID));
1286                                 string modeName = null;
1287                                 if (row.RowState == DataRowState.Modified)
1288                                         modeName = "modified";
1289                                 else if (row.RowState == DataRowState.Added)
1290                                         modeName = "inserted";
1291
1292                                 if (version != DataRowVersion.Original && modeName != null)
1293                                         WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
1294                         }
1295                 }
1296                     
1297                 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1298                 {
1299                         writer.WriteStartElement (prefix, name, nspc);
1300                 }
1301                 
1302                 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1303                 {
1304                         switch ( mode) {
1305                                 case XmlWriteMode.WriteSchema:
1306                                         writer.WriteAttributeString (prefix, name, nspc);
1307                                         break;
1308                                 case XmlWriteMode.DiffGram:
1309                                         writer.WriteAttributeString (prefix, name, nspc,stringValue);
1310                                         break;
1311                                 default:
1312                                         writer.WriteAttributeString (name, stringValue);
1313                                         break;                                  
1314                         };
1315                 }
1316                 
1317                 internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
1318                 {
1319                         ((XmlTextWriter)writer).Formatting = Formatting.Indented;
1320
1321                         if (mode == XmlWriteMode.DiffGram) {
1322                                 SetTableRowsID (table);
1323                                 WriteDiffGramElement (writer);
1324                         }
1325                         
1326                         WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
1327                         
1328                         WriteTable (writer, table, mode, DataRowVersion.Default);
1329                         
1330                         if (mode == XmlWriteMode.DiffGram) {
1331                                 writer.WriteEndElement (); //DataSet name
1332                                 if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
1333
1334                                         DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);   
1335                                         WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
1336                                         WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
1337                                         writer.WriteEndElement ();
1338                                 }
1339                         }
1340                         writer.WriteEndElement (); // DataSet name or diffgr:diffgram
1341                 }
1342                 
1343
1344                 private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
1345                 {
1346                         if (ns == String.Empty)
1347                                 return;
1348                         if (ns != nsmgr.DefaultNamespace) {
1349                                 if (nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix)) != ns) {
1350                                         for (int i = 1; i < int.MaxValue; i++) {
1351                                                 string p = nsmgr.NameTable.Add ("app" + i);
1352                                                 if (!nsmgr.HasNamespace (p)) {
1353                                                         nsmgr.AddNamespace (p, ns);
1354                                                         HandleExternalNamespace (p, ns, schema);
1355                                                         break;
1356                                                 }
1357                                         }
1358                                 }
1359                         }
1360                 }
1361                 
1362                 XmlSchema BuildSchema ()
1363                 {
1364                         return BuildSchema (Tables, Relations);
1365                 }
1366                 
1367                 internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
1368                 {
1369                         string constraintPrefix = "";
1370                         XmlSchema schema = new XmlSchema ();
1371                         XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
1372                         
1373                         if (Namespace != "") {
1374                                 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1375                                 schema.ElementFormDefault = XmlSchemaForm.Qualified;
1376                                 schema.TargetNamespace = Namespace;
1377                                 constraintPrefix = XmlConstants.TnsPrefix + ":";
1378                         }
1379
1380                         // set the schema id
1381                         string xmlNSURI = "http://www.w3.org/2000/xmlns/";
1382                         schema.Id = DataSetName;
1383                         XmlDocument doc = new XmlDocument ();
1384                         XmlAttribute attr = null;
1385                         ArrayList atts = new ArrayList ();
1386
1387                         nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
1388                         nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1389                         if (Namespace != "") {
1390                                 nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
1391                                 nsmgr.AddNamespace (String.Empty, Namespace);
1392                         }
1393                         if (CheckExtendedPropertyExists ())
1394                                 nsmgr.AddNamespace (XmlConstants.MspropPrefix, XmlConstants.MspropNamespace);
1395
1396                         if (atts.Count > 0)
1397                                 schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1398
1399                         XmlSchemaElement elem = new XmlSchemaElement ();
1400                         elem.Name = XmlConvert.EncodeName (DataSetName);
1401
1402                         // Add namespaces used in DataSet components (tables, columns, ...)
1403                         foreach (DataTable dt in Tables) {
1404                                 foreach (DataColumn col in dt.Columns)
1405                                         CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
1406                                 CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
1407                         }
1408
1409                         // Attributes for DataSet element
1410                         atts.Clear ();
1411                         attr = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1412                         attr.Value = "true";
1413                         atts.Add (attr);
1414
1415                         attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1416                         attr.Value = locale.Name;
1417                         atts.Add (attr);
1418
1419                         elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1420
1421                         AddExtendedPropertyAttributes (elem, ExtendedProperties, doc);
1422
1423                         XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1424                         elem.SchemaType = complex;
1425
1426                         XmlSchemaChoice choice = new XmlSchemaChoice ();
1427                         complex.Particle = choice;
1428                         choice.MaxOccursString = XmlConstants.Unbounded;
1429                         
1430                         //Write out schema for each table in order
1431                         foreach (DataTable table in tables) {           
1432                                 bool isTopLevel = true;
1433                                 foreach (DataRelation rel in table.ParentRelations) {
1434                                         if (rel.Nested) {
1435                                                 isTopLevel = false;
1436                                                 break;
1437                                         }
1438                                 }
1439                                 
1440                                 if (isTopLevel) {
1441                                         if (table.Namespace != SafeNS (schema.TargetNamespace)) {
1442                                                 XmlSchemaElement extElem = new XmlSchemaElement ();
1443                                                 extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
1444                                                 choice.Items.Add (extElem);
1445                                         }
1446                                         else
1447                                                 choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
1448                                 }
1449                         }
1450
1451                         schema.Items.Add (elem);
1452                         
1453                         AddConstraintsToSchema (elem, constraintPrefix, tables, relations, doc);
1454                         foreach (string prefix in nsmgr) {
1455                                 string ns = nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix));
1456                                 if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
1457                                         schema.Namespaces.Add (prefix, ns);
1458                         }
1459                         return schema;
1460                 }
1461                 
1462                 private bool CheckExtendedPropertyExists ()
1463                 {
1464                         if (ExtendedProperties.Count > 0)
1465                                 return true;
1466                         foreach (DataTable dt in Tables) {
1467                                 if (dt.ExtendedProperties.Count > 0)
1468                                         return true;
1469                                 foreach (DataColumn col in dt.Columns)
1470                                         if (col.ExtendedProperties.Count > 0)
1471                                                 return true;
1472                                 foreach (Constraint c in dt.Constraints)
1473                                         if (c.ExtendedProperties.Count > 0)
1474                                                 return true;
1475                         }
1476                         foreach (DataRelation rel in Relations)
1477                                 if (rel.ExtendedProperties.Count > 0)
1478                                         return true;
1479                         return false;
1480                 }
1481
1482                 // Add all constraints in all tables to the schema.
1483                 private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations, XmlDocument doc)
1484                 {
1485                         // first add all unique constraints.
1486                         Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables, doc);
1487                         // Add all foriegn key constraints.
1488                         AddForeignKeys (uniqueNames, elem, constraintPrefix, relations, doc);
1489                 }
1490                 
1491                 // Add unique constaraints to the schema.
1492                 // return hashtable with the names of all XmlSchemaUnique elements we created.
1493                 private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, XmlDocument doc)
1494                 {
1495                         Hashtable uniqueNames = new Hashtable();
1496                         foreach (DataTable table in tables) {
1497                                 
1498                                 foreach (Constraint constraint in table.Constraints) {
1499                                         
1500                                         if (constraint is UniqueConstraint) {
1501                                                 ArrayList attrs = new ArrayList ();
1502                                                 XmlAttribute attrib;
1503                                                 UniqueConstraint uqConst = (UniqueConstraint) constraint;
1504                                                 XmlSchemaUnique uniq = new XmlSchemaUnique ();
1505                                                 
1506                                                 // if column of the constraint is hidden do not write the constraint.
1507                                                 bool isHidden = false;
1508                                                 foreach (DataColumn column in uqConst.Columns) {
1509                                                         if (column.ColumnMapping == MappingType.Hidden) {
1510                                                                 isHidden = true;
1511                                                                 break;
1512                                                         }
1513                                                 }
1514
1515                                                 if (isHidden)
1516                                                         continue;
1517
1518                                                 // if constaraint name do not exist in the hashtable we can use it.
1519                                                 if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
1520                                                         uniq.Name = uqConst.ConstraintName;
1521                                                 }
1522                                                 // generate new constraint name for the XmlSchemaUnique element.
1523                                                 else {
1524                                                         uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
1525                                                         attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1526                                                         attrib.Value = uqConst.ConstraintName;
1527                                                         attrs.Add (attrib);
1528                                                 }
1529                                                 if (uqConst.IsPrimaryKey) {
1530                                                         attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
1531                                                         attrib.Value = "true";
1532                                                         attrs.Add (attrib);
1533                                                 }
1534                 
1535                                                 uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1536
1537                                                 uniq.Selector = new XmlSchemaXPath();
1538                                                 uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
1539                                                 XmlSchemaXPath field;
1540                                                 foreach (DataColumn column in uqConst.Columns) {
1541                                                         field = new XmlSchemaXPath();
1542                                                         field.XPath = constraintPrefix+column.ColumnName;
1543                                                         uniq.Fields.Add(field);
1544                                                 }
1545                                 
1546                                                 AddExtendedPropertyAttributes (uniq, constraint.ExtendedProperties, doc);
1547
1548                                                 elem.Constraints.Add (uniq);
1549                                                 uniqueNames.Add (uniq.Name, null);
1550                                         }
1551                                 }
1552                         }
1553                         return uniqueNames;
1554                 }
1555                 
1556                 // Add the foriegn keys to the schema.
1557                 private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations, XmlDocument doc)
1558                 {
1559                         if (relations == null) return;
1560                         
1561                         foreach (DataRelation rel in relations) {
1562                                 
1563                                 if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
1564                                         continue;
1565
1566                                 bool isHidden = false;
1567                                 foreach (DataColumn col in rel.ParentColumns) {
1568                                         if (col.ColumnMapping == MappingType.Hidden) {
1569                                                 isHidden = true;
1570                                                 break;
1571                                         }
1572                                 }
1573                                 foreach (DataColumn col in rel.ChildColumns) {
1574                                         if (col.ColumnMapping == MappingType.Hidden) {
1575                                                 isHidden = true;
1576                                                 break;
1577                                         }
1578                                 }
1579                                 if (isHidden)
1580                                         continue;
1581                                 
1582                                 ArrayList attrs = new ArrayList ();
1583                                 XmlAttribute attrib;
1584                                 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1585                                 keyRef.Name = rel.RelationName;
1586                                 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1587                                 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1588                                 
1589                                 string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
1590                                 // first try to find the concatenated name. If we didn't find it - use constraint name.
1591                                 if (uniqueNames.ContainsKey (concatName)) {
1592                                         keyRef.Refer = new XmlQualifiedName(concatName);
1593                                 }
1594                                 else {
1595                                         keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
1596                                 }
1597
1598                                 if (rel.Nested) {
1599                                         attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1600                                         attrib.Value = "true";
1601                                         attrs.Add (attrib);
1602                                 }
1603
1604                                 keyRef.Selector = new XmlSchemaXPath();
1605                                 keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
1606                                 XmlSchemaXPath field;
1607                                 foreach (DataColumn column in rel.ChildColumns) {
1608                                         field = new XmlSchemaXPath();
1609                                         field.XPath = constraintPrefix+column.ColumnName;
1610                                         keyRef.Fields.Add(field);
1611                                 }
1612
1613                                 keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1614                                 AddExtendedPropertyAttributes (keyRef, rel.ExtendedProperties, doc);
1615
1616                                 elem.Constraints.Add (keyRef);
1617                         }
1618                 }
1619
1620                 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
1621                 {
1622                         ArrayList elements;
1623                         ArrayList atts;
1624                         DataColumn simple;
1625                         
1626                         SplitColumns (table, out atts, out elements, out simple);
1627
1628                         XmlSchemaElement elem = new XmlSchemaElement ();
1629                         elem.Name = table.TableName;
1630
1631                         XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1632                         elem.SchemaType = complex;
1633
1634                         XmlSchemaObjectCollection schemaAttributes = null;
1635
1636                         if (simple != null) {
1637                                 // add simpleContent
1638                                 XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
1639                                 complex.ContentModel = simpleContent;
1640
1641                                 // add column name attribute
1642                                 XmlAttribute[] xlmAttrs = new XmlAttribute [2];
1643                                 xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
1644                                 xlmAttrs[0].Value = simple.ColumnName;
1645                                 
1646                                 // add ordinal attribute
1647                                 xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
1648                                 xlmAttrs[1].Value = XmlConvert.ToString (simple.Ordinal);
1649                                 simpleContent.UnhandledAttributes = xlmAttrs;
1650                                 
1651                                 
1652                                 // add extension
1653                                 XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
1654                                 simpleContent.Content = extension;
1655                                 extension.BaseTypeName = MapType (simple.DataType);
1656                                 schemaAttributes = extension.Attributes;
1657                         } else {
1658                                 schemaAttributes = complex.Attributes;
1659                                 //A sequence of element types or a simple content node
1660                                 //<xs:sequence>
1661                                 XmlSchemaSequence seq = new XmlSchemaSequence ();
1662
1663                                 foreach (DataColumn col in elements) {
1664                                         
1665                                         // Add element for the column.
1666                                         XmlSchemaElement colElem = new XmlSchemaElement ();
1667                                         ArrayList xattrs = new ArrayList();
1668                                         XmlAttribute xattr;
1669                                         colElem.Name = col.ColumnName;
1670                                 
1671                                         if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
1672                                                 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1673                                                 xattr.Value = col.Caption;
1674                                                 xattrs.Add (xattr);
1675                                         }
1676
1677                                         if (col.AutoIncrement == true) {
1678                                                 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
1679                                                 xattr.Value = "true";
1680                                                 xattrs.Add (xattr);
1681                                         }
1682
1683                                         if (col.AutoIncrementSeed != 0) {
1684                                                 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
1685                                                 xattr.Value = XmlConvert.ToString (col.AutoIncrementSeed);
1686                                                 xattrs.Add (xattr);
1687                                         }
1688
1689                                         if (col.DefaultValue.ToString () != String.Empty)
1690                                                 colElem.DefaultValue = WriteObjectXml (col.DefaultValue);
1691                                         
1692                                         if (col.MaxLength < 0)
1693                                                 colElem.SchemaTypeName = MapType (col.DataType);
1694                                         
1695                                         if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string) 
1696                                                 && col.DataType != typeof (char)) {
1697                                                 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
1698                                                 xattr.Value = col.DataType.AssemblyQualifiedName;
1699                                                 xattrs.Add (xattr);
1700                                         }
1701
1702                                         if (col.AllowDBNull) {
1703                                                 colElem.MinOccurs = 0;
1704                                         }
1705
1706                                         //writer.WriteAttributeString (XmlConstants.MsdataPrefix, 
1707                                         //                            XmlConstants.Ordinal, 
1708                                         //                            XmlConstants.MsdataNamespace, 
1709                                         //                            col.Ordinal.ToString ());
1710
1711                                         // Write SimpleType if column have MaxLength
1712                                         if (col.MaxLength > -1) {
1713                                                 colElem.SchemaType = GetTableSimpleType (doc, col);
1714                                         }
1715                                         
1716                                         colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
1717                                         AddExtendedPropertyAttributes (colElem, col.ExtendedProperties, doc);
1718                                         seq.Items.Add (colElem);
1719                                 }
1720
1721                                 foreach (DataRelation rel in table.ChildRelations) {
1722                                         if (rel.Nested) {
1723                                                 if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
1724                                                         XmlSchemaElement el = new XmlSchemaElement ();
1725                                                         el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
1726                                                 } else {
1727                                                         XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
1728                                                         el.MinOccurs = 0;
1729                                                         el.MaxOccursString = "unbounded";
1730                                                         XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
1731                                                         ct.Name = el.Name;
1732                                                         el.SchemaType = null;
1733                                                         el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
1734                                                         schemaToAdd.Items.Add (ct);
1735                                                         seq.Items.Add (el);
1736                                                 }
1737                                         }
1738                                 }
1739
1740                                 if (seq.Items.Count > 0)
1741                                         complex.Particle = seq;
1742                         }
1743
1744                         //Then a list of attributes
1745                         foreach (DataColumn col in atts) {
1746                                 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1747                                 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1748                                 att.Name = col.ColumnName;
1749                                 if (col.Namespace != String.Empty) {
1750                                         att.Form = XmlSchemaForm.Qualified;
1751                                         string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
1752                                         att.Name = prefix + ":" + col.ColumnName;
1753                                         // FIXME: Handle prefix mapping correctly.
1754                                         schemaToAdd.Namespaces.Add (prefix, col.Namespace);
1755                                 }
1756                                 att.SchemaTypeName = MapType (col.DataType);
1757                                 // FIXME: what happens if extended properties are set on attribute columns??
1758                                 schemaAttributes.Add (att);
1759                         }
1760
1761                         AddExtendedPropertyAttributes (elem, table.ExtendedProperties, doc);
1762
1763                         return elem;
1764                 }
1765
1766                 private void AddExtendedPropertyAttributes (XmlSchemaAnnotated xsobj, PropertyCollection props, XmlDocument doc)
1767                 {
1768                         ArrayList attList = new ArrayList ();
1769                         XmlAttribute xmlAttr;
1770
1771                         if (xsobj.UnhandledAttributes != null)
1772                                 attList.AddRange (xsobj.UnhandledAttributes);
1773
1774                         // add extended properties to xs:element
1775                         foreach (DictionaryEntry de in props) {
1776                                 xmlAttr = doc.CreateAttribute (XmlConstants.MspropPrefix, XmlConvert.EncodeName (de.Key.ToString ()), XmlConstants.MspropNamespace);
1777                                 xmlAttr.Value = de.Value != null ? WriteObjectXml (de.Value) : String.Empty;
1778                                 attList.Add (xmlAttr);
1779                         }
1780                         if (attList.Count > 0)
1781                                 xsobj.UnhandledAttributes = attList.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1782                 }
1783
1784                 private string SafeNS (string ns)
1785                 {
1786                         return ns != null ? ns : String.Empty;
1787                 }
1788
1789                 private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
1790                 {
1791                         foreach (XmlSchemaExternal ext in schema.Includes) {
1792                                 XmlSchemaImport imp = ext as XmlSchemaImport;
1793                                 if (imp != null && imp.Namespace == ns)
1794                                         return; // nothing to do
1795                         }
1796                         XmlSchemaImport i = new XmlSchemaImport ();
1797                         i.Namespace = ns;
1798                         i.SchemaLocation = "_" + prefix + ".xsd";
1799                         schema.Includes.Add (i);
1800                 }
1801
1802                 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1803                 {
1804                         // SimpleType
1805                         XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1806
1807                         // Restriction
1808                         XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1809                         restriction.BaseTypeName = MapType (col.DataType);
1810                         
1811                         // MaxValue
1812                         XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1813                         max.Value = XmlConvert.ToString (col.MaxLength);
1814                         restriction.Facets.Add (max);
1815                         
1816                         simple.Content = restriction;
1817                         return simple;
1818                 }
1819
1820                 private void DoWriteXmlSchema (XmlWriter writer)
1821                 {
1822                         BuildSchema ().Write (writer);
1823                 }
1824                 
1825                 ///<summary>
1826                 /// Helper function to split columns into attributes elements and simple
1827                 /// content
1828                 /// </summary>
1829                 private void SplitColumns (DataTable table, 
1830                         out ArrayList atts, 
1831                         out ArrayList elements, 
1832                         out DataColumn simple)
1833                 {
1834                         //The columns can be attributes, hidden, elements, or simple content
1835                         //There can be 0-1 simple content cols or 0-* elements
1836                         atts = new System.Collections.ArrayList ();
1837                         elements = new System.Collections.ArrayList ();
1838                         simple = null;
1839                         
1840                         //Sort out the columns
1841                         foreach (DataColumn col in table.Columns) {
1842                                 switch (col.ColumnMapping) {
1843                                         case MappingType.Attribute:
1844                                                 atts.Add (col);
1845                                                 break;
1846                                         case MappingType.Element:
1847                                                 elements.Add (col);
1848                                                 break;
1849                                         case MappingType.SimpleContent:
1850                                                 if (simple != null) {
1851                                                         throw new System.InvalidOperationException ("There may only be one simple content element");
1852                                                 }
1853                                                 simple = col;
1854                                                 break;
1855                                         default:
1856                                                 //ignore Hidden elements
1857                                                 break;
1858                                 }
1859                         }
1860                 }
1861
1862                 private void WriteDiffGramElement(XmlWriter writer)
1863                 {
1864                         WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
1865                         WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1866                 }
1867
1868                 private void SetRowsID()
1869                 {
1870                         foreach (DataTable Table in Tables)
1871                                 SetTableRowsID (Table);
1872                 }
1873                 
1874                 private void SetTableRowsID (DataTable Table)
1875                 {
1876                         int dataRowID = 0;
1877                         foreach (DataRow Row in Table.Rows) {
1878                                 Row.XmlRowID = dataRowID;
1879                                 dataRowID++;
1880                         }
1881                 }
1882
1883                 
1884                 private XmlQualifiedName MapType (Type type)
1885                 {
1886                         switch (Type.GetTypeCode (type)) {
1887                                 case TypeCode.String: return XmlConstants.QnString;
1888                                 case TypeCode.Int16: return XmlConstants.QnShort;
1889                                 case TypeCode.Int32: return XmlConstants.QnInt;
1890                                 case TypeCode.Int64: return XmlConstants.QnLong;
1891                                 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1892                                 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1893                                 //case TypeCode.Char: return XmlConstants.QnChar;
1894                                 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1895                                 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1896                                 case TypeCode.Double: return XmlConstants.QnDouble;
1897                                 case TypeCode.SByte: return XmlConstants.QnSbyte;
1898                                 case TypeCode.Single: return XmlConstants.QnFloat;
1899                                 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1900                                 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1901                                 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1902                         }
1903                         
1904                         if (typeof (TimeSpan) == type)
1905                                 return XmlConstants.QnDuration;
1906                         else if (typeof (System.Uri) == type)
1907                                 return XmlConstants.QnUri;
1908                         else if (typeof (byte[]) == type)
1909                                 return XmlConstants.QnBase64Binary;
1910                         else if (typeof (XmlQualifiedName) == type)
1911                                 return XmlConstants.QnXmlQualifiedName;
1912                         else
1913                                 return XmlConstants.QnString;
1914                 }
1915
1916                 #endregion //Private Xml Serialisation
1917         }
1918 }