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 using System.Collections;
19 using System.ComponentModel;
20 using System.Globalization;
21 using System.Threading;
23 using System.Runtime.Serialization;
25 using System.Xml.Schema;
26 using System.Xml.Serialization;
27 using System.Data.Common;
29 namespace System.Data {
32 [DefaultProperty ("DataSetName")]
33 [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataSetDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
36 public class DataSet : MarshalByValueComponent, IListSource,
37 ISupportInitialize, ISerializable, IXmlSerializable
39 private string dataSetName;
40 private string _namespace = "";
41 private string prefix;
42 private bool caseSensitive;
43 private bool enforceConstraints = true;
44 private DataTableCollection tableCollection;
45 private DataRelationCollection relationCollection;
46 private PropertyCollection properties;
47 private DataViewManager defaultView;
48 private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
49 internal XmlDataDocument _xmlDataDocument = null;
53 public DataSet () : this ("NewDataSet")
57 public DataSet (string name)
60 tableCollection = new DataTableCollection (this);
61 relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
62 properties = new PropertyCollection ();
63 this.prefix = String.Empty;
65 this.Locale = CultureInfo.CurrentCulture;
68 protected DataSet (SerializationInfo info, StreamingContext context) : this ()
70 GetSerializationData (info, context);
73 #endregion // Constructors
75 #region Public Properties
77 [DataCategory ("Data")]
78 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
79 [DefaultValue (false)]
80 public bool CaseSensitive {
85 caseSensitive = value;
87 foreach (DataTable table in Tables) {
88 foreach (Constraint c in table.Constraints)
89 c.AssertConstraint ();
95 [DataCategory ("Data")]
96 [DataSysDescription ("The name of this DataSet.")]
98 public string DataSetName {
99 get { return dataSetName; }
100 set { dataSetName = value; }
103 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
105 public DataViewManager DefaultViewManager {
107 if (defaultView == null)
108 defaultView = new DataViewManager (this);
113 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
114 [DefaultValue (true)]
115 public bool EnforceConstraints {
116 get { return enforceConstraints; }
118 if (value != enforceConstraints) {
119 enforceConstraints = value;
121 foreach (DataTable table in Tables) {
122 // first assert all unique constraints
123 foreach (UniqueConstraint uc in table.Constraints.UniqueConstraints)
124 uc.AssertConstraint ();
125 // then assert all foreign keys
126 foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
127 fk.AssertConstraint ();
135 [DataCategory ("Data")]
136 [DataSysDescription ("The collection that holds custom user information.")]
137 public PropertyCollection ExtendedProperties {
138 get { return properties; }
142 [DataSysDescription ("Indicates that the DataSet has errors.")]
143 public bool HasErrors {
146 for (int i = 0; i < Tables.Count; i++) {
147 if (Tables[i].HasErrors)
154 [DataCategory ("Data")]
155 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
156 public CultureInfo Locale {
161 if (locale == null || !locale.Equals (value)) {
162 // TODO: check if the new locale is valid
163 // TODO: update locale of all tables
169 public void Merge (DataRow[] rows)
171 Merge (rows, false, MissingSchemaAction.Add);
174 public void Merge (DataSet dataSet)
176 Merge (dataSet, false, MissingSchemaAction.Add);
179 public void Merge (DataTable table)
181 Merge (table, false, MissingSchemaAction.Add);
184 public void Merge (DataSet dataSet, bool preserveChanges)
186 Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
190 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
193 throw new ArgumentNullException ("rows");
194 if (!IsLegalSchemaAction (missingSchemaAction))
195 throw new ArgumentOutOfRangeException ("missingSchemaAction");
197 MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
201 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
204 throw new ArgumentNullException ("dataSet");
205 if (!IsLegalSchemaAction (missingSchemaAction))
206 throw new ArgumentOutOfRangeException ("missingSchemaAction");
208 MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
212 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
215 throw new ArgumentNullException ("table");
216 if (!IsLegalSchemaAction (missingSchemaAction))
217 throw new ArgumentOutOfRangeException ("missingSchemaAction");
219 MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
222 private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
224 if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
225 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
230 [DataCategory ("Data")]
231 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
233 public string Namespace {
234 get { return _namespace; }
236 //TODO - trigger an event if this happens?
238 value = String.Empty;
239 if (value != this._namespace)
240 RaisePropertyChanging ("Namespace");
245 [DataCategory ("Data")]
246 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
248 public string Prefix {
249 get { return prefix; }
252 value = String.Empty;
253 // Prefix cannot contain any special characters other than '_' and ':'
254 for (int i = 0; i < value.Length; i++) {
255 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
256 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
261 value = string.Empty;
263 if (value != this.prefix)
264 RaisePropertyChanging ("Prefix");
269 [DataCategory ("Data")]
270 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
272 public DataRelationCollection Relations {
274 return relationCollection;
279 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
280 public override ISite Site {
283 throw new NotImplementedException ();
288 throw new NotImplementedException ();
292 [DataCategory ("Data")]
293 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
294 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
295 public DataTableCollection Tables {
296 get { return tableCollection; }
299 #endregion // Public Properties
301 #region Public Methods
304 public void AcceptChanges ()
306 foreach (DataTable tempTable in tableCollection)
307 tempTable.AcceptChanges ();
312 if (_xmlDataDocument != null)
313 throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
314 for (int t = 0; t < tableCollection.Count; t++) {
315 tableCollection[t].Clear ();
319 public virtual DataSet Clone ()
321 DataSet Copy = new DataSet ();
322 CopyProperties (Copy);
324 foreach (DataTable Table in Tables) {
325 Copy.Tables.Add (Table.Clone ());
328 //Copy Relationships between tables after existance of tables
329 //and setting properties correctly
330 CopyRelations (Copy);
335 // Copies both the structure and data for this DataSet.
336 public DataSet Copy ()
338 DataSet Copy = new DataSet ();
339 CopyProperties (Copy);
341 // Copy DatSet's tables
342 foreach (DataTable Table in Tables)
343 Copy.Tables.Add (Table.Copy ());
345 //Copy Relationships between tables after existance of tables
346 //and setting properties correctly
347 CopyRelations (Copy);
352 private void CopyProperties (DataSet Copy)
354 Copy.CaseSensitive = CaseSensitive;
355 //Copy.Container = Container
356 Copy.DataSetName = DataSetName;
357 //Copy.DefaultViewManager
359 Copy.EnforceConstraints = EnforceConstraints;
360 if(ExtendedProperties.Count > 0) {
361 // Cannot copy extended properties directly as the property does not have a set accessor
362 Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
363 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
364 for (int i=0; i < ExtendedProperties.Count; i++)
365 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
367 Copy.Locale = Locale;
368 Copy.Namespace = Namespace;
369 Copy.Prefix = Prefix;
370 //Copy.Site = Site; // FIXME : Not sure of this.
375 private void CopyRelations (DataSet Copy)
378 //Creation of the relation contains some of the properties, and the constructor
379 //demands these values. instead changing the DataRelation constructor and behaviour the
380 //parameters are pre-configured and sent to the most general constructor
382 foreach (DataRelation MyRelation in this.Relations) {
383 string pTable = MyRelation.ParentTable.TableName;
384 string cTable = MyRelation.ChildTable.TableName;
385 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
386 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
389 foreach (DataColumn DC in MyRelation.ParentColumns) {
390 P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
396 foreach (DataColumn DC in MyRelation.ChildColumns) {
397 C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
401 DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
402 //cRel.ChildColumns = MyRelation.ChildColumns;
403 //cRel.ChildTable = MyRelation.ChildTable;
404 //cRel.ExtendedProperties = cRel.ExtendedProperties;
405 //cRel.Nested = MyRelation.Nested;
406 //cRel.ParentColumns = MyRelation.ParentColumns;
407 //cRel.ParentTable = MyRelation.ParentTable;
409 Copy.Relations.Add (cRel);
416 public DataSet GetChanges ()
418 return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
422 public DataSet GetChanges (DataRowState rowStates)
424 if (!HasChanges (rowStates))
427 DataSet copySet = Clone ();
428 Hashtable addedRows = new Hashtable ();
430 IEnumerator tableEnumerator = Tables.GetEnumerator ();
433 while (tableEnumerator.MoveNext ()) {
434 origTable = (DataTable)tableEnumerator.Current;
435 copyTable = copySet.Tables[origTable.TableName];
437 // Look for relations that have this table as child
438 IEnumerator relations = origTable.ParentRelations.GetEnumerator ();
440 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
441 while (rowEnumerator.MoveNext ()) {
442 DataRow row = (DataRow)rowEnumerator.Current;
444 if (row.IsRowChanged (rowStates))
445 AddChangedRow (addedRows, copySet, copyTable, relations, row);
451 void AddChangedRow (Hashtable addedRows, DataSet copySet, DataTable copyTable, IEnumerator relations, DataRow row)
453 if (addedRows.ContainsKey (row)) return;
456 while (relations.MoveNext ()) {
457 DataRow parentRow = row.GetParentRow ((DataRelation) relations.Current);
458 if (parentRow == null || addedRows.ContainsKey (parentRow)) continue;
459 DataTable parentCopyTable = copySet.Tables [parentRow.Table.TableName];
460 AddChangedRow (addedRows, copySet, parentCopyTable, parentRow.Table.ParentRelations.GetEnumerator (), parentRow);
463 DataRow newRow = copyTable.NewRow ();
464 copyTable.Rows.Add (newRow);
465 row.CopyValuesToRow (newRow);
466 newRow.XmlRowID = row.XmlRowID;
467 addedRows.Add (row,row);
472 public DataTableReader GetDataReader (DataTable[] dataTables)
474 throw new NotImplementedException ();
478 public DataTableReader GetDataReader ()
480 throw new NotImplementedException ();
484 public string GetXml ()
486 StringWriter Writer = new StringWriter ();
487 WriteXml (Writer, XmlWriteMode.IgnoreSchema);
488 return Writer.ToString ();
491 public string GetXmlSchema ()
493 StringWriter Writer = new StringWriter ();
494 WriteXmlSchema (Writer);
495 return Writer.ToString ();
499 public bool HasChanges ()
501 return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
505 public bool HasChanges (DataRowState rowState)
507 if (((int)rowState & 0xffffffe0) != 0)
508 throw new ArgumentOutOfRangeException ("rowState");
510 DataTableCollection tableCollection = Tables;
512 DataRowCollection rowCollection;
515 for (int i = 0; i < tableCollection.Count; i++) {
516 table = tableCollection[i];
517 rowCollection = table.Rows;
518 for (int j = 0; j < rowCollection.Count; j++) {
519 row = rowCollection[j];
520 if ((row.RowState & rowState) != 0)
528 [MonoTODO ("Consider ignored namespace array")]
529 public void InferXmlSchema (XmlReader reader, string[] nsArray)
534 XmlDocument doc = new XmlDocument ();
536 InferXmlSchema (doc, nsArray);
538 XmlDataLoader Loader = new XmlDataLoader (this);
539 Loader.LoadData (reader, XmlReadMode.InferSchema);
543 private void InferXmlSchema (XmlDocument doc, string [] nsArray)
546 XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, false);
548 XmlDataInferenceLoader.Infer (this, new XmlNodeReader (doc), XmlReadMode.InferSchema, false);
552 public void InferXmlSchema (Stream stream, string[] nsArray)
554 InferXmlSchema (new XmlTextReader (stream), nsArray);
557 public void InferXmlSchema (TextReader reader, string[] nsArray)
559 InferXmlSchema (new XmlTextReader (reader), nsArray);
562 public void InferXmlSchema (string fileName, string[] nsArray)
564 XmlTextReader reader = new XmlTextReader (fileName);
566 InferXmlSchema (reader, nsArray);
574 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
576 throw new NotImplementedException ();
580 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
582 throw new NotImplementedException ();
586 public virtual void RejectChanges ()
589 bool oldEnforceConstraints = this.EnforceConstraints;
590 this.EnforceConstraints = false;
592 for (i = 0; i < this.Tables.Count;i++)
593 this.Tables[i].RejectChanges ();
595 this.EnforceConstraints = oldEnforceConstraints;
598 public virtual void Reset ()
600 IEnumerator constraintEnumerator;
602 // first we remove all ForeignKeyConstraints (if we will not do that
603 // we will get an exception when clearing the tables).
604 for (int i = 0; i < Tables.Count; i++) {
605 ConstraintCollection cc = Tables[i].Constraints;
606 for (int j = 0; j < cc.Count; j++) {
607 if (cc[j] is ForeignKeyConstraint)
617 public void WriteXml (Stream stream)
619 XmlTextWriter writer = new XmlTextWriter (stream, null);
620 writer.Formatting = Formatting.Indented;
625 /// Writes the current data for the DataSet to the specified file.
627 /// <param name="filename">Fully qualified filename to write to</param>
628 public void WriteXml (string fileName)
630 XmlTextWriter writer = new XmlTextWriter (fileName, null);
631 writer.Formatting = Formatting.Indented;
632 writer.WriteStartDocument (true);
637 writer.WriteEndDocument ();
642 public void WriteXml (TextWriter writer)
644 XmlTextWriter xwriter = new XmlTextWriter (writer);
645 xwriter.Formatting = Formatting.Indented;
649 public void WriteXml (XmlWriter writer)
651 WriteXml (writer, XmlWriteMode.IgnoreSchema);
654 public void WriteXml (string filename, XmlWriteMode mode)
656 XmlTextWriter writer = new XmlTextWriter (filename, null);
657 writer.Formatting = Formatting.Indented;
658 writer.WriteStartDocument (true);
661 WriteXml (writer, mode);
664 writer.WriteEndDocument ();
669 public void WriteXml (Stream stream, XmlWriteMode mode)
671 XmlTextWriter writer = new XmlTextWriter (stream, null);
672 writer.Formatting = Formatting.Indented;
673 WriteXml (writer, mode);
676 public void WriteXml (TextWriter writer, XmlWriteMode mode)
678 XmlTextWriter xwriter = new XmlTextWriter (writer);
679 xwriter.Formatting = Formatting.Indented;
680 WriteXml (xwriter, mode);
683 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
685 if (mode == XmlWriteMode.DiffGram) {
687 WriteDiffGramElement(writer);
690 // It should not write when there is no content to be written
691 bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
692 for (int n = 0; n < tableCollection.Count && !shouldOutputContent; n++)
693 shouldOutputContent = tableCollection [n].Rows.Count > 0;
695 if (shouldOutputContent) {
696 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
698 if (mode == XmlWriteMode.WriteSchema)
699 DoWriteXmlSchema (writer);
701 WriteTables (writer, mode, Tables, DataRowVersion.Default);
702 writer.WriteEndElement ();
705 if (mode == XmlWriteMode.DiffGram) {
706 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
708 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
709 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
710 WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
711 writer.WriteEndElement ();
715 if (mode == XmlWriteMode.DiffGram)
716 writer.WriteEndElement (); // diffgr:diffgram
721 public void WriteXmlSchema (Stream stream)
723 XmlTextWriter writer = new XmlTextWriter (stream, null );
724 writer.Formatting = Formatting.Indented;
725 WriteXmlSchema (writer);
728 public void WriteXmlSchema (string fileName)
730 XmlTextWriter writer = new XmlTextWriter (fileName, null);
732 writer.Formatting = Formatting.Indented;
733 writer.WriteStartDocument (true);
734 WriteXmlSchema (writer);
736 writer.WriteEndDocument ();
741 public void WriteXmlSchema (TextWriter writer)
743 XmlTextWriter xwriter = new XmlTextWriter (writer);
745 xwriter.Formatting = Formatting.Indented;
746 // xwriter.WriteStartDocument ();
747 WriteXmlSchema (xwriter);
749 // xwriter.WriteEndDocument ();
754 public void WriteXmlSchema (XmlWriter writer)
756 //Create a skeleton doc and then write the schema
757 //proper which is common to the WriteXml method in schema mode
758 DoWriteXmlSchema (writer);
761 public void ReadXmlSchema (Stream stream)
763 XmlReader reader = new XmlTextReader (stream, null);
764 ReadXmlSchema (reader);
767 public void ReadXmlSchema (string str)
769 XmlReader reader = new XmlTextReader (str);
771 ReadXmlSchema (reader);
778 public void ReadXmlSchema (TextReader treader)
780 XmlReader reader = new XmlTextReader (treader);
781 ReadXmlSchema (reader);
784 public void ReadXmlSchema (XmlReader reader)
787 new XmlSchemaDataImporter (this, reader).Process ();
789 XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
790 SchemaMapper.Read (reader);
794 public XmlReadMode ReadXml (Stream stream)
796 return ReadXml (new XmlTextReader (stream));
799 public XmlReadMode ReadXml (string str)
801 XmlTextReader reader = new XmlTextReader (str);
803 return ReadXml (reader);
810 public XmlReadMode ReadXml (TextReader reader)
812 return ReadXml (new XmlTextReader (reader));
815 public XmlReadMode ReadXml (XmlReader r)
817 return ReadXml (r, XmlReadMode.Auto);
820 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
822 return ReadXml (new XmlTextReader (stream), mode);
825 public XmlReadMode ReadXml (string str, XmlReadMode mode)
827 XmlTextReader reader = new XmlTextReader (str);
829 return ReadXml (reader, mode);
836 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
838 return ReadXml (new XmlTextReader (reader), mode);
842 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
844 switch (reader.ReadState) {
845 case ReadState.EndOfFile:
846 case ReadState.Error:
847 case ReadState.Closed:
850 // Skip XML declaration and prolog
851 reader.MoveToContent();
855 XmlReadMode Result = mode;
857 // If diffgram, then read the first element as diffgram
858 if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
860 case XmlReadMode.Auto:
861 case XmlReadMode.DiffGram:
862 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
863 DiffLoader.Load (reader);
864 // (and leave rest of the reader as is)
865 return XmlReadMode.DiffGram;
866 case XmlReadMode.Fragment:
868 // (and continue to read)
872 // (and leave rest of the reader as is)
876 // If schema, then read the first element as schema
877 if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
879 case XmlReadMode.IgnoreSchema:
880 case XmlReadMode.InferSchema:
882 // (and break up read)
884 case XmlReadMode.Fragment:
885 ReadXmlSchema (reader);
886 // (and continue to read)
888 case XmlReadMode.Auto:
889 if (Tables.Count == 0) {
890 ReadXmlSchema (reader);
891 return XmlReadMode.ReadSchema;
893 // otherwise just ignore and return IgnoreSchema
895 return XmlReadMode.IgnoreSchema;
898 ReadXmlSchema (reader);
899 // (and leave rest of the reader as is)
900 return mode; // When DiffGram, return DiffGram
903 // Otherwise, read as dataset... but only when required.
904 bool inferedSchema = false;
906 case XmlReadMode.Auto:
907 if (Tables.Count > 0)
908 goto case XmlReadMode.IgnoreSchema;
910 goto case XmlReadMode.InferSchema;
911 case XmlReadMode.InferSchema:
912 #if true // sync with the switch immediately below
913 XmlDocument doc = new XmlDocument ();
915 doc.AppendChild (doc.ReadNode (reader));
916 reader.MoveToContent ();
917 if (doc.DocumentElement != null)
919 } while (!reader.EOF);
920 InferXmlSchema (doc, null);
921 reader = new XmlNodeReader (doc);
923 inferedSchema = true;
925 case XmlReadMode.IgnoreSchema:
926 case XmlReadMode.Fragment:
932 #if true // sync with the switch immediately above
933 XmlDataReader.ReadXml (this, reader, mode);
935 return XmlReadMode.InferSchema;
936 return mode == XmlReadMode.Auto ? XmlReadMode.IgnoreSchema : mode;
938 XmlDataLoader Loader = new XmlDataLoader (this);
939 return Loader.LoadData (reader, mode);
942 #endregion // Public Methods
944 #region Public Events
946 [DataCategory ("Action")]
947 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
948 public event MergeFailedEventHandler MergeFailed;
950 #endregion // Public Events
958 #endregion Destructors
960 #region IListSource methods
961 IList IListSource.GetList ()
963 return DefaultViewManager;
966 bool IListSource.ContainsListCollection {
971 #endregion IListSource methods
973 #region ISupportInitialize methods
974 public void BeginInit ()
978 public void EndInit ()
983 #region ISerializable
984 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
986 StringWriter sw = new StringWriter ();
987 XmlTextWriter writer = new XmlTextWriter (sw);
988 DoWriteXmlSchema (writer);
990 si.AddValue ("XmlSchema", sw.ToString ());
992 sw = new StringWriter ();
993 writer = new XmlTextWriter (sw);
994 WriteXml (writer, XmlWriteMode.DiffGram);
996 si.AddValue ("XmlDiffGram", sw.ToString ());
1000 #region Protected Methods
1001 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
1003 string s = info.GetValue ("XmlSchema", typeof (String)) as String;
1004 XmlTextReader reader = new XmlTextReader (new StringReader (s));
1005 ReadXmlSchema (reader);
1008 s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
1009 reader = new XmlTextReader (new StringReader (s));
1010 ReadXml (reader, XmlReadMode.DiffGram);
1015 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
1020 protected virtual void ReadXmlSerializable (XmlReader reader)
1022 reader.MoveToContent ();
1023 reader.ReadStartElement ();
1024 reader.MoveToContent ();
1025 ReadXmlSchema (reader);
1026 reader.MoveToContent ();
1027 ReadXml (reader, XmlReadMode.DiffGram);
1028 reader.MoveToContent ();
1029 reader.ReadEndElement ();
1032 void IXmlSerializable.ReadXml (XmlReader reader)
1034 ReadXmlSerializable(reader);
1037 void IXmlSerializable.WriteXml (XmlWriter writer)
1039 DoWriteXmlSchema (writer);
1040 WriteXml (writer, XmlWriteMode.DiffGram);
1043 XmlSchema IXmlSerializable.GetSchema ()
\r
1045 return BuildSchema ();
\r
1048 protected virtual bool ShouldSerializeRelations ()
1053 protected virtual bool ShouldSerializeTables ()
1059 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
1064 protected virtual void OnRemoveRelation (DataRelation relation)
1069 protected virtual void OnRemoveTable (DataTable table)
1073 protected internal virtual void OnMergeFailed (MergeFailedEventArgs e)
1075 if (MergeFailed != null)
1076 MergeFailed (this, e);
1080 protected internal void RaisePropertyChanging (string name)
1085 #region Private Xml Serialisation
1087 private string WriteObjectXml (object o)
1089 switch (Type.GetTypeCode (o.GetType ())) {
1090 case TypeCode.Boolean:
1091 return XmlConvert.ToString ((Boolean) o);
1093 return XmlConvert.ToString ((Byte) o);
1095 return XmlConvert.ToString ((Char) o);
1096 case TypeCode.DateTime:
1097 return XmlConvert.ToString ((DateTime) o);
1098 case TypeCode.Decimal:
1099 return XmlConvert.ToString ((Decimal) o);
1100 case TypeCode.Double:
1101 return XmlConvert.ToString ((Double) o);
1102 case TypeCode.Int16:
1103 return XmlConvert.ToString ((Int16) o);
1104 case TypeCode.Int32:
1105 return XmlConvert.ToString ((Int32) o);
1106 case TypeCode.Int64:
1107 return XmlConvert.ToString ((Int64) o);
1108 case TypeCode.SByte:
1109 return XmlConvert.ToString ((SByte) o);
1110 case TypeCode.Single:
1111 return XmlConvert.ToString ((Single) o);
1112 case TypeCode.UInt16:
1113 return XmlConvert.ToString ((UInt16) o);
1114 case TypeCode.UInt32:
1115 return XmlConvert.ToString ((UInt32) o);
1116 case TypeCode.UInt64:
1117 return XmlConvert.ToString ((UInt64) o);
1119 if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1120 if (o is Guid) return XmlConvert.ToString ((Guid) o);
1121 if (o is byte[]) return Convert.ToBase64String ((byte[])o);
1122 return o.ToString ();
1125 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1127 //Write out each table in order, providing it is not
1128 //part of another table structure via a nested parent relationship
1129 foreach (DataTable table in tableCollection) {
1130 bool isTopLevel = true;
1131 foreach (DataRelation rel in table.ParentRelations) {
1139 WriteTable ( writer, table, mode, version);
1144 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1146 DataRow[] rows = new DataRow [table.Rows.Count];
1147 table.Rows.CopyTo (rows, 0);
1148 WriteTable (writer, rows, mode, version);
1151 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version)
1153 //The columns can be attributes, hidden, elements, or simple content
1154 //There can be 0-1 simple content cols or 0-* elements
1155 System.Collections.ArrayList atts;
1156 System.Collections.ArrayList elements;
1157 DataColumn simple = null;
1159 if (rows.Length == 0) return;
1160 DataTable table = rows[0].Table;
1161 SplitColumns (table, out atts, out elements, out simple);
1162 //sort out the namespacing
1163 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1165 foreach (DataRow row in rows) {
1166 if (!row.HasVersion(version) ||
1167 (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
1168 && version == DataRowVersion.Original))
1171 // First check are all the rows null. If they are we just write empty element
1172 bool AllNulls = true;
1173 foreach (DataColumn dc in table.Columns) {
1175 if (row [dc.ColumnName, version] != DBNull.Value) {
1181 // If all of the columns were null, we have to write empty element
1183 writer.WriteElementString (table.TableName, "");
1187 WriteTableElement (writer, mode, table, row, version);
1189 foreach (DataColumn col in atts) {
1190 WriteColumnAsAttribute (writer, mode, col, row, version);
1193 if (simple != null) {
1194 writer.WriteString (WriteObjectXml (row[simple, version]));
1197 foreach (DataColumn col in elements) {
1198 WriteColumnAsElement (writer, mode, col, row, version);
1202 foreach (DataRelation relation in table.ChildRelations) {
1203 if (relation.Nested) {
1204 WriteTable (writer, row.GetChildRows (relation), mode, version);
1208 writer.WriteEndElement ();
1213 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1215 string colnspc = null;
1216 object rowObject = row [col, version];
1218 if (rowObject == null || rowObject == DBNull.Value)
1221 if (col.Namespace != String.Empty)
1222 colnspc = col.Namespace;
1224 //TODO check if I can get away with write element string
1225 WriteStartElement (writer, mode, colnspc, col.Prefix, col.ColumnName);
1226 writer.WriteString (WriteObjectXml (rowObject));
1227 writer.WriteEndElement ();
1230 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1232 WriteAttributeString (writer, mode, col.Namespace, col.Prefix, col.ColumnName, row[col, version].ToString ());
1235 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1237 //sort out the namespacing
1238 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1240 WriteStartElement (writer, mode, nspc, table.Prefix, table.TableName);
1242 if (mode == XmlWriteMode.DiffGram) {
1243 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
1244 WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", row.XmlRowID.ToString());
1245 string modeName = null;
1246 if (row.RowState == DataRowState.Modified)
1247 modeName = "modified";
1248 else if (row.RowState == DataRowState.Added)
1249 modeName = "inserted";
1251 if (version != DataRowVersion.Original && modeName != null)
1252 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
1256 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1258 writer.WriteStartElement (prefix, name, nspc);
1261 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1264 case XmlWriteMode.WriteSchema:
1265 writer.WriteAttributeString (prefix, name, nspc);
1267 case XmlWriteMode.DiffGram:
1268 writer.WriteAttributeString (prefix, name, nspc,stringValue);
1271 writer.WriteAttributeString (name, stringValue);
1276 internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
1278 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
1280 if (mode == XmlWriteMode.DiffGram) {
1281 SetTableRowsID (table);
1282 WriteDiffGramElement (writer);
1285 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
1287 WriteTable (writer, table, mode, DataRowVersion.Default);
1289 if (mode == XmlWriteMode.DiffGram) {
1290 writer.WriteEndElement (); //DataSet name
1291 if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
1293 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
1294 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
1295 WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
1296 writer.WriteEndElement ();
1299 writer.WriteEndElement (); // DataSet name or diffgr:diffgram
1302 private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
1304 if (ns == String.Empty)
1306 if (ns != nsmgr.DefaultNamespace) {
1307 if (nsmgr.LookupNamespace (prefix) != ns) {
1308 for (int i = 1; i < int.MaxValue; i++) {
1309 string p = nsmgr.NameTable.Add ("app" + i);
1310 if (!nsmgr.HasNamespace (p)) {
1311 nsmgr.AddNamespace (p, ns);
1312 HandleExternalNamespace (p, ns, schema);
1320 XmlSchema BuildSchema ()
1322 return BuildSchema (Tables, Relations);
1325 internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
1327 string constraintPrefix = "";
1328 XmlSchema schema = new XmlSchema ();
1329 XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
1331 if (Namespace != "") {
1332 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1333 schema.ElementFormDefault = XmlSchemaForm.Qualified;
1334 schema.TargetNamespace = Namespace;
1335 constraintPrefix = XmlConstants.TnsPrefix + ":";
1338 // set the schema id
1339 string xmlNSURI = "http://www.w3.org/2000/xmlns/";
1340 schema.Id = DataSetName;
1341 XmlDocument doc = new XmlDocument ();
1342 XmlAttribute attr = null;
1343 ArrayList atts = new ArrayList ();
1345 nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
1346 nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1347 if (Namespace != "") {
1348 nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
1349 nsmgr.AddNamespace (String.Empty, Namespace);
1353 schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1355 XmlSchemaElement elem = new XmlSchemaElement ();
1356 elem.Name = XmlConvert.EncodeName (DataSetName);
1358 // Add namespaces used in DataSet components (tables, columns, ...)
1359 foreach (DataTable dt in Tables) {
1360 foreach (DataColumn col in dt.Columns)
1361 CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
1362 CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
1365 // Attributes for DataSet element
1367 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1368 attr.Value = "true";
1371 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1372 attr.Value = locale.Name;
1375 elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1377 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1378 elem.SchemaType = complex;
1380 XmlSchemaChoice choice = new XmlSchemaChoice ();
1381 complex.Particle = choice;
1382 choice.MaxOccursString = XmlConstants.Unbounded;
1384 //Write out schema for each table in order
1385 foreach (DataTable table in tables) {
1386 bool isTopLevel = true;
1387 foreach (DataRelation rel in table.ParentRelations) {
1395 if (table.Namespace != SafeNS (schema.TargetNamespace)) {
1396 XmlSchemaElement extElem = new XmlSchemaElement ();
1397 extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
1398 choice.Items.Add (extElem);
1401 choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
1405 schema.Items.Add (elem);
1407 AddConstraintsToSchema (elem, constraintPrefix, tables, relations);
1408 foreach (string prefix in nsmgr) {
1409 string ns = nsmgr.LookupNamespace (prefix);
1410 if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
1411 schema.Namespaces.Add (prefix, ns);
1416 // Add all constraints in all tables to the schema.
1417 private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations)
1419 // first add all unique constraints.
1420 Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables);
1421 // Add all foriegn key constraints.
1422 AddForeignKeys (uniqueNames, elem, constraintPrefix, relations);
1425 // Add unique constaraints to the schema.
1426 // return hashtable with the names of all XmlSchemaUnique elements we created.
1427 private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables)
1429 XmlDocument doc = new XmlDocument();
1430 Hashtable uniqueNames = new Hashtable();
1431 foreach (DataTable table in tables) {
1433 foreach (Constraint constaint in table.Constraints) {
1435 if (constaint is UniqueConstraint) {
1436 ArrayList attrs = new ArrayList ();
1437 XmlAttribute attrib;
1438 UniqueConstraint uqConst = (UniqueConstraint)constaint;
1439 XmlSchemaUnique uniq = new XmlSchemaUnique ();
1441 // if column of the constraint is hidden do not write the constraint.
1442 bool isHidden = false;
1443 foreach (DataColumn column in uqConst.Columns) {
1444 if (column.ColumnMapping == MappingType.Hidden) {
1453 // if constaraint name do not exist in the hashtable we can use it.
1454 if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
1455 uniq.Name = uqConst.ConstraintName;
1457 // generate new constraint name for the XmlSchemaUnique element.
1459 uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
1460 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1461 attrib.Value = uqConst.ConstraintName;
1464 if (uqConst.IsPrimaryKey) {
1465 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
1466 attrib.Value = "true";
1470 uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1472 uniq.Selector = new XmlSchemaXPath();
1473 uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
1474 XmlSchemaXPath field;
1475 foreach (DataColumn column in uqConst.Columns) {
1476 field = new XmlSchemaXPath();
1477 field.XPath = constraintPrefix+column.ColumnName;
1478 uniq.Fields.Add(field);
1481 elem.Constraints.Add (uniq);
1482 uniqueNames.Add (uniq.Name, null);
1489 // Add the foriegn keys to the schema.
1490 private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations)
1492 if (relations == null) return;
1494 XmlDocument doc = new XmlDocument();
1495 foreach (DataRelation rel in relations) {
1497 if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
1500 bool isHidden = false;
1501 foreach (DataColumn col in rel.ParentColumns) {
1502 if (col.ColumnMapping == MappingType.Hidden) {
1507 foreach (DataColumn col in rel.ChildColumns) {
1508 if (col.ColumnMapping == MappingType.Hidden) {
1516 ArrayList attrs = new ArrayList ();
1517 XmlAttribute attrib;
1518 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1519 keyRef.Name = rel.RelationName;
1520 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1521 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1523 string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
1524 // first try to find the concatenated name. If we didn't find it - use constraint name.
1525 if (uniqueNames.ContainsKey (concatName)) {
1526 keyRef.Refer = new XmlQualifiedName(concatName);
1529 keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
1533 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1534 attrib.Value = "true";
1538 keyRef.Selector = new XmlSchemaXPath();
1539 keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
1540 XmlSchemaXPath field;
1541 foreach (DataColumn column in rel.ChildColumns) {
1542 field = new XmlSchemaXPath();
1543 field.XPath = constraintPrefix+column.ColumnName;
1544 keyRef.Fields.Add(field);
1546 keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1547 elem.Constraints.Add (keyRef);
1551 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
1557 SplitColumns (table, out atts, out elements, out simple);
1559 XmlSchemaElement elem = new XmlSchemaElement ();
1560 elem.Name = table.TableName;
1562 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1563 elem.SchemaType = complex;
1565 XmlSchemaObjectCollection schemaAttributes = null;
1567 //TODO - what about the simple content?
1568 if (simple != null) {
1569 // add simpleContent
1570 XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
1571 complex.ContentModel = simpleContent;
1573 // add column name attribute
1574 XmlAttribute[] xlmAttrs = new XmlAttribute [2];
1575 xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
1576 xlmAttrs[0].Value = simple.ColumnName;
1578 // add ordinal attribute
1579 xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
1580 xlmAttrs[1].Value = simple.Ordinal.ToString();
1581 simpleContent.UnhandledAttributes = xlmAttrs;
1585 XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
1586 simpleContent.Content = extension;
1587 extension.BaseTypeName = MapType (simple.DataType);
1588 schemaAttributes = extension.Attributes;
1590 schemaAttributes = complex.Attributes;
1591 //A sequence of element types or a simple content node
1593 XmlSchemaSequence seq = new XmlSchemaSequence ();
1595 foreach (DataColumn col in elements) {
1597 // Add element for the column.
1598 XmlSchemaElement colElem = new XmlSchemaElement ();
1599 ArrayList xattrs = new ArrayList();
1601 colElem.Name = col.ColumnName;
1603 if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
1604 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1605 xattr.Value = col.Caption;
1609 if (col.AutoIncrement == true) {
1610 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
1611 xattr.Value = "true";
1615 if (col.AutoIncrementSeed != 0) {
1616 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
1617 xattr.Value = col.AutoIncrementSeed.ToString();
1621 if (col.DefaultValue.ToString () != String.Empty)
1622 colElem.DefaultValue = col.DefaultValue.ToString ();
1624 if (col.MaxLength < 0)
1625 colElem.SchemaTypeName = MapType (col.DataType);
1627 if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string)
1628 && col.DataType != typeof (char)) {
1629 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
1630 xattr.Value = col.DataType.AssemblyQualifiedName;
1634 if (col.AllowDBNull) {
1635 colElem.MinOccurs = 0;
1638 //writer.WriteAttributeString (XmlConstants.MsdataPrefix,
1639 // XmlConstants.Ordinal,
1640 // XmlConstants.MsdataNamespace,
1641 // col.Ordinal.ToString ());
1643 // Write SimpleType if column have MaxLength
1644 if (col.MaxLength > -1) {
1645 colElem.SchemaType = GetTableSimpleType (doc, col);
1648 colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
1649 seq.Items.Add (colElem);
1651 if (seq.Items.Count > 0)
1652 complex.Particle = seq;
1654 foreach (DataRelation rel in table.ChildRelations) {
1656 if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
1657 XmlSchemaElement el = new XmlSchemaElement ();
1658 el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
1660 XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
1661 XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
1663 el.SchemaType = null;
1664 el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
1665 schemaToAdd.Items.Add (ct);
1672 //Then a list of attributes
1673 foreach (DataColumn col in atts) {
1674 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1675 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1676 att.Name = col.ColumnName;
1677 if (col.Namespace != String.Empty) {
1678 att.Form = XmlSchemaForm.Qualified;
1679 string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
1680 att.Name = prefix + ":" + col.ColumnName;
1681 // FIXME: Handle prefix mapping correctly.
1682 schemaToAdd.Namespaces.Add (prefix, col.Namespace);
1684 att.SchemaTypeName = MapType (col.DataType);
1685 schemaAttributes.Add (att);
1691 private string SafeNS (string ns)
1693 return ns != null ? ns : String.Empty;
1696 private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
1698 foreach (XmlSchemaExternal ext in schema.Includes) {
1699 XmlSchemaImport imp = ext as XmlSchemaImport;
1700 if (imp != null && imp.Namespace == ns)
1701 return; // nothing to do
1703 XmlSchemaImport i = new XmlSchemaImport ();
1705 i.SchemaLocation = "_" + prefix + ".xsd";
1706 schema.Includes.Add (i);
1709 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1712 XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1715 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1716 restriction.BaseTypeName = MapType (col.DataType);
1719 XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1720 max.Value = XmlConvert.ToString (col.MaxLength);
1721 restriction.Facets.Add (max);
1723 simple.Content = restriction;
1727 private void DoWriteXmlSchema (XmlWriter writer)
1729 BuildSchema ().Write (writer);
1733 /// Helper function to split columns into attributes elements and simple
1736 private void SplitColumns (DataTable table,
1738 out ArrayList elements,
1739 out DataColumn simple)
1741 //The columns can be attributes, hidden, elements, or simple content
1742 //There can be 0-1 simple content cols or 0-* elements
1743 atts = new System.Collections.ArrayList ();
1744 elements = new System.Collections.ArrayList ();
1747 //Sort out the columns
1748 foreach (DataColumn col in table.Columns) {
1749 switch (col.ColumnMapping) {
1750 case MappingType.Attribute:
1753 case MappingType.Element:
1756 case MappingType.SimpleContent:
1757 if (simple != null) {
1758 throw new System.InvalidOperationException ("There may only be one simple content element");
1763 //ignore Hidden elements
1769 private void WriteDiffGramElement(XmlWriter writer)
1771 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
1772 WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1775 private void SetRowsID()
1777 foreach (DataTable Table in Tables)
1778 SetTableRowsID (Table);
1781 private void SetTableRowsID (DataTable Table)
1784 foreach (DataRow Row in Table.Rows) {
1785 Row.XmlRowID = dataRowID;
1791 private XmlQualifiedName MapType (Type type)
1793 switch (Type.GetTypeCode (type)) {
1794 case TypeCode.String: return XmlConstants.QnString;
1795 case TypeCode.Int16: return XmlConstants.QnShort;
1796 case TypeCode.Int32: return XmlConstants.QnInt;
1797 case TypeCode.Int64: return XmlConstants.QnLong;
1798 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1799 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1800 //case TypeCode.Char: return XmlConstants.QnChar;
1801 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1802 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1803 case TypeCode.Double: return XmlConstants.QnDouble;
1804 case TypeCode.SByte: return XmlConstants.QnSbyte;
1805 case TypeCode.Single: return XmlConstants.QnFloat;
1806 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1807 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1808 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1811 if (typeof (TimeSpan) == type)
1812 return XmlConstants.QnDuration;
1813 else if (typeof (System.Uri) == type)
1814 return XmlConstants.QnUri;
1815 else if (typeof (byte[]) == type)
1816 return XmlConstants.QnBase64Binary;
1817 else if (typeof (XmlQualifiedName) == type)
1818 return XmlConstants.QnXmlQualifiedName;
1820 return XmlConstants.QnString;
1823 #endregion //Private Xml Serialisation