2 // System.Data/DataSet.cs
5 // Christopher Podurgiel <cpodurgiel@msn.com>
6 // Daniel Morgan <danmorg@sc.rr.com>
7 // Rodrigo Moya <rodrigo@ximian.com>
8 // Stuart Caborn <stuart.caborn@virgin.net>
9 // Tim Coleman (tim@timcoleman.com)
10 // Ville Palo <vi64pa@koti.soon.fi>
11 // Atsushi Enomoto <atsushi@ximian.com>
13 // (C) Ximian, Inc. 2002
14 // Copyright (C) Tim Coleman, 2002, 2003
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 using System.Collections;
42 using System.ComponentModel;
43 using System.Globalization;
44 using System.Threading;
46 using System.Runtime.Serialization;
48 using System.Xml.Schema;
49 using System.Xml.Serialization;
50 using System.Data.Common;
52 namespace System.Data {
55 [DefaultProperty ("DataSetName")]
56 [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataSetDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
59 public class DataSet : MarshalByValueComponent, IListSource,
60 ISupportInitialize, ISerializable, IXmlSerializable
62 private string dataSetName;
63 private string _namespace = "";
64 private string prefix;
65 private bool caseSensitive;
66 private bool enforceConstraints = true;
67 private DataTableCollection tableCollection;
68 private DataRelationCollection relationCollection;
69 private PropertyCollection properties;
70 private DataViewManager defaultView;
71 private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
72 internal XmlDataDocument _xmlDataDocument = null;
76 public DataSet () : this ("NewDataSet")
80 public DataSet (string name)
83 tableCollection = new DataTableCollection (this);
84 relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
85 properties = new PropertyCollection ();
86 this.prefix = String.Empty;
88 this.Locale = CultureInfo.CurrentCulture;
91 protected DataSet (SerializationInfo info, StreamingContext context) : this ()
93 GetSerializationData (info, context);
96 #endregion // Constructors
98 #region Public Properties
100 [DataCategory ("Data")]
101 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
102 [DefaultValue (false)]
103 public bool CaseSensitive {
105 return caseSensitive;
108 caseSensitive = value;
109 if (!caseSensitive) {
110 foreach (DataTable table in Tables) {
111 foreach (Constraint c in table.Constraints)
112 c.AssertConstraint ();
118 [DataCategory ("Data")]
119 [DataSysDescription ("The name of this DataSet.")]
121 public string DataSetName {
122 get { return dataSetName; }
123 set { dataSetName = value; }
126 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
128 public DataViewManager DefaultViewManager {
130 if (defaultView == null)
131 defaultView = new DataViewManager (this);
136 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
137 [DefaultValue (true)]
138 public bool EnforceConstraints {
139 get { return enforceConstraints; }
141 if (value != enforceConstraints) {
142 enforceConstraints = value;
144 foreach (DataTable table in Tables) {
145 // first assert all unique constraints
146 foreach (UniqueConstraint uc in table.Constraints.UniqueConstraints)
147 uc.AssertConstraint ();
148 // then assert all foreign keys
149 foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
150 fk.AssertConstraint ();
158 [DataCategory ("Data")]
159 [DataSysDescription ("The collection that holds custom user information.")]
160 public PropertyCollection ExtendedProperties {
161 get { return properties; }
165 [DataSysDescription ("Indicates that the DataSet has errors.")]
166 public bool HasErrors {
169 for (int i = 0; i < Tables.Count; i++) {
170 if (Tables[i].HasErrors)
177 [DataCategory ("Data")]
178 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
179 public CultureInfo Locale {
184 if (locale == null || !locale.Equals (value)) {
185 // TODO: check if the new locale is valid
186 // TODO: update locale of all tables
192 public void Merge (DataRow[] rows)
194 Merge (rows, false, MissingSchemaAction.Add);
197 public void Merge (DataSet dataSet)
199 Merge (dataSet, false, MissingSchemaAction.Add);
202 public void Merge (DataTable table)
204 Merge (table, false, MissingSchemaAction.Add);
207 public void Merge (DataSet dataSet, bool preserveChanges)
209 Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
213 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
216 throw new ArgumentNullException ("rows");
217 if (!IsLegalSchemaAction (missingSchemaAction))
218 throw new ArgumentOutOfRangeException ("missingSchemaAction");
220 MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
224 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
227 throw new ArgumentNullException ("dataSet");
228 if (!IsLegalSchemaAction (missingSchemaAction))
229 throw new ArgumentOutOfRangeException ("missingSchemaAction");
231 MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
235 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
238 throw new ArgumentNullException ("table");
239 if (!IsLegalSchemaAction (missingSchemaAction))
240 throw new ArgumentOutOfRangeException ("missingSchemaAction");
242 MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
245 private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
247 if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
248 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
253 [DataCategory ("Data")]
254 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
256 public string Namespace {
257 get { return _namespace; }
259 //TODO - trigger an event if this happens?
261 value = String.Empty;
262 if (value != this._namespace)
263 RaisePropertyChanging ("Namespace");
268 [DataCategory ("Data")]
269 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
271 public string Prefix {
272 get { return prefix; }
275 value = String.Empty;
276 // Prefix cannot contain any special characters other than '_' and ':'
277 for (int i = 0; i < value.Length; i++) {
278 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
279 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
284 value = string.Empty;
286 if (value != this.prefix)
287 RaisePropertyChanging ("Prefix");
292 [DataCategory ("Data")]
293 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
294 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
295 public DataRelationCollection Relations {
297 return relationCollection;
302 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
303 public override ISite Site {
306 throw new NotImplementedException ();
311 throw new NotImplementedException ();
315 [DataCategory ("Data")]
316 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
317 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
318 public DataTableCollection Tables {
319 get { return tableCollection; }
322 #endregion // Public Properties
324 #region Public Methods
327 public void AcceptChanges ()
329 foreach (DataTable tempTable in tableCollection)
330 tempTable.AcceptChanges ();
334 /// Clears all the tables
338 if (_xmlDataDocument != null)
339 throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
340 bool enforceConstraints = this.EnforceConstraints;
341 this.EnforceConstraints = false;
342 for (int t = 0; t < tableCollection.Count; t++) {
343 tableCollection [t].Clear ();
345 this.EnforceConstraints = enforceConstraints;
348 public virtual DataSet Clone ()
350 DataSet Copy = new DataSet ();
351 CopyProperties (Copy);
353 foreach (DataTable Table in Tables) {
354 Copy.Tables.Add (Table.Clone ());
357 //Copy Relationships between tables after existance of tables
358 //and setting properties correctly
359 CopyRelations (Copy);
364 // Copies both the structure and data for this DataSet.
365 public DataSet Copy ()
367 DataSet Copy = new DataSet ();
368 CopyProperties (Copy);
370 // Copy DatSet's tables
371 foreach (DataTable Table in Tables)
372 Copy.Tables.Add (Table.Copy ());
374 //Copy Relationships between tables after existance of tables
375 //and setting properties correctly
376 CopyRelations (Copy);
381 private void CopyProperties (DataSet Copy)
383 Copy.CaseSensitive = CaseSensitive;
384 //Copy.Container = Container
385 Copy.DataSetName = DataSetName;
386 //Copy.DefaultViewManager
388 Copy.EnforceConstraints = EnforceConstraints;
389 if(ExtendedProperties.Count > 0) {
390 // Cannot copy extended properties directly as the property does not have a set accessor
391 Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
392 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
393 for (int i=0; i < ExtendedProperties.Count; i++)
394 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
396 Copy.Locale = Locale;
397 Copy.Namespace = Namespace;
398 Copy.Prefix = Prefix;
399 //Copy.Site = Site; // FIXME : Not sure of this.
404 private void CopyRelations (DataSet Copy)
407 //Creation of the relation contains some of the properties, and the constructor
408 //demands these values. instead changing the DataRelation constructor and behaviour the
409 //parameters are pre-configured and sent to the most general constructor
411 foreach (DataRelation MyRelation in this.Relations) {
412 string pTable = MyRelation.ParentTable.TableName;
413 string cTable = MyRelation.ChildTable.TableName;
414 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
415 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
418 foreach (DataColumn DC in MyRelation.ParentColumns) {
419 P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
425 foreach (DataColumn DC in MyRelation.ChildColumns) {
426 C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
430 DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
431 //cRel.ChildColumns = MyRelation.ChildColumns;
432 //cRel.ChildTable = MyRelation.ChildTable;
433 //cRel.ExtendedProperties = cRel.ExtendedProperties;
434 //cRel.Nested = MyRelation.Nested;
435 //cRel.ParentColumns = MyRelation.ParentColumns;
436 //cRel.ParentTable = MyRelation.ParentTable;
438 Copy.Relations.Add (cRel);
445 public DataSet GetChanges ()
447 return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
451 public DataSet GetChanges (DataRowState rowStates)
453 if (!HasChanges (rowStates))
456 DataSet copySet = Clone ();
457 Hashtable addedRows = new Hashtable ();
459 IEnumerator tableEnumerator = Tables.GetEnumerator ();
462 while (tableEnumerator.MoveNext ()) {
463 origTable = (DataTable)tableEnumerator.Current;
464 copyTable = copySet.Tables[origTable.TableName];
466 // Look for relations that have this table as child
467 IEnumerator relations = origTable.ParentRelations.GetEnumerator ();
469 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
470 while (rowEnumerator.MoveNext ()) {
471 DataRow row = (DataRow)rowEnumerator.Current;
473 if (row.IsRowChanged (rowStates))
474 AddChangedRow (addedRows, copySet, copyTable, relations, row);
480 void AddChangedRow (Hashtable addedRows, DataSet copySet, DataTable copyTable, IEnumerator relations, DataRow row)
482 if (addedRows.ContainsKey (row)) return;
485 while (relations.MoveNext ()) {
486 DataRow parentRow = row.GetParentRow ((DataRelation) relations.Current);
487 if (parentRow == null || addedRows.ContainsKey (parentRow)) continue;
488 DataTable parentCopyTable = copySet.Tables [parentRow.Table.TableName];
489 AddChangedRow (addedRows, copySet, parentCopyTable, parentRow.Table.ParentRelations.GetEnumerator (), parentRow);
492 DataRow newRow = copyTable.NewRow ();
493 copyTable.Rows.Add (newRow);
494 row.CopyValuesToRow (newRow);
495 newRow.XmlRowID = row.XmlRowID;
496 addedRows.Add (row,row);
501 public DataTableReader GetDataReader (DataTable[] dataTables)
503 throw new NotImplementedException ();
507 public DataTableReader GetDataReader ()
509 throw new NotImplementedException ();
513 public string GetXml ()
515 StringWriter Writer = new StringWriter ();
516 WriteXml (Writer, XmlWriteMode.IgnoreSchema);
517 return Writer.ToString ();
520 public string GetXmlSchema ()
522 StringWriter Writer = new StringWriter ();
523 WriteXmlSchema (Writer);
524 return Writer.ToString ();
528 public bool HasChanges ()
530 return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
534 public bool HasChanges (DataRowState rowState)
536 if (((int)rowState & 0xffffffe0) != 0)
537 throw new ArgumentOutOfRangeException ("rowState");
539 DataTableCollection tableCollection = Tables;
541 DataRowCollection rowCollection;
544 for (int i = 0; i < tableCollection.Count; i++) {
545 table = tableCollection[i];
546 rowCollection = table.Rows;
547 for (int j = 0; j < rowCollection.Count; j++) {
548 row = rowCollection[j];
549 if ((row.RowState & rowState) != 0)
557 public void InferXmlSchema (XmlReader reader, string[] nsArray)
561 XmlDocument doc = new XmlDocument ();
563 InferXmlSchema (doc, nsArray);
566 private void InferXmlSchema (XmlDocument doc, string [] nsArray)
568 XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, nsArray);
571 public void InferXmlSchema (Stream stream, string[] nsArray)
573 InferXmlSchema (new XmlTextReader (stream), nsArray);
576 public void InferXmlSchema (TextReader reader, string[] nsArray)
578 InferXmlSchema (new XmlTextReader (reader), nsArray);
581 public void InferXmlSchema (string fileName, string[] nsArray)
583 XmlTextReader reader = new XmlTextReader (fileName);
585 InferXmlSchema (reader, nsArray);
593 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
595 throw new NotImplementedException ();
599 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
601 throw new NotImplementedException ();
605 public virtual void RejectChanges ()
608 bool oldEnforceConstraints = this.EnforceConstraints;
609 this.EnforceConstraints = false;
611 for (i = 0; i < this.Tables.Count;i++)
612 this.Tables[i].RejectChanges ();
614 this.EnforceConstraints = oldEnforceConstraints;
617 public virtual void Reset ()
619 IEnumerator constraintEnumerator;
621 // first we remove all ForeignKeyConstraints (if we will not do that
622 // we will get an exception when clearing the tables).
623 for (int i = 0; i < Tables.Count; i++) {
624 ConstraintCollection cc = Tables[i].Constraints;
625 for (int j = 0; j < cc.Count; j++) {
626 if (cc[j] is ForeignKeyConstraint)
636 public void WriteXml (Stream stream)
638 XmlTextWriter writer = new XmlTextWriter (stream, null);
639 writer.Formatting = Formatting.Indented;
644 /// Writes the current data for the DataSet to the specified file.
646 /// <param name="filename">Fully qualified filename to write to</param>
647 public void WriteXml (string fileName)
649 XmlTextWriter writer = new XmlTextWriter (fileName, null);
650 writer.Formatting = Formatting.Indented;
651 writer.WriteStartDocument (true);
656 writer.WriteEndDocument ();
661 public void WriteXml (TextWriter writer)
663 XmlTextWriter xwriter = new XmlTextWriter (writer);
664 xwriter.Formatting = Formatting.Indented;
668 public void WriteXml (XmlWriter writer)
670 WriteXml (writer, XmlWriteMode.IgnoreSchema);
673 public void WriteXml (string filename, XmlWriteMode mode)
675 XmlTextWriter writer = new XmlTextWriter (filename, null);
676 writer.Formatting = Formatting.Indented;
677 writer.WriteStartDocument (true);
680 WriteXml (writer, mode);
683 writer.WriteEndDocument ();
688 public void WriteXml (Stream stream, XmlWriteMode mode)
690 XmlTextWriter writer = new XmlTextWriter (stream, null);
691 writer.Formatting = Formatting.Indented;
692 WriteXml (writer, mode);
695 public void WriteXml (TextWriter writer, XmlWriteMode mode)
697 XmlTextWriter xwriter = new XmlTextWriter (writer);
698 xwriter.Formatting = Formatting.Indented;
699 WriteXml (xwriter, mode);
702 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
704 if (mode == XmlWriteMode.DiffGram) {
706 WriteDiffGramElement(writer);
709 // It should not write when there is no content to be written
710 bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
711 for (int n = 0; n < tableCollection.Count && !shouldOutputContent; n++)
712 shouldOutputContent = tableCollection [n].Rows.Count > 0;
714 if (shouldOutputContent) {
715 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
717 if (mode == XmlWriteMode.WriteSchema)
718 DoWriteXmlSchema (writer);
720 WriteTables (writer, mode, Tables, DataRowVersion.Default);
721 writer.WriteEndElement ();
724 if (mode == XmlWriteMode.DiffGram) {
725 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
727 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
728 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
729 WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
730 writer.WriteEndElement ();
734 if (mode == XmlWriteMode.DiffGram)
735 writer.WriteEndElement (); // diffgr:diffgram
740 public void WriteXmlSchema (Stream stream)
742 XmlTextWriter writer = new XmlTextWriter (stream, null );
743 writer.Formatting = Formatting.Indented;
744 WriteXmlSchema (writer);
747 public void WriteXmlSchema (string fileName)
749 XmlTextWriter writer = new XmlTextWriter (fileName, null);
751 writer.Formatting = Formatting.Indented;
752 writer.WriteStartDocument (true);
753 WriteXmlSchema (writer);
755 writer.WriteEndDocument ();
760 public void WriteXmlSchema (TextWriter writer)
762 XmlTextWriter xwriter = new XmlTextWriter (writer);
764 xwriter.Formatting = Formatting.Indented;
765 // xwriter.WriteStartDocument ();
766 WriteXmlSchema (xwriter);
768 // xwriter.WriteEndDocument ();
773 public void WriteXmlSchema (XmlWriter writer)
775 //Create a skeleton doc and then write the schema
776 //proper which is common to the WriteXml method in schema mode
777 DoWriteXmlSchema (writer);
780 public void ReadXmlSchema (Stream stream)
782 XmlReader reader = new XmlTextReader (stream, null);
783 ReadXmlSchema (reader);
786 public void ReadXmlSchema (string str)
788 XmlReader reader = new XmlTextReader (str);
790 ReadXmlSchema (reader);
797 public void ReadXmlSchema (TextReader treader)
799 XmlReader reader = new XmlTextReader (treader);
800 ReadXmlSchema (reader);
803 public void ReadXmlSchema (XmlReader reader)
806 new XmlSchemaDataImporter (this, reader).Process ();
808 XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
809 SchemaMapper.Read (reader);
813 public XmlReadMode ReadXml (Stream stream)
815 return ReadXml (new XmlTextReader (stream));
818 public XmlReadMode ReadXml (string str)
820 XmlTextReader reader = new XmlTextReader (str);
822 return ReadXml (reader);
829 public XmlReadMode ReadXml (TextReader reader)
831 return ReadXml (new XmlTextReader (reader));
834 public XmlReadMode ReadXml (XmlReader r)
836 return ReadXml (r, XmlReadMode.Auto);
839 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
841 return ReadXml (new XmlTextReader (stream), mode);
844 public XmlReadMode ReadXml (string str, XmlReadMode mode)
846 XmlTextReader reader = new XmlTextReader (str);
848 return ReadXml (reader, mode);
855 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
857 return ReadXml (new XmlTextReader (reader), mode);
860 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
862 switch (reader.ReadState) {
863 case ReadState.EndOfFile:
864 case ReadState.Error:
865 case ReadState.Closed:
868 // Skip XML declaration and prolog
869 reader.MoveToContent();
873 XmlReadMode Result = mode;
875 // If diffgram, then read the first element as diffgram
876 if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
878 case XmlReadMode.Auto:
879 case XmlReadMode.DiffGram:
880 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
881 DiffLoader.Load (reader);
882 // (and leave rest of the reader as is)
883 return XmlReadMode.DiffGram;
884 case XmlReadMode.Fragment:
886 // (and continue to read)
890 // (and leave rest of the reader as is)
894 // If schema, then read the first element as schema
895 if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
897 case XmlReadMode.IgnoreSchema:
898 case XmlReadMode.InferSchema:
900 // (and break up read)
902 case XmlReadMode.Fragment:
903 ReadXmlSchema (reader);
904 // (and continue to read)
906 case XmlReadMode.Auto:
907 if (Tables.Count == 0) {
908 ReadXmlSchema (reader);
909 return XmlReadMode.ReadSchema;
911 // otherwise just ignore and return IgnoreSchema
913 return XmlReadMode.IgnoreSchema;
916 ReadXmlSchema (reader);
917 // (and leave rest of the reader as is)
918 return mode; // When DiffGram, return DiffGram
921 // Otherwise, read as dataset... but only when required.
922 XmlReadMode explicitReturnMode = XmlReadMode.Auto;
925 case XmlReadMode.Auto:
926 if (Tables.Count > 0)
927 goto case XmlReadMode.IgnoreSchema;
929 goto case XmlReadMode.InferSchema;
930 case XmlReadMode.InferSchema:
931 doc = new XmlDocument ();
933 doc.AppendChild (doc.ReadNode (reader));
934 reader.MoveToContent ();
935 if (doc.DocumentElement != null)
937 } while (!reader.EOF);
938 InferXmlSchema (doc, null);
939 reader = new XmlNodeReader (doc);
940 explicitReturnMode = XmlReadMode.InferSchema;
942 case XmlReadMode.ReadSchema:
943 doc = new XmlDocument ();
945 doc.AppendChild (doc.ReadNode (reader));
946 reader.MoveToContent ();
947 if (doc.DocumentElement != null)
949 } while (!reader.EOF);
950 if (doc.DocumentElement != null) {
951 XmlElement schema = doc.DocumentElement ["schema", XmlSchema.Namespace] as XmlElement;
952 if (schema != null) {
953 ReadXmlSchema (new XmlNodeReader (schema));
954 explicitReturnMode = XmlReadMode.ReadSchema;
957 reader = new XmlNodeReader (doc);
959 case XmlReadMode.IgnoreSchema:
960 case XmlReadMode.Fragment:
967 XmlDataReader.ReadXml (this, reader, mode);
968 if (explicitReturnMode != XmlReadMode.Auto)
969 return explicitReturnMode;
970 return mode == XmlReadMode.Auto ? XmlReadMode.IgnoreSchema : mode;
972 #endregion // Public Methods
974 #region Public Events
976 [DataCategory ("Action")]
977 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
978 public event MergeFailedEventHandler MergeFailed;
980 #endregion // Public Events
982 #region IListSource methods
983 IList IListSource.GetList ()
985 return DefaultViewManager;
988 bool IListSource.ContainsListCollection {
993 #endregion IListSource methods
995 #region ISupportInitialize methods
996 public void BeginInit ()
1000 public void EndInit ()
1005 #region ISerializable
1006 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
1008 StringWriter sw = new StringWriter ();
1009 XmlTextWriter writer = new XmlTextWriter (sw);
1010 DoWriteXmlSchema (writer);
1012 si.AddValue ("XmlSchema", sw.ToString ());
1014 sw = new StringWriter ();
1015 writer = new XmlTextWriter (sw);
1016 WriteXml (writer, XmlWriteMode.DiffGram);
1018 si.AddValue ("XmlDiffGram", sw.ToString ());
1022 #region Protected Methods
1023 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
1025 string s = info.GetValue ("XmlSchema", typeof (String)) as String;
1026 XmlTextReader reader = new XmlTextReader (new StringReader (s));
1027 ReadXmlSchema (reader);
1030 s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
1031 reader = new XmlTextReader (new StringReader (s));
1032 ReadXml (reader, XmlReadMode.DiffGram);
1037 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
1042 protected virtual void ReadXmlSerializable (XmlReader reader)
1044 reader.MoveToContent ();
1045 reader.ReadStartElement ();
1046 reader.MoveToContent ();
1047 ReadXmlSchema (reader);
1048 reader.MoveToContent ();
1049 ReadXml (reader, XmlReadMode.DiffGram);
1050 reader.MoveToContent ();
1051 reader.ReadEndElement ();
1054 void IXmlSerializable.ReadXml (XmlReader reader)
1056 ReadXmlSerializable(reader);
1059 void IXmlSerializable.WriteXml (XmlWriter writer)
1061 DoWriteXmlSchema (writer);
1062 WriteXml (writer, XmlWriteMode.DiffGram);
1065 XmlSchema IXmlSerializable.GetSchema ()
1067 return BuildSchema ();
1070 protected virtual bool ShouldSerializeRelations ()
1075 protected virtual bool ShouldSerializeTables ()
1081 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
1086 protected virtual void OnRemoveRelation (DataRelation relation)
1091 protected virtual void OnRemoveTable (DataTable table)
1095 internal virtual void OnMergeFailed (MergeFailedEventArgs e)
1097 if (MergeFailed != null)
1098 MergeFailed (this, e);
1102 protected internal void RaisePropertyChanging (string name)
1107 #region Private Xml Serialisation
1109 private string WriteObjectXml (object o)
1111 switch (Type.GetTypeCode (o.GetType ())) {
1112 case TypeCode.Boolean:
1113 return XmlConvert.ToString ((Boolean) o);
1115 return XmlConvert.ToString ((Byte) o);
1117 return XmlConvert.ToString ((Char) o);
1118 case TypeCode.DateTime:
1119 return XmlConvert.ToString ((DateTime) o);
1120 case TypeCode.Decimal:
1121 return XmlConvert.ToString ((Decimal) o);
1122 case TypeCode.Double:
1123 return XmlConvert.ToString ((Double) o);
1124 case TypeCode.Int16:
1125 return XmlConvert.ToString ((Int16) o);
1126 case TypeCode.Int32:
1127 return XmlConvert.ToString ((Int32) o);
1128 case TypeCode.Int64:
1129 return XmlConvert.ToString ((Int64) o);
1130 case TypeCode.SByte:
1131 return XmlConvert.ToString ((SByte) o);
1132 case TypeCode.Single:
1133 return XmlConvert.ToString ((Single) o);
1134 case TypeCode.UInt16:
1135 return XmlConvert.ToString ((UInt16) o);
1136 case TypeCode.UInt32:
1137 return XmlConvert.ToString ((UInt32) o);
1138 case TypeCode.UInt64:
1139 return XmlConvert.ToString ((UInt64) o);
1141 if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1142 if (o is Guid) return XmlConvert.ToString ((Guid) o);
1143 if (o is byte[]) return Convert.ToBase64String ((byte[])o);
1144 return o.ToString ();
1147 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1149 //Write out each table in order, providing it is not
1150 //part of another table structure via a nested parent relationship
1151 foreach (DataTable table in tableCollection) {
1152 bool isTopLevel = true;
1154 foreach (DataRelation rel in table.ParentRelations) {
1162 WriteTable ( writer, table, mode, version);
1167 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1169 DataRow[] rows = new DataRow [table.Rows.Count];
1170 table.Rows.CopyTo (rows, 0);
1171 WriteTable (writer, rows, mode, version, true);
1174 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version, bool skipIfNested)
1176 //The columns can be attributes, hidden, elements, or simple content
1177 //There can be 0-1 simple content cols or 0-* elements
1178 System.Collections.ArrayList atts;
1179 System.Collections.ArrayList elements;
1180 DataColumn simple = null;
1182 if (rows.Length == 0) return;
1183 DataTable table = rows[0].Table;
1184 SplitColumns (table, out atts, out elements, out simple);
1185 //sort out the namespacing
1186 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1187 int relationCount = table.ParentRelations.Count;
1188 DataRelation oneRel = relationCount == 1 ? table.ParentRelations [0] : null;
1190 foreach (DataRow row in rows) {
1192 // Skip rows that is a child of any tables.
1193 switch (relationCount) {
1199 if (row.GetParentRow (oneRel) != null)
1204 for (int i = 0; i < table.ParentRelations.Count; i++) {
1205 DataRelation prel = table.ParentRelations [i];
1208 if (row.GetParentRow (prel) != null) {
1219 if (!row.HasVersion(version) ||
1220 (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
1221 && version == DataRowVersion.Original))
1224 // First check are all the rows null. If they are we just write empty element
1225 bool AllNulls = true;
1226 foreach (DataColumn dc in table.Columns) {
1228 if (row [dc.ColumnName, version] != DBNull.Value) {
1234 // If all of the columns were null, we have to write empty element
1236 writer.WriteElementString (XmlConvert.EncodeLocalName (table.TableName), "");
1240 WriteTableElement (writer, mode, table, row, version);
1242 foreach (DataColumn col in atts) {
1243 WriteColumnAsAttribute (writer, mode, col, row, version);
1246 if (simple != null) {
1247 writer.WriteString (WriteObjectXml (row[simple, version]));
1250 foreach (DataColumn col in elements) {
1251 WriteColumnAsElement (writer, mode, col, row, version);
1255 foreach (DataRelation relation in table.ChildRelations) {
1256 if (relation.Nested) {
1257 WriteTable (writer, row.GetChildRows (relation), mode, version, false);
1261 writer.WriteEndElement ();
1266 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1268 string colnspc = null;
1269 object rowObject = row [col, version];
1271 if (rowObject == null || rowObject == DBNull.Value)
1274 if (col.Namespace != String.Empty)
1275 colnspc = col.Namespace;
1277 //TODO check if I can get away with write element string
1278 WriteStartElement (writer, mode, colnspc, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName));
1279 writer.WriteString (WriteObjectXml (rowObject));
1280 writer.WriteEndElement ();
1283 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1285 WriteAttributeString (writer, mode, col.Namespace, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName), WriteObjectXml (row[col, version]));
1288 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1290 //sort out the namespacing
1291 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1293 WriteStartElement (writer, mode, nspc, table.Prefix, XmlConvert.EncodeLocalName (table.TableName));
1295 if (mode == XmlWriteMode.DiffGram) {
1296 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
1297 WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", XmlConvert.ToString (row.XmlRowID));
1298 string modeName = null;
1299 if (row.RowState == DataRowState.Modified)
1300 modeName = "modified";
1301 else if (row.RowState == DataRowState.Added)
1302 modeName = "inserted";
1304 if (version != DataRowVersion.Original && modeName != null)
1305 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
1309 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1311 writer.WriteStartElement (prefix, name, nspc);
1314 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1317 case XmlWriteMode.WriteSchema:
1318 writer.WriteAttributeString (prefix, name, nspc);
1320 case XmlWriteMode.DiffGram:
1321 writer.WriteAttributeString (prefix, name, nspc,stringValue);
1324 writer.WriteAttributeString (name, stringValue);
1329 internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
1331 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
1333 if (mode == XmlWriteMode.DiffGram) {
1334 SetTableRowsID (table);
1335 WriteDiffGramElement (writer);
1338 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
1340 WriteTable (writer, table, mode, DataRowVersion.Default);
1342 if (mode == XmlWriteMode.DiffGram) {
1343 writer.WriteEndElement (); //DataSet name
1344 if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
1346 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
1347 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
1348 WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
1349 writer.WriteEndElement ();
1352 writer.WriteEndElement (); // DataSet name or diffgr:diffgram
1356 private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
1358 if (ns == String.Empty)
1360 if (ns != nsmgr.DefaultNamespace) {
1361 if (nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix)) != ns) {
1362 for (int i = 1; i < int.MaxValue; i++) {
1363 string p = nsmgr.NameTable.Add ("app" + i);
1364 if (!nsmgr.HasNamespace (p)) {
1365 nsmgr.AddNamespace (p, ns);
1366 HandleExternalNamespace (p, ns, schema);
1374 XmlSchema BuildSchema ()
1376 return BuildSchema (Tables, Relations);
1379 internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
1381 string constraintPrefix = "";
1382 XmlSchema schema = new XmlSchema ();
1383 XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
1385 if (Namespace != "") {
1386 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1387 schema.ElementFormDefault = XmlSchemaForm.Qualified;
1388 schema.TargetNamespace = Namespace;
1389 constraintPrefix = XmlConstants.TnsPrefix + ":";
1392 // set the schema id
1393 string xmlNSURI = "http://www.w3.org/2000/xmlns/";
1394 schema.Id = DataSetName;
1395 XmlDocument doc = new XmlDocument ();
1396 XmlAttribute attr = null;
1397 ArrayList atts = new ArrayList ();
1399 nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
1400 nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1401 if (Namespace != "") {
1402 nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
1403 nsmgr.AddNamespace (String.Empty, Namespace);
1405 if (CheckExtendedPropertyExists ())
1406 nsmgr.AddNamespace (XmlConstants.MspropPrefix, XmlConstants.MspropNamespace);
1409 schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1411 XmlSchemaElement elem = new XmlSchemaElement ();
1412 elem.Name = XmlConvert.EncodeName (DataSetName);
1414 // Add namespaces used in DataSet components (tables, columns, ...)
1415 foreach (DataTable dt in Tables) {
1416 foreach (DataColumn col in dt.Columns)
1417 CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
1418 CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
1421 // Attributes for DataSet element
1423 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1424 attr.Value = "true";
1427 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1428 attr.Value = locale.Name;
1431 elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1433 AddExtendedPropertyAttributes (elem, ExtendedProperties, doc);
1435 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1436 elem.SchemaType = complex;
1438 XmlSchemaChoice choice = new XmlSchemaChoice ();
1439 complex.Particle = choice;
1440 choice.MaxOccursString = XmlConstants.Unbounded;
1442 //Write out schema for each table in order
1443 foreach (DataTable table in tables) {
1444 bool isTopLevel = true;
1445 foreach (DataRelation rel in table.ParentRelations) {
1453 if (table.Namespace != SafeNS (schema.TargetNamespace)) {
1454 XmlSchemaElement extElem = new XmlSchemaElement ();
1455 extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
1456 choice.Items.Add (extElem);
1459 choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
1463 schema.Items.Add (elem);
1465 AddConstraintsToSchema (elem, constraintPrefix, tables, relations, doc);
1466 foreach (string prefix in nsmgr) {
1467 string ns = nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix));
1468 if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
1469 schema.Namespaces.Add (prefix, ns);
1474 private bool CheckExtendedPropertyExists ()
1476 if (ExtendedProperties.Count > 0)
1478 foreach (DataTable dt in Tables) {
1479 if (dt.ExtendedProperties.Count > 0)
1481 foreach (DataColumn col in dt.Columns)
1482 if (col.ExtendedProperties.Count > 0)
1484 foreach (Constraint c in dt.Constraints)
1485 if (c.ExtendedProperties.Count > 0)
1488 foreach (DataRelation rel in Relations)
1489 if (rel.ExtendedProperties.Count > 0)
1494 // Add all constraints in all tables to the schema.
1495 private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations, XmlDocument doc)
1497 // first add all unique constraints.
1498 Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables, doc);
1499 // Add all foriegn key constraints.
1500 AddForeignKeys (uniqueNames, elem, constraintPrefix, relations, doc);
1503 // Add unique constaraints to the schema.
1504 // return hashtable with the names of all XmlSchemaUnique elements we created.
1505 private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, XmlDocument doc)
1507 Hashtable uniqueNames = new Hashtable();
1508 foreach (DataTable table in tables) {
1510 foreach (Constraint constraint in table.Constraints) {
1512 if (constraint is UniqueConstraint) {
1513 ArrayList attrs = new ArrayList ();
1514 XmlAttribute attrib;
1515 UniqueConstraint uqConst = (UniqueConstraint) constraint;
1516 XmlSchemaUnique uniq = new XmlSchemaUnique ();
1518 // if column of the constraint is hidden do not write the constraint.
1519 bool isHidden = false;
1520 foreach (DataColumn column in uqConst.Columns) {
1521 if (column.ColumnMapping == MappingType.Hidden) {
1530 // if constaraint name do not exist in the hashtable we can use it.
1531 if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
1532 uniq.Name = uqConst.ConstraintName;
1534 // generate new constraint name for the XmlSchemaUnique element.
1536 uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
1537 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1538 attrib.Value = uqConst.ConstraintName;
1541 if (uqConst.IsPrimaryKey) {
1542 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
1543 attrib.Value = "true";
1547 uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1549 uniq.Selector = new XmlSchemaXPath();
1550 uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
1551 XmlSchemaXPath field;
1552 foreach (DataColumn column in uqConst.Columns) {
1553 field = new XmlSchemaXPath();
1554 string typePrefix = column.ColumnMapping == MappingType.Attribute ? "@" : "";
1555 field.XPath = typePrefix + constraintPrefix + column.ColumnName;
1556 uniq.Fields.Add(field);
1559 AddExtendedPropertyAttributes (uniq, constraint.ExtendedProperties, doc);
1561 elem.Constraints.Add (uniq);
1562 uniqueNames.Add (uniq.Name, null);
1569 // Add the foriegn keys to the schema.
1570 private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations, XmlDocument doc)
1572 if (relations == null) return;
1574 foreach (DataRelation rel in relations) {
1576 if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
1579 bool isHidden = false;
1580 foreach (DataColumn col in rel.ParentColumns) {
1581 if (col.ColumnMapping == MappingType.Hidden) {
1586 foreach (DataColumn col in rel.ChildColumns) {
1587 if (col.ColumnMapping == MappingType.Hidden) {
1595 ArrayList attrs = new ArrayList ();
1596 XmlAttribute attrib;
1597 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1598 keyRef.Name = rel.RelationName;
1599 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1600 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1602 string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
1603 // first try to find the concatenated name. If we didn't find it - use constraint name.
1604 if (uniqueNames.ContainsKey (concatName)) {
1605 keyRef.Refer = new XmlQualifiedName(concatName);
1608 keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
1612 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1613 attrib.Value = "true";
1617 keyRef.Selector = new XmlSchemaXPath();
1618 keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
1619 XmlSchemaXPath field;
1620 foreach (DataColumn column in rel.ChildColumns) {
1621 field = new XmlSchemaXPath();
1622 string typePrefix = column.ColumnMapping == MappingType.Attribute ? "@" : "";
1623 field.XPath = typePrefix + constraintPrefix + column.ColumnName;
1624 keyRef.Fields.Add(field);
1627 keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1628 AddExtendedPropertyAttributes (keyRef, rel.ExtendedProperties, doc);
1630 elem.Constraints.Add (keyRef);
1634 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
1640 ArrayList xattrs = new ArrayList();
1643 SplitColumns (table, out atts, out elements, out simple);
1645 XmlSchemaElement elem = new XmlSchemaElement ();
1646 elem.Name = table.TableName;
1648 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1649 elem.SchemaType = complex;
1651 XmlSchemaObjectCollection schemaAttributes = null;
1653 if (simple != null) {
1654 // add simpleContent
1655 XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
1656 complex.ContentModel = simpleContent;
1658 // add column name attribute
1659 XmlAttribute[] xlmAttrs = new XmlAttribute [2];
1660 xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
1661 xlmAttrs[0].Value = simple.ColumnName;
1663 // add ordinal attribute
1664 xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
1665 xlmAttrs[1].Value = XmlConvert.ToString (simple.Ordinal);
1666 simpleContent.UnhandledAttributes = xlmAttrs;
1670 XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
1671 simpleContent.Content = extension;
1672 extension.BaseTypeName = MapType (simple.DataType);
1673 schemaAttributes = extension.Attributes;
1675 schemaAttributes = complex.Attributes;
1676 //A sequence of element types or a simple content node
1678 XmlSchemaSequence seq = new XmlSchemaSequence ();
1680 foreach (DataColumn col in elements) {
1682 // Add element for the column.
1683 XmlSchemaElement colElem = new XmlSchemaElement ();
1684 colElem.Name = col.ColumnName;
1686 if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
1687 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1688 xattr.Value = col.Caption;
1692 if (col.AutoIncrement == true) {
1693 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
1694 xattr.Value = "true";
1698 if (col.AutoIncrementSeed != 0) {
1699 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
1700 xattr.Value = XmlConvert.ToString (col.AutoIncrementSeed);
1704 if (col.DefaultValue.ToString () != String.Empty)
1705 colElem.DefaultValue = WriteObjectXml (col.DefaultValue);
1708 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ReadOnly, XmlConstants.MsdataNamespace);
1709 xattr.Value = "true";
1713 if (col.MaxLength < 0)
1714 colElem.SchemaTypeName = MapType (col.DataType);
1716 if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string)
1717 && col.DataType != typeof (char)) {
1718 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
1719 xattr.Value = col.DataType.AssemblyQualifiedName;
1723 if (col.AllowDBNull) {
1724 colElem.MinOccurs = 0;
1727 //writer.WriteAttributeString (XmlConstants.MsdataPrefix,
1728 // XmlConstants.Ordinal,
1729 // XmlConstants.MsdataNamespace,
1730 // col.Ordinal.ToString ());
1732 // Write SimpleType if column have MaxLength
1733 if (col.MaxLength > -1) {
1734 colElem.SchemaType = GetTableSimpleType (doc, col);
1737 colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
1738 AddExtendedPropertyAttributes (colElem, col.ExtendedProperties, doc);
1739 seq.Items.Add (colElem);
1742 foreach (DataRelation rel in table.ChildRelations) {
1744 if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
1745 XmlSchemaElement el = new XmlSchemaElement ();
1746 el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
1748 XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
1750 el.MaxOccursString = "unbounded";
1751 XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
1753 el.SchemaType = null;
1754 el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
1755 schemaToAdd.Items.Add (ct);
1761 if (seq.Items.Count > 0)
1762 complex.Particle = seq;
1765 //Then a list of attributes
1766 foreach (DataColumn col in atts) {
1767 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1768 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1769 att.Name = col.ColumnName;
1770 if (col.Namespace != String.Empty) {
1771 att.Form = XmlSchemaForm.Qualified;
1772 string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
1773 att.Name = prefix + ":" + col.ColumnName;
1774 // FIXME: Handle prefix mapping correctly.
1775 schemaToAdd.Namespaces.Add (prefix, col.Namespace);
1777 if (!col.AllowDBNull)
1778 att.Use = XmlSchemaUse.Required;
1780 if (col.MaxLength > -1)
1781 att.SchemaType = GetTableSimpleType (doc, col);
1783 att.SchemaTypeName = MapType (col.DataType);
1784 // FIXME: what happens if extended properties are set on attribute columns??
1785 if (!col.AllowDBNull)
1786 att.Use = XmlSchemaUse.Required;
1787 if (col.DefaultValue.ToString () != String.Empty)
1788 att.DefaultValue = WriteObjectXml (col.DefaultValue);
1791 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ReadOnly, XmlConstants.MsdataNamespace);
1792 xattr.Value = "true";
1796 att.UnhandledAttributes = xattrs.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1798 if (col.MaxLength > -1)
1799 att.SchemaType = GetTableSimpleType (doc, col);
1801 att.SchemaTypeName = MapType (col.DataType);
1802 schemaAttributes.Add (att);
1805 AddExtendedPropertyAttributes (elem, table.ExtendedProperties, doc);
1810 private void AddExtendedPropertyAttributes (XmlSchemaAnnotated xsobj, PropertyCollection props, XmlDocument doc)
1812 ArrayList attList = new ArrayList ();
1813 XmlAttribute xmlAttr;
1815 if (xsobj.UnhandledAttributes != null)
1816 attList.AddRange (xsobj.UnhandledAttributes);
1818 // add extended properties to xs:element
1819 foreach (DictionaryEntry de in props) {
1820 xmlAttr = doc.CreateAttribute (XmlConstants.MspropPrefix, XmlConvert.EncodeName (de.Key.ToString ()), XmlConstants.MspropNamespace);
1821 xmlAttr.Value = de.Value != null ? WriteObjectXml (de.Value) : String.Empty;
1822 attList.Add (xmlAttr);
1824 if (attList.Count > 0)
1825 xsobj.UnhandledAttributes = attList.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1828 private string SafeNS (string ns)
1830 return ns != null ? ns : String.Empty;
1833 private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
1835 foreach (XmlSchemaExternal ext in schema.Includes) {
1836 XmlSchemaImport imp = ext as XmlSchemaImport;
1837 if (imp != null && imp.Namespace == ns)
1838 return; // nothing to do
1840 XmlSchemaImport i = new XmlSchemaImport ();
1842 i.SchemaLocation = "_" + prefix + ".xsd";
1843 schema.Includes.Add (i);
1846 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1849 XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1852 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1853 restriction.BaseTypeName = MapType (col.DataType);
1856 XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1857 max.Value = XmlConvert.ToString (col.MaxLength);
1858 restriction.Facets.Add (max);
1860 simple.Content = restriction;
1864 private void DoWriteXmlSchema (XmlWriter writer)
1866 BuildSchema ().Write (writer);
1870 /// Helper function to split columns into attributes elements and simple
1873 private void SplitColumns (DataTable table,
1875 out ArrayList elements,
1876 out DataColumn simple)
1878 //The columns can be attributes, hidden, elements, or simple content
1879 //There can be 0-1 simple content cols or 0-* elements
1880 atts = new System.Collections.ArrayList ();
1881 elements = new System.Collections.ArrayList ();
1884 //Sort out the columns
1885 foreach (DataColumn col in table.Columns) {
1886 switch (col.ColumnMapping) {
1887 case MappingType.Attribute:
1890 case MappingType.Element:
1893 case MappingType.SimpleContent:
1894 if (simple != null) {
1895 throw new System.InvalidOperationException ("There may only be one simple content element");
1900 //ignore Hidden elements
1906 private void WriteDiffGramElement(XmlWriter writer)
1908 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
1909 WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1912 private void SetRowsID()
1914 foreach (DataTable Table in Tables)
1915 SetTableRowsID (Table);
1918 private void SetTableRowsID (DataTable Table)
1921 foreach (DataRow Row in Table.Rows) {
1922 Row.XmlRowID = dataRowID;
1928 private XmlQualifiedName MapType (Type type)
1930 switch (Type.GetTypeCode (type)) {
1931 case TypeCode.String: return XmlConstants.QnString;
1932 case TypeCode.Int16: return XmlConstants.QnShort;
1933 case TypeCode.Int32: return XmlConstants.QnInt;
1934 case TypeCode.Int64: return XmlConstants.QnLong;
1935 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1936 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1937 //case TypeCode.Char: return XmlConstants.QnChar;
1938 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1939 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1940 case TypeCode.Double: return XmlConstants.QnDouble;
1941 case TypeCode.SByte: return XmlConstants.QnSbyte;
1942 case TypeCode.Single: return XmlConstants.QnFloat;
1943 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1944 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1945 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1948 if (typeof (TimeSpan) == type)
1949 return XmlConstants.QnDuration;
1950 else if (typeof (System.Uri) == type)
1951 return XmlConstants.QnUri;
1952 else if (typeof (byte[]) == type)
1953 return XmlConstants.QnBase64Binary;
1954 else if (typeof (XmlQualifiedName) == type)
1955 return XmlConstants.QnXmlQualifiedName;
1957 return XmlConstants.QnString;
1960 #endregion //Private Xml Serialisation