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 public void InferXmlSchema (XmlReader reader, string[] nsArray)
532 XmlDocument doc = new XmlDocument ();
534 InferXmlSchema (doc, nsArray);
537 private void InferXmlSchema (XmlDocument doc, string [] nsArray)
539 XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, nsArray);
542 public void InferXmlSchema (Stream stream, string[] nsArray)
544 InferXmlSchema (new XmlTextReader (stream), nsArray);
547 public void InferXmlSchema (TextReader reader, string[] nsArray)
549 InferXmlSchema (new XmlTextReader (reader), nsArray);
552 public void InferXmlSchema (string fileName, string[] nsArray)
554 XmlTextReader reader = new XmlTextReader (fileName);
556 InferXmlSchema (reader, nsArray);
564 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
566 throw new NotImplementedException ();
570 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
572 throw new NotImplementedException ();
576 public virtual void RejectChanges ()
579 bool oldEnforceConstraints = this.EnforceConstraints;
580 this.EnforceConstraints = false;
582 for (i = 0; i < this.Tables.Count;i++)
583 this.Tables[i].RejectChanges ();
585 this.EnforceConstraints = oldEnforceConstraints;
588 public virtual void Reset ()
590 IEnumerator constraintEnumerator;
592 // first we remove all ForeignKeyConstraints (if we will not do that
593 // we will get an exception when clearing the tables).
594 for (int i = 0; i < Tables.Count; i++) {
595 ConstraintCollection cc = Tables[i].Constraints;
596 for (int j = 0; j < cc.Count; j++) {
597 if (cc[j] is ForeignKeyConstraint)
607 public void WriteXml (Stream stream)
609 XmlTextWriter writer = new XmlTextWriter (stream, null);
610 writer.Formatting = Formatting.Indented;
615 /// Writes the current data for the DataSet to the specified file.
617 /// <param name="filename">Fully qualified filename to write to</param>
618 public void WriteXml (string fileName)
620 XmlTextWriter writer = new XmlTextWriter (fileName, null);
621 writer.Formatting = Formatting.Indented;
622 writer.WriteStartDocument (true);
627 writer.WriteEndDocument ();
632 public void WriteXml (TextWriter writer)
634 XmlTextWriter xwriter = new XmlTextWriter (writer);
635 xwriter.Formatting = Formatting.Indented;
639 public void WriteXml (XmlWriter writer)
641 WriteXml (writer, XmlWriteMode.IgnoreSchema);
644 public void WriteXml (string filename, XmlWriteMode mode)
646 XmlTextWriter writer = new XmlTextWriter (filename, null);
647 writer.Formatting = Formatting.Indented;
648 writer.WriteStartDocument (true);
651 WriteXml (writer, mode);
654 writer.WriteEndDocument ();
659 public void WriteXml (Stream stream, XmlWriteMode mode)
661 XmlTextWriter writer = new XmlTextWriter (stream, null);
662 writer.Formatting = Formatting.Indented;
663 WriteXml (writer, mode);
666 public void WriteXml (TextWriter writer, XmlWriteMode mode)
668 XmlTextWriter xwriter = new XmlTextWriter (writer);
669 xwriter.Formatting = Formatting.Indented;
670 WriteXml (xwriter, mode);
673 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
675 if (mode == XmlWriteMode.DiffGram) {
677 WriteDiffGramElement(writer);
680 // It should not write when there is no content to be written
681 bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
682 for (int n = 0; n < tableCollection.Count && !shouldOutputContent; n++)
683 shouldOutputContent = tableCollection [n].Rows.Count > 0;
685 if (shouldOutputContent) {
686 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
688 if (mode == XmlWriteMode.WriteSchema)
689 DoWriteXmlSchema (writer);
691 WriteTables (writer, mode, Tables, DataRowVersion.Default);
692 writer.WriteEndElement ();
695 if (mode == XmlWriteMode.DiffGram) {
696 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
698 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
699 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
700 WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
701 writer.WriteEndElement ();
705 if (mode == XmlWriteMode.DiffGram)
706 writer.WriteEndElement (); // diffgr:diffgram
711 public void WriteXmlSchema (Stream stream)
713 XmlTextWriter writer = new XmlTextWriter (stream, null );
714 writer.Formatting = Formatting.Indented;
715 WriteXmlSchema (writer);
718 public void WriteXmlSchema (string fileName)
720 XmlTextWriter writer = new XmlTextWriter (fileName, null);
722 writer.Formatting = Formatting.Indented;
723 writer.WriteStartDocument (true);
724 WriteXmlSchema (writer);
726 writer.WriteEndDocument ();
731 public void WriteXmlSchema (TextWriter writer)
733 XmlTextWriter xwriter = new XmlTextWriter (writer);
735 xwriter.Formatting = Formatting.Indented;
736 // xwriter.WriteStartDocument ();
737 WriteXmlSchema (xwriter);
739 // xwriter.WriteEndDocument ();
744 public void WriteXmlSchema (XmlWriter writer)
746 //Create a skeleton doc and then write the schema
747 //proper which is common to the WriteXml method in schema mode
748 DoWriteXmlSchema (writer);
751 public void ReadXmlSchema (Stream stream)
753 XmlReader reader = new XmlTextReader (stream, null);
754 ReadXmlSchema (reader);
757 public void ReadXmlSchema (string str)
759 XmlReader reader = new XmlTextReader (str);
761 ReadXmlSchema (reader);
768 public void ReadXmlSchema (TextReader treader)
770 XmlReader reader = new XmlTextReader (treader);
771 ReadXmlSchema (reader);
774 public void ReadXmlSchema (XmlReader reader)
777 new XmlSchemaDataImporter (this, reader).Process ();
779 XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
780 SchemaMapper.Read (reader);
784 public XmlReadMode ReadXml (Stream stream)
786 return ReadXml (new XmlTextReader (stream));
789 public XmlReadMode ReadXml (string str)
791 XmlTextReader reader = new XmlTextReader (str);
793 return ReadXml (reader);
800 public XmlReadMode ReadXml (TextReader reader)
802 return ReadXml (new XmlTextReader (reader));
805 public XmlReadMode ReadXml (XmlReader r)
807 return ReadXml (r, XmlReadMode.Auto);
810 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
812 return ReadXml (new XmlTextReader (stream), mode);
815 public XmlReadMode ReadXml (string str, XmlReadMode mode)
817 XmlTextReader reader = new XmlTextReader (str);
819 return ReadXml (reader, mode);
826 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
828 return ReadXml (new XmlTextReader (reader), mode);
831 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
833 switch (reader.ReadState) {
834 case ReadState.EndOfFile:
835 case ReadState.Error:
836 case ReadState.Closed:
839 // Skip XML declaration and prolog
840 reader.MoveToContent();
844 XmlReadMode Result = mode;
846 // If diffgram, then read the first element as diffgram
847 if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
849 case XmlReadMode.Auto:
850 case XmlReadMode.DiffGram:
851 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
852 DiffLoader.Load (reader);
853 // (and leave rest of the reader as is)
854 return XmlReadMode.DiffGram;
855 case XmlReadMode.Fragment:
857 // (and continue to read)
861 // (and leave rest of the reader as is)
865 // If schema, then read the first element as schema
866 if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
868 case XmlReadMode.IgnoreSchema:
869 case XmlReadMode.InferSchema:
871 // (and break up read)
873 case XmlReadMode.Fragment:
874 ReadXmlSchema (reader);
875 // (and continue to read)
877 case XmlReadMode.Auto:
878 if (Tables.Count == 0) {
879 ReadXmlSchema (reader);
880 return XmlReadMode.ReadSchema;
882 // otherwise just ignore and return IgnoreSchema
884 return XmlReadMode.IgnoreSchema;
887 ReadXmlSchema (reader);
888 // (and leave rest of the reader as is)
889 return mode; // When DiffGram, return DiffGram
892 // Otherwise, read as dataset... but only when required.
893 bool inferedSchema = false;
895 case XmlReadMode.Auto:
896 if (Tables.Count > 0)
897 goto case XmlReadMode.IgnoreSchema;
899 goto case XmlReadMode.InferSchema;
900 case XmlReadMode.InferSchema:
901 #if true // sync with the switch immediately below
902 XmlDocument doc = new XmlDocument ();
904 doc.AppendChild (doc.ReadNode (reader));
905 reader.MoveToContent ();
906 if (doc.DocumentElement != null)
908 } while (!reader.EOF);
909 InferXmlSchema (doc, null);
910 reader = new XmlNodeReader (doc);
912 inferedSchema = true;
914 case XmlReadMode.IgnoreSchema:
915 case XmlReadMode.Fragment:
921 #if true // sync with the switch immediately above
922 XmlDataReader.ReadXml (this, reader, mode);
924 return XmlReadMode.InferSchema;
925 return mode == XmlReadMode.Auto ? XmlReadMode.IgnoreSchema : mode;
927 XmlDataLoader Loader = new XmlDataLoader (this);
928 return Loader.LoadData (reader, mode);
931 #endregion // Public Methods
933 #region Public Events
935 [DataCategory ("Action")]
936 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
937 public event MergeFailedEventHandler MergeFailed;
939 #endregion // Public Events
947 #endregion Destructors
949 #region IListSource methods
950 IList IListSource.GetList ()
952 return DefaultViewManager;
955 bool IListSource.ContainsListCollection {
960 #endregion IListSource methods
962 #region ISupportInitialize methods
963 public void BeginInit ()
967 public void EndInit ()
972 #region ISerializable
973 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
975 StringWriter sw = new StringWriter ();
976 XmlTextWriter writer = new XmlTextWriter (sw);
977 DoWriteXmlSchema (writer);
979 si.AddValue ("XmlSchema", sw.ToString ());
981 sw = new StringWriter ();
982 writer = new XmlTextWriter (sw);
983 WriteXml (writer, XmlWriteMode.DiffGram);
985 si.AddValue ("XmlDiffGram", sw.ToString ());
989 #region Protected Methods
990 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
992 string s = info.GetValue ("XmlSchema", typeof (String)) as String;
993 XmlTextReader reader = new XmlTextReader (new StringReader (s));
994 ReadXmlSchema (reader);
997 s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
998 reader = new XmlTextReader (new StringReader (s));
999 ReadXml (reader, XmlReadMode.DiffGram);
1004 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
1009 protected virtual void ReadXmlSerializable (XmlReader reader)
1011 reader.MoveToContent ();
1012 reader.ReadStartElement ();
1013 reader.MoveToContent ();
1014 ReadXmlSchema (reader);
1015 reader.MoveToContent ();
1016 ReadXml (reader, XmlReadMode.DiffGram);
1017 reader.MoveToContent ();
1018 reader.ReadEndElement ();
1021 void IXmlSerializable.ReadXml (XmlReader reader)
1023 ReadXmlSerializable(reader);
1026 void IXmlSerializable.WriteXml (XmlWriter writer)
1028 DoWriteXmlSchema (writer);
1029 WriteXml (writer, XmlWriteMode.DiffGram);
1032 XmlSchema IXmlSerializable.GetSchema ()
\r
1034 return BuildSchema ();
\r
1037 protected virtual bool ShouldSerializeRelations ()
1042 protected virtual bool ShouldSerializeTables ()
1048 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
1053 protected virtual void OnRemoveRelation (DataRelation relation)
1058 protected virtual void OnRemoveTable (DataTable table)
1062 protected internal virtual void OnMergeFailed (MergeFailedEventArgs e)
1064 if (MergeFailed != null)
1065 MergeFailed (this, e);
1069 protected internal void RaisePropertyChanging (string name)
1074 #region Private Xml Serialisation
1076 private string WriteObjectXml (object o)
1078 switch (Type.GetTypeCode (o.GetType ())) {
1079 case TypeCode.Boolean:
1080 return XmlConvert.ToString ((Boolean) o);
1082 return XmlConvert.ToString ((Byte) o);
1084 return XmlConvert.ToString ((Char) o);
1085 case TypeCode.DateTime:
1086 return XmlConvert.ToString ((DateTime) o);
1087 case TypeCode.Decimal:
1088 return XmlConvert.ToString ((Decimal) o);
1089 case TypeCode.Double:
1090 return XmlConvert.ToString ((Double) o);
1091 case TypeCode.Int16:
1092 return XmlConvert.ToString ((Int16) o);
1093 case TypeCode.Int32:
1094 return XmlConvert.ToString ((Int32) o);
1095 case TypeCode.Int64:
1096 return XmlConvert.ToString ((Int64) o);
1097 case TypeCode.SByte:
1098 return XmlConvert.ToString ((SByte) o);
1099 case TypeCode.Single:
1100 return XmlConvert.ToString ((Single) o);
1101 case TypeCode.UInt16:
1102 return XmlConvert.ToString ((UInt16) o);
1103 case TypeCode.UInt32:
1104 return XmlConvert.ToString ((UInt32) o);
1105 case TypeCode.UInt64:
1106 return XmlConvert.ToString ((UInt64) o);
1108 if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1109 if (o is Guid) return XmlConvert.ToString ((Guid) o);
1110 if (o is byte[]) return Convert.ToBase64String ((byte[])o);
1111 return o.ToString ();
1114 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1116 //Write out each table in order, providing it is not
1117 //part of another table structure via a nested parent relationship
1118 foreach (DataTable table in tableCollection) {
1119 bool isTopLevel = true;
1121 foreach (DataRelation rel in table.ParentRelations) {
1129 WriteTable ( writer, table, mode, version);
1134 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1136 DataRow[] rows = new DataRow [table.Rows.Count];
1137 table.Rows.CopyTo (rows, 0);
1138 WriteTable (writer, rows, mode, version);
1141 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version)
1143 //The columns can be attributes, hidden, elements, or simple content
1144 //There can be 0-1 simple content cols or 0-* elements
1145 System.Collections.ArrayList atts;
1146 System.Collections.ArrayList elements;
1147 DataColumn simple = null;
1149 if (rows.Length == 0) return;
1150 DataTable table = rows[0].Table;
1151 SplitColumns (table, out atts, out elements, out simple);
1152 //sort out the namespacing
1153 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1154 int relationCount = table.ParentRelations.Count;
1155 DataRelation oneRel = relationCount == 1 ? table.ParentRelations [0] : null;
1157 foreach (DataRow row in rows) {
1158 // Skip rows that is a child of any tables.
1159 switch (relationCount) {
1163 if (row.GetParentRow (oneRel) != null)
1167 for (int i = 0; i < table.ParentRelations.Count; i++)
1168 if (row.GetParentRow (table.ParentRelations [i]) != null)
1173 if (!row.HasVersion(version) ||
1174 (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
1175 && version == DataRowVersion.Original))
1178 // First check are all the rows null. If they are we just write empty element
1179 bool AllNulls = true;
1180 foreach (DataColumn dc in table.Columns) {
1182 if (row [dc.ColumnName, version] != DBNull.Value) {
1188 // If all of the columns were null, we have to write empty element
1190 writer.WriteElementString (XmlConvert.EncodeLocalName (table.TableName), "");
1194 WriteTableElement (writer, mode, table, row, version);
1196 foreach (DataColumn col in atts) {
1197 WriteColumnAsAttribute (writer, mode, col, row, version);
1200 if (simple != null) {
1201 writer.WriteString (WriteObjectXml (row[simple, version]));
1204 foreach (DataColumn col in elements) {
1205 WriteColumnAsElement (writer, mode, col, row, version);
1209 foreach (DataRelation relation in table.ChildRelations) {
1210 if (relation.Nested) {
1211 WriteTable (writer, row.GetChildRows (relation), mode, version);
1215 writer.WriteEndElement ();
1220 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1222 string colnspc = null;
1223 object rowObject = row [col, version];
1225 if (rowObject == null || rowObject == DBNull.Value)
1228 if (col.Namespace != String.Empty)
1229 colnspc = col.Namespace;
1231 //TODO check if I can get away with write element string
1232 WriteStartElement (writer, mode, colnspc, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName));
1233 writer.WriteString (WriteObjectXml (rowObject));
1234 writer.WriteEndElement ();
1237 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1239 WriteAttributeString (writer, mode, col.Namespace, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName), row[col, version].ToString ());
1242 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1244 //sort out the namespacing
1245 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1247 WriteStartElement (writer, mode, nspc, table.Prefix, XmlConvert.EncodeLocalName (table.TableName));
1249 if (mode == XmlWriteMode.DiffGram) {
1250 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
1251 WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", row.XmlRowID.ToString());
1252 string modeName = null;
1253 if (row.RowState == DataRowState.Modified)
1254 modeName = "modified";
1255 else if (row.RowState == DataRowState.Added)
1256 modeName = "inserted";
1258 if (version != DataRowVersion.Original && modeName != null)
1259 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
1263 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1265 writer.WriteStartElement (prefix, name, nspc);
1268 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1271 case XmlWriteMode.WriteSchema:
1272 writer.WriteAttributeString (prefix, name, nspc);
1274 case XmlWriteMode.DiffGram:
1275 writer.WriteAttributeString (prefix, name, nspc,stringValue);
1278 writer.WriteAttributeString (name, stringValue);
1283 internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
1285 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
1287 if (mode == XmlWriteMode.DiffGram) {
1288 SetTableRowsID (table);
1289 WriteDiffGramElement (writer);
1292 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
1294 WriteTable (writer, table, mode, DataRowVersion.Default);
1296 if (mode == XmlWriteMode.DiffGram) {
1297 writer.WriteEndElement (); //DataSet name
1298 if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
1300 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
1301 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
1302 WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
1303 writer.WriteEndElement ();
1306 writer.WriteEndElement (); // DataSet name or diffgr:diffgram
1309 private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
1311 if (ns == String.Empty)
1313 if (ns != nsmgr.DefaultNamespace) {
1314 if (nsmgr.LookupNamespace (prefix) != ns) {
1315 for (int i = 1; i < int.MaxValue; i++) {
1316 string p = nsmgr.NameTable.Add ("app" + i);
1317 if (!nsmgr.HasNamespace (p)) {
1318 nsmgr.AddNamespace (p, ns);
1319 HandleExternalNamespace (p, ns, schema);
1327 XmlSchema BuildSchema ()
1329 return BuildSchema (Tables, Relations);
1332 internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
1334 string constraintPrefix = "";
1335 XmlSchema schema = new XmlSchema ();
1336 XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
1338 if (Namespace != "") {
1339 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1340 schema.ElementFormDefault = XmlSchemaForm.Qualified;
1341 schema.TargetNamespace = Namespace;
1342 constraintPrefix = XmlConstants.TnsPrefix + ":";
1345 // set the schema id
1346 string xmlNSURI = "http://www.w3.org/2000/xmlns/";
1347 schema.Id = DataSetName;
1348 XmlDocument doc = new XmlDocument ();
1349 XmlAttribute attr = null;
1350 ArrayList atts = new ArrayList ();
1352 nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
1353 nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1354 if (Namespace != "") {
1355 nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
1356 nsmgr.AddNamespace (String.Empty, Namespace);
1360 schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1362 XmlSchemaElement elem = new XmlSchemaElement ();
1363 elem.Name = XmlConvert.EncodeName (DataSetName);
1365 // Add namespaces used in DataSet components (tables, columns, ...)
1366 foreach (DataTable dt in Tables) {
1367 foreach (DataColumn col in dt.Columns)
1368 CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
1369 CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
1372 // Attributes for DataSet element
1374 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1375 attr.Value = "true";
1378 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1379 attr.Value = locale.Name;
1382 elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1384 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1385 elem.SchemaType = complex;
1387 XmlSchemaChoice choice = new XmlSchemaChoice ();
1388 complex.Particle = choice;
1389 choice.MaxOccursString = XmlConstants.Unbounded;
1391 //Write out schema for each table in order
1392 foreach (DataTable table in tables) {
1393 bool isTopLevel = true;
1394 foreach (DataRelation rel in table.ParentRelations) {
1402 if (table.Namespace != SafeNS (schema.TargetNamespace)) {
1403 XmlSchemaElement extElem = new XmlSchemaElement ();
1404 extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
1405 choice.Items.Add (extElem);
1408 choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
1412 schema.Items.Add (elem);
1414 AddConstraintsToSchema (elem, constraintPrefix, tables, relations);
1415 foreach (string prefix in nsmgr) {
1416 string ns = nsmgr.LookupNamespace (prefix);
1417 if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
1418 schema.Namespaces.Add (prefix, ns);
1423 // Add all constraints in all tables to the schema.
1424 private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations)
1426 // first add all unique constraints.
1427 Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables);
1428 // Add all foriegn key constraints.
1429 AddForeignKeys (uniqueNames, elem, constraintPrefix, relations);
1432 // Add unique constaraints to the schema.
1433 // return hashtable with the names of all XmlSchemaUnique elements we created.
1434 private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables)
1436 XmlDocument doc = new XmlDocument();
1437 Hashtable uniqueNames = new Hashtable();
1438 foreach (DataTable table in tables) {
1440 foreach (Constraint constaint in table.Constraints) {
1442 if (constaint is UniqueConstraint) {
1443 ArrayList attrs = new ArrayList ();
1444 XmlAttribute attrib;
1445 UniqueConstraint uqConst = (UniqueConstraint)constaint;
1446 XmlSchemaUnique uniq = new XmlSchemaUnique ();
1448 // if column of the constraint is hidden do not write the constraint.
1449 bool isHidden = false;
1450 foreach (DataColumn column in uqConst.Columns) {
1451 if (column.ColumnMapping == MappingType.Hidden) {
1460 // if constaraint name do not exist in the hashtable we can use it.
1461 if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
1462 uniq.Name = uqConst.ConstraintName;
1464 // generate new constraint name for the XmlSchemaUnique element.
1466 uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
1467 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1468 attrib.Value = uqConst.ConstraintName;
1471 if (uqConst.IsPrimaryKey) {
1472 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
1473 attrib.Value = "true";
1477 uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1479 uniq.Selector = new XmlSchemaXPath();
1480 uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
1481 XmlSchemaXPath field;
1482 foreach (DataColumn column in uqConst.Columns) {
1483 field = new XmlSchemaXPath();
1484 field.XPath = constraintPrefix+column.ColumnName;
1485 uniq.Fields.Add(field);
1488 elem.Constraints.Add (uniq);
1489 uniqueNames.Add (uniq.Name, null);
1496 // Add the foriegn keys to the schema.
1497 private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations)
1499 if (relations == null) return;
1501 XmlDocument doc = new XmlDocument();
1502 foreach (DataRelation rel in relations) {
1504 if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
1507 bool isHidden = false;
1508 foreach (DataColumn col in rel.ParentColumns) {
1509 if (col.ColumnMapping == MappingType.Hidden) {
1514 foreach (DataColumn col in rel.ChildColumns) {
1515 if (col.ColumnMapping == MappingType.Hidden) {
1523 ArrayList attrs = new ArrayList ();
1524 XmlAttribute attrib;
1525 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1526 keyRef.Name = rel.RelationName;
1527 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1528 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1530 string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
1531 // first try to find the concatenated name. If we didn't find it - use constraint name.
1532 if (uniqueNames.ContainsKey (concatName)) {
1533 keyRef.Refer = new XmlQualifiedName(concatName);
1536 keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
1540 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1541 attrib.Value = "true";
1545 keyRef.Selector = new XmlSchemaXPath();
1546 keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
1547 XmlSchemaXPath field;
1548 foreach (DataColumn column in rel.ChildColumns) {
1549 field = new XmlSchemaXPath();
1550 field.XPath = constraintPrefix+column.ColumnName;
1551 keyRef.Fields.Add(field);
1553 keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1554 elem.Constraints.Add (keyRef);
1558 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
1564 SplitColumns (table, out atts, out elements, out simple);
1566 XmlSchemaElement elem = new XmlSchemaElement ();
1567 elem.Name = table.TableName;
1569 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1570 elem.SchemaType = complex;
1572 XmlSchemaObjectCollection schemaAttributes = null;
1574 //TODO - what about the simple content?
1575 if (simple != null) {
1576 // add simpleContent
1577 XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
1578 complex.ContentModel = simpleContent;
1580 // add column name attribute
1581 XmlAttribute[] xlmAttrs = new XmlAttribute [2];
1582 xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
1583 xlmAttrs[0].Value = simple.ColumnName;
1585 // add ordinal attribute
1586 xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
1587 xlmAttrs[1].Value = simple.Ordinal.ToString();
1588 simpleContent.UnhandledAttributes = xlmAttrs;
1592 XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
1593 simpleContent.Content = extension;
1594 extension.BaseTypeName = MapType (simple.DataType);
1595 schemaAttributes = extension.Attributes;
1597 schemaAttributes = complex.Attributes;
1598 //A sequence of element types or a simple content node
1600 XmlSchemaSequence seq = new XmlSchemaSequence ();
1602 foreach (DataColumn col in elements) {
1604 // Add element for the column.
1605 XmlSchemaElement colElem = new XmlSchemaElement ();
1606 ArrayList xattrs = new ArrayList();
1608 colElem.Name = col.ColumnName;
1610 if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
1611 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1612 xattr.Value = col.Caption;
1616 if (col.AutoIncrement == true) {
1617 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
1618 xattr.Value = "true";
1622 if (col.AutoIncrementSeed != 0) {
1623 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
1624 xattr.Value = col.AutoIncrementSeed.ToString();
1628 if (col.DefaultValue.ToString () != String.Empty)
1629 colElem.DefaultValue = col.DefaultValue.ToString ();
1631 if (col.MaxLength < 0)
1632 colElem.SchemaTypeName = MapType (col.DataType);
1634 if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string)
1635 && col.DataType != typeof (char)) {
1636 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
1637 xattr.Value = col.DataType.AssemblyQualifiedName;
1641 if (col.AllowDBNull) {
1642 colElem.MinOccurs = 0;
1645 //writer.WriteAttributeString (XmlConstants.MsdataPrefix,
1646 // XmlConstants.Ordinal,
1647 // XmlConstants.MsdataNamespace,
1648 // col.Ordinal.ToString ());
1650 // Write SimpleType if column have MaxLength
1651 if (col.MaxLength > -1) {
1652 colElem.SchemaType = GetTableSimpleType (doc, col);
1655 colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
1656 seq.Items.Add (colElem);
1658 if (seq.Items.Count > 0)
1659 complex.Particle = seq;
1661 foreach (DataRelation rel in table.ChildRelations) {
1663 if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
1664 XmlSchemaElement el = new XmlSchemaElement ();
1665 el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
1667 XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
1668 XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
1670 el.SchemaType = null;
1671 el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
1672 schemaToAdd.Items.Add (ct);
1679 //Then a list of attributes
1680 foreach (DataColumn col in atts) {
1681 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1682 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1683 att.Name = col.ColumnName;
1684 if (col.Namespace != String.Empty) {
1685 att.Form = XmlSchemaForm.Qualified;
1686 string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
1687 att.Name = prefix + ":" + col.ColumnName;
1688 // FIXME: Handle prefix mapping correctly.
1689 schemaToAdd.Namespaces.Add (prefix, col.Namespace);
1691 att.SchemaTypeName = MapType (col.DataType);
1692 schemaAttributes.Add (att);
1698 private string SafeNS (string ns)
1700 return ns != null ? ns : String.Empty;
1703 private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
1705 foreach (XmlSchemaExternal ext in schema.Includes) {
1706 XmlSchemaImport imp = ext as XmlSchemaImport;
1707 if (imp != null && imp.Namespace == ns)
1708 return; // nothing to do
1710 XmlSchemaImport i = new XmlSchemaImport ();
1712 i.SchemaLocation = "_" + prefix + ".xsd";
1713 schema.Includes.Add (i);
1716 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1719 XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1722 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1723 restriction.BaseTypeName = MapType (col.DataType);
1726 XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1727 max.Value = XmlConvert.ToString (col.MaxLength);
1728 restriction.Facets.Add (max);
1730 simple.Content = restriction;
1734 private void DoWriteXmlSchema (XmlWriter writer)
1736 BuildSchema ().Write (writer);
1740 /// Helper function to split columns into attributes elements and simple
1743 private void SplitColumns (DataTable table,
1745 out ArrayList elements,
1746 out DataColumn simple)
1748 //The columns can be attributes, hidden, elements, or simple content
1749 //There can be 0-1 simple content cols or 0-* elements
1750 atts = new System.Collections.ArrayList ();
1751 elements = new System.Collections.ArrayList ();
1754 //Sort out the columns
1755 foreach (DataColumn col in table.Columns) {
1756 switch (col.ColumnMapping) {
1757 case MappingType.Attribute:
1760 case MappingType.Element:
1763 case MappingType.SimpleContent:
1764 if (simple != null) {
1765 throw new System.InvalidOperationException ("There may only be one simple content element");
1770 //ignore Hidden elements
1776 private void WriteDiffGramElement(XmlWriter writer)
1778 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
1779 WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1782 private void SetRowsID()
1784 foreach (DataTable Table in Tables)
1785 SetTableRowsID (Table);
1788 private void SetTableRowsID (DataTable Table)
1791 foreach (DataRow Row in Table.Rows) {
1792 Row.XmlRowID = dataRowID;
1798 private XmlQualifiedName MapType (Type type)
1800 switch (Type.GetTypeCode (type)) {
1801 case TypeCode.String: return XmlConstants.QnString;
1802 case TypeCode.Int16: return XmlConstants.QnShort;
1803 case TypeCode.Int32: return XmlConstants.QnInt;
1804 case TypeCode.Int64: return XmlConstants.QnLong;
1805 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1806 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1807 //case TypeCode.Char: return XmlConstants.QnChar;
1808 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1809 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1810 case TypeCode.Double: return XmlConstants.QnDouble;
1811 case TypeCode.SByte: return XmlConstants.QnSbyte;
1812 case TypeCode.Single: return XmlConstants.QnFloat;
1813 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1814 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1815 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1818 if (typeof (TimeSpan) == type)
1819 return XmlConstants.QnDuration;
1820 else if (typeof (System.Uri) == type)
1821 return XmlConstants.QnUri;
1822 else if (typeof (byte[]) == type)
1823 return XmlConstants.QnBase64Binary;
1824 else if (typeof (XmlQualifiedName) == type)
1825 return XmlConstants.QnXmlQualifiedName;
1827 return XmlConstants.QnString;
1830 #endregion //Private Xml Serialisation