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