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")]
34 public class DataSet : MarshalByValueComponent, IListSource,
35 ISupportInitialize, ISerializable, IXmlSerializable
37 private string dataSetName;
38 private string _namespace = "";
39 private string prefix;
40 private bool caseSensitive;
41 private bool enforceConstraints = true;
42 private DataTableCollection tableCollection;
43 private DataRelationCollection relationCollection;
44 private PropertyCollection properties;
45 private DataViewManager defaultView;
46 private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
47 internal XmlDataDocument _xmlDataDocument = null;
51 public DataSet () : this ("NewDataSet")
55 public DataSet (string name)
58 tableCollection = new DataTableCollection (this);
59 relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
60 properties = new PropertyCollection ();
61 this.prefix = String.Empty;
63 this.Locale = CultureInfo.CurrentCulture;
66 protected DataSet (SerializationInfo info, StreamingContext context) : this ()
68 GetSerializationData (info, context);
71 #endregion // Constructors
73 #region Public Properties
75 [DataCategory ("Data")]
76 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
77 [DefaultValue (false)]
78 public bool CaseSensitive {
83 caseSensitive = value;
85 foreach (DataTable table in Tables) {
86 foreach (Constraint c in table.Constraints)
87 c.AssertConstraint ();
93 [DataCategory ("Data")]
94 [DataSysDescription ("The name of this DataSet.")]
96 public string DataSetName {
97 get { return dataSetName; }
98 set { dataSetName = value; }
101 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
103 public DataViewManager DefaultViewManager {
105 if (defaultView == null)
106 defaultView = new DataViewManager (this);
111 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
112 [DefaultValue (true)]
113 public bool EnforceConstraints {
114 get { return enforceConstraints; }
116 if (value != enforceConstraints) {
117 enforceConstraints = value;
119 foreach (DataTable table in Tables) {
120 // first assert all unique constraints
121 foreach (UniqueConstraint uc in table.Constraints.UniqueConstraints)
122 uc.AssertConstraint ();
123 // then assert all foreign keys
124 foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
125 fk.AssertConstraint ();
133 [DataCategory ("Data")]
134 [DataSysDescription ("The collection that holds custom user information.")]
135 public PropertyCollection ExtendedProperties {
136 get { return properties; }
140 [DataSysDescription ("Indicates that the DataSet has errors.")]
141 public bool HasErrors {
144 for (int i = 0; i < Tables.Count; i++) {
145 if (Tables[i].HasErrors)
152 [DataCategory ("Data")]
153 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
154 public CultureInfo Locale {
159 if (locale == null || !locale.Equals (value)) {
160 // TODO: check if the new locale is valid
161 // TODO: update locale of all tables
167 public void Merge (DataRow[] rows)
169 Merge (rows, false, MissingSchemaAction.Add);
172 public void Merge (DataSet dataSet)
174 Merge (dataSet, false, MissingSchemaAction.Add);
177 public void Merge (DataTable table)
179 Merge (table, false, MissingSchemaAction.Add);
182 public void Merge (DataSet dataSet, bool preserveChanges)
184 Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
188 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
191 throw new ArgumentNullException ("rows");
192 if (!IsLegalSchemaAction (missingSchemaAction))
193 throw new ArgumentOutOfRangeException ("missingSchemaAction");
195 MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
199 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
202 throw new ArgumentNullException ("dataSet");
203 if (!IsLegalSchemaAction (missingSchemaAction))
204 throw new ArgumentOutOfRangeException ("missingSchemaAction");
206 MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
210 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
213 throw new ArgumentNullException ("table");
214 if (!IsLegalSchemaAction (missingSchemaAction))
215 throw new ArgumentOutOfRangeException ("missingSchemaAction");
217 MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
220 private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
222 if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
223 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
228 [DataCategory ("Data")]
229 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
231 public string Namespace {
232 get { return _namespace; }
234 //TODO - trigger an event if this happens?
236 value = String.Empty;
237 if (value != this._namespace)
238 RaisePropertyChanging ("Namespace");
243 [DataCategory ("Data")]
244 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
246 public string Prefix {
247 get { return prefix; }
250 value = String.Empty;
251 // Prefix cannot contain any special characters other than '_' and ':'
252 for (int i = 0; i < value.Length; i++) {
253 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
254 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
259 value = string.Empty;
261 if (value != this.prefix)
262 RaisePropertyChanging ("Prefix");
267 [DataCategory ("Data")]
268 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
269 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
270 public DataRelationCollection Relations {
272 return relationCollection;
277 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
278 public override ISite Site {
281 throw new NotImplementedException ();
286 throw new NotImplementedException ();
290 [DataCategory ("Data")]
291 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
292 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
293 public DataTableCollection Tables {
294 get { return tableCollection; }
297 #endregion // Public Properties
299 #region Public Methods
302 public void AcceptChanges ()
304 foreach (DataTable tempTable in tableCollection)
305 tempTable.AcceptChanges ();
310 if (_xmlDataDocument != null)
311 throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
312 for (int t = 0; t < tableCollection.Count; t++) {
313 tableCollection[t].Clear ();
317 public virtual DataSet Clone ()
319 DataSet Copy = new DataSet ();
320 CopyProperties (Copy);
322 foreach (DataTable Table in Tables) {
323 Copy.Tables.Add (Table.Clone ());
326 //Copy Relationships between tables after existance of tables
327 //and setting properties correctly
328 CopyRelations (Copy);
333 // Copies both the structure and data for this DataSet.
334 public DataSet Copy ()
336 DataSet Copy = new DataSet ();
337 CopyProperties (Copy);
339 // Copy DatSet's tables
340 foreach (DataTable Table in Tables)
341 Copy.Tables.Add (Table.Copy ());
343 //Copy Relationships between tables after existance of tables
344 //and setting properties correctly
345 CopyRelations (Copy);
350 private void CopyProperties (DataSet Copy)
352 Copy.CaseSensitive = CaseSensitive;
353 //Copy.Container = Container
354 Copy.DataSetName = DataSetName;
355 //Copy.DefaultViewManager
357 Copy.EnforceConstraints = EnforceConstraints;
358 if(ExtendedProperties.Count > 0) {
359 // Cannot copy extended properties directly as the property does not have a set accessor
360 Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
361 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
362 for (int i=0; i < ExtendedProperties.Count; i++)
363 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
365 Copy.Locale = Locale;
366 Copy.Namespace = Namespace;
367 Copy.Prefix = Prefix;
368 //Copy.Site = Site; // FIXME : Not sure of this.
373 private void CopyRelations (DataSet Copy)
376 //Creation of the relation contains some of the properties, and the constructor
377 //demands these values. instead changing the DataRelation constructor and behaviour the
378 //parameters are pre-configured and sent to the most general constructor
380 foreach (DataRelation MyRelation in this.Relations) {
381 string pTable = MyRelation.ParentTable.TableName;
382 string cTable = MyRelation.ChildTable.TableName;
383 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
384 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
387 foreach (DataColumn DC in MyRelation.ParentColumns) {
388 P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
394 foreach (DataColumn DC in MyRelation.ChildColumns) {
395 C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
399 DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
400 //cRel.ChildColumns = MyRelation.ChildColumns;
401 //cRel.ChildTable = MyRelation.ChildTable;
402 //cRel.ExtendedProperties = cRel.ExtendedProperties;
403 //cRel.Nested = MyRelation.Nested;
404 //cRel.ParentColumns = MyRelation.ParentColumns;
405 //cRel.ParentTable = MyRelation.ParentTable;
407 Copy.Relations.Add (cRel);
414 public DataSet GetChanges ()
416 return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
420 public DataSet GetChanges (DataRowState rowStates)
422 if (!HasChanges (rowStates))
425 DataSet copySet = Clone ();
426 Hashtable addedRows = new Hashtable ();
428 IEnumerator tableEnumerator = Tables.GetEnumerator ();
431 while (tableEnumerator.MoveNext ()) {
432 origTable = (DataTable)tableEnumerator.Current;
433 copyTable = copySet.Tables[origTable.TableName];
435 // Look for relations that have this table as child
436 IEnumerator relations = origTable.ParentRelations.GetEnumerator ();
438 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
439 while (rowEnumerator.MoveNext ()) {
440 DataRow row = (DataRow)rowEnumerator.Current;
442 if (row.IsRowChanged (rowStates))
443 AddChangedRow (addedRows, copySet, copyTable, relations, row);
449 void AddChangedRow (Hashtable addedRows, DataSet copySet, DataTable copyTable, IEnumerator relations, DataRow row)
451 if (addedRows.ContainsKey (row)) return;
454 while (relations.MoveNext ()) {
455 DataRow parentRow = row.GetParentRow ((DataRelation) relations.Current);
456 if (parentRow == null || addedRows.ContainsKey (parentRow)) continue;
457 DataTable parentCopyTable = copySet.Tables [parentRow.Table.TableName];
458 AddChangedRow (addedRows, copySet, parentCopyTable, parentRow.Table.ParentRelations.GetEnumerator (), parentRow);
461 DataRow newRow = copyTable.NewRow ();
462 copyTable.Rows.Add (newRow);
463 row.CopyValuesToRow (newRow);
464 newRow.XmlRowID = row.XmlRowID;
465 addedRows.Add (row,row);
470 public DataTableReader GetDataReader (DataTable[] dataTables)
472 throw new NotImplementedException ();
476 public DataTableReader GetDataReader ()
478 throw new NotImplementedException ();
482 public string GetXml ()
484 StringWriter Writer = new StringWriter ();
485 WriteXml (Writer, XmlWriteMode.IgnoreSchema);
486 return Writer.ToString ();
489 public string GetXmlSchema ()
491 StringWriter Writer = new StringWriter ();
492 WriteXmlSchema (Writer);
493 return Writer.ToString ();
497 public bool HasChanges ()
499 return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
503 public bool HasChanges (DataRowState rowState)
505 if (((int)rowState & 0xffffffe0) != 0)
506 throw new ArgumentOutOfRangeException ("rowState");
508 DataTableCollection tableCollection = Tables;
510 DataRowCollection rowCollection;
513 for (int i = 0; i < tableCollection.Count; i++) {
514 table = tableCollection[i];
515 rowCollection = table.Rows;
516 for (int j = 0; j < rowCollection.Count; j++) {
517 row = rowCollection[j];
518 if ((row.RowState & rowState) != 0)
526 [MonoTODO ("Consider ignored namespace array")]
527 public void InferXmlSchema (XmlReader reader, string[] nsArray)
532 XmlDataLoader Loader = new XmlDataLoader (this);
533 Loader.LoadData (reader, XmlReadMode.InferSchema);
536 public void InferXmlSchema (Stream stream, string[] nsArray)
538 InferXmlSchema (new XmlTextReader (stream), nsArray);
541 public void InferXmlSchema (TextReader reader, string[] nsArray)
543 InferXmlSchema (new XmlTextReader (reader), nsArray);
546 public void InferXmlSchema (string fileName, string[] nsArray)
548 XmlTextReader reader = new XmlTextReader (fileName);
550 InferXmlSchema (reader, nsArray);
558 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
560 throw new NotImplementedException ();
564 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
566 throw new NotImplementedException ();
570 public virtual void RejectChanges ()
573 bool oldEnforceConstraints = this.EnforceConstraints;
574 this.EnforceConstraints = false;
576 for (i = 0; i < this.Tables.Count;i++)
577 this.Tables[i].RejectChanges ();
579 this.EnforceConstraints = oldEnforceConstraints;
582 public virtual void Reset ()
584 IEnumerator constraintEnumerator;
586 // first we remove all ForeignKeyConstraints (if we will not do that
587 // we will get an exception when clearing the tables).
588 for (int i = 0; i < Tables.Count; i++) {
589 ConstraintCollection cc = Tables[i].Constraints;
590 for (int j = 0; j < cc.Count; j++) {
591 if (cc[j] is ForeignKeyConstraint)
601 public void WriteXml (Stream stream)
603 XmlTextWriter writer = new XmlTextWriter (stream, null);
604 writer.Formatting = Formatting.Indented;
609 /// Writes the current data for the DataSet to the specified file.
611 /// <param name="filename">Fully qualified filename to write to</param>
612 public void WriteXml (string fileName)
614 XmlTextWriter writer = new XmlTextWriter (fileName, null);
615 writer.Formatting = Formatting.Indented;
616 writer.WriteStartDocument (true);
621 writer.WriteEndDocument ();
626 public void WriteXml (TextWriter writer)
628 XmlTextWriter xwriter = new XmlTextWriter (writer);
629 xwriter.Formatting = Formatting.Indented;
633 public void WriteXml (XmlWriter writer)
635 WriteXml (writer, XmlWriteMode.IgnoreSchema);
638 public void WriteXml (string filename, XmlWriteMode mode)
640 XmlTextWriter writer = new XmlTextWriter (filename, null);
641 writer.Formatting = Formatting.Indented;
642 writer.WriteStartDocument (true);
645 WriteXml (writer, mode);
648 writer.WriteEndDocument ();
653 public void WriteXml (Stream stream, XmlWriteMode mode)
655 XmlTextWriter writer = new XmlTextWriter (stream, null);
656 writer.Formatting = Formatting.Indented;
657 WriteXml (writer, mode);
660 public void WriteXml (TextWriter writer, XmlWriteMode mode)
662 XmlTextWriter xwriter = new XmlTextWriter (writer);
663 xwriter.Formatting = Formatting.Indented;
664 WriteXml (xwriter, mode);
667 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
669 if (mode == XmlWriteMode.DiffGram) {
671 WriteDiffGramElement(writer);
674 // It should not write when there is no content to be written
675 bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
676 for (int n=0; n<tableCollection.Count && !shouldOutputContent; n++)
677 shouldOutputContent = tableCollection [n].Rows.Count > 0;
679 if (shouldOutputContent) {
680 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
682 if (mode == XmlWriteMode.WriteSchema)
683 DoWriteXmlSchema (writer);
685 WriteTables (writer, mode, Tables, DataRowVersion.Default);
686 writer.WriteEndElement ();
689 if (mode == XmlWriteMode.DiffGram) {
690 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
692 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
693 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
694 WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
695 writer.WriteEndElement ();
699 if (mode == XmlWriteMode.DiffGram)
700 writer.WriteEndElement (); // diffgr:diffgram
703 public void WriteXmlSchema (Stream stream)
705 XmlTextWriter writer = new XmlTextWriter (stream, null );
706 writer.Formatting = Formatting.Indented;
707 WriteXmlSchema (writer);
710 public void WriteXmlSchema (string fileName)
712 XmlTextWriter writer = new XmlTextWriter (fileName, null);
714 writer.Formatting = Formatting.Indented;
715 writer.WriteStartDocument (true);
716 WriteXmlSchema (writer);
718 writer.WriteEndDocument ();
723 public void WriteXmlSchema (TextWriter writer)
725 XmlTextWriter xwriter = new XmlTextWriter (writer);
727 xwriter.Formatting = Formatting.Indented;
728 // xwriter.WriteStartDocument ();
729 WriteXmlSchema (xwriter);
731 // xwriter.WriteEndDocument ();
736 public void WriteXmlSchema (XmlWriter writer)
738 //Create a skeleton doc and then write the schema
739 //proper which is common to the WriteXml method in schema mode
740 DoWriteXmlSchema (writer);
743 public void ReadXmlSchema (Stream stream)
745 XmlReader reader = new XmlTextReader (stream, null);
746 ReadXmlSchema (reader);
749 public void ReadXmlSchema (string str)
751 XmlReader reader = new XmlTextReader (str);
753 ReadXmlSchema (reader);
760 public void ReadXmlSchema (TextReader treader)
762 XmlReader reader = new XmlTextReader (treader);
763 ReadXmlSchema (reader);
766 public void ReadXmlSchema (XmlReader reader)
769 new XmlSchemaDataImporter (this, reader).Process ();
771 XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
772 SchemaMapper.Read (reader);
776 public XmlReadMode ReadXml (Stream stream)
778 return ReadXml (new XmlTextReader (stream));
781 public XmlReadMode ReadXml (string str)
783 XmlTextReader reader = new XmlTextReader (str);
785 return ReadXml (reader);
792 public XmlReadMode ReadXml (TextReader reader)
794 return ReadXml (new XmlTextReader (reader));
797 public XmlReadMode ReadXml (XmlReader r)
799 return ReadXml (r, XmlReadMode.Auto);
802 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
804 return ReadXml (new XmlTextReader (stream), mode);
807 public XmlReadMode ReadXml (string str, XmlReadMode mode)
809 XmlTextReader reader = new XmlTextReader (str);
811 return ReadXml (reader, mode);
818 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
820 return ReadXml (new XmlTextReader (reader), mode);
824 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
826 switch (reader.ReadState) {
827 case ReadState.EndOfFile:
828 case ReadState.Error:
829 case ReadState.Closed:
832 // Skip XML declaration and prolog
833 reader.MoveToContent();
837 XmlReadMode Result = mode;
839 // If diffgram, then read the first element as diffgram
840 if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
842 case XmlReadMode.Auto:
843 case XmlReadMode.DiffGram:
844 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
845 DiffLoader.Load (reader);
846 // (and leave rest of the reader as is)
847 return XmlReadMode.DiffGram;
848 case XmlReadMode.Fragment:
850 // (and continue to read)
854 // (and leave rest of the reader as is)
858 // If schema, then read the first element as schema
859 if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
861 case XmlReadMode.IgnoreSchema:
862 case XmlReadMode.InferSchema:
864 // (and break up read)
866 case XmlReadMode.Fragment:
867 ReadXmlSchema (reader);
868 // (and continue to read)
870 case XmlReadMode.Auto:
871 if (Tables.Count == 0) {
872 ReadXmlSchema (reader);
873 return XmlReadMode.ReadSchema;
875 // otherwise just ignore and return IgnoreSchema
877 return XmlReadMode.IgnoreSchema;
880 ReadXmlSchema (reader);
881 // (and leave rest of the reader as is)
882 return mode; // When DiffGram, return DiffGram
885 // Otherwise, read as dataset... but only when required.
887 case XmlReadMode.Auto:
888 case XmlReadMode.InferSchema:
889 case XmlReadMode.IgnoreSchema:
890 case XmlReadMode.Fragment:
896 XmlDataLoader Loader = new XmlDataLoader (this);
897 return Loader.LoadData (reader, mode);
899 #endregion // Public Methods
901 #region Public Events
903 [DataCategory ("Action")]
904 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
905 public event MergeFailedEventHandler MergeFailed;
907 #endregion // Public Events
915 #endregion Destructors
917 #region IListSource methods
918 IList IListSource.GetList ()
920 return DefaultViewManager;
923 bool IListSource.ContainsListCollection {
928 #endregion IListSource methods
930 #region ISupportInitialize methods
931 public void BeginInit ()
935 public void EndInit ()
940 #region ISerializable
941 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
943 StringWriter sw = new StringWriter ();
944 XmlTextWriter writer = new XmlTextWriter (sw);
945 DoWriteXmlSchema (writer);
947 si.AddValue ("XmlSchema", sw.ToString ());
949 sw = new StringWriter ();
950 writer = new XmlTextWriter (sw);
951 WriteXml (writer, XmlWriteMode.DiffGram);
953 si.AddValue ("XmlDiffGram", sw.ToString ());
957 #region Protected Methods
958 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
960 string s = info.GetValue ("XmlSchema", typeof (String)) as String;
961 XmlTextReader reader = new XmlTextReader (new StringReader (s));
962 ReadXmlSchema (reader);
965 s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
966 reader = new XmlTextReader (new StringReader (s));
967 ReadXml (reader, XmlReadMode.DiffGram);
972 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
977 protected virtual void ReadXmlSerializable (XmlReader reader)
979 reader.MoveToContent ();
980 reader.ReadStartElement ();
981 reader.MoveToContent ();
982 ReadXmlSchema (reader);
983 reader.MoveToContent ();
984 ReadXml (reader, XmlReadMode.DiffGram);
985 reader.MoveToContent ();
986 reader.ReadEndElement ();
989 void IXmlSerializable.ReadXml (XmlReader reader)
991 ReadXmlSerializable(reader);
994 void IXmlSerializable.WriteXml (XmlWriter writer)
996 DoWriteXmlSchema (writer);
997 WriteXml (writer, XmlWriteMode.DiffGram);
1000 protected virtual bool ShouldSerializeRelations ()
1005 protected virtual bool ShouldSerializeTables ()
1011 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
1016 protected virtual void OnRemoveRelation (DataRelation relation)
1021 protected virtual void OnRemoveTable (DataTable table)
1025 protected internal virtual void OnMergeFailed (MergeFailedEventArgs e)
1027 if (MergeFailed != null)
1028 MergeFailed (this, e);
1032 protected internal void RaisePropertyChanging (string name)
1037 #region Private Xml Serialisation
1039 private string WriteObjectXml (object o)
1041 switch (Type.GetTypeCode (o.GetType ())) {
1042 case TypeCode.Boolean:
1043 return XmlConvert.ToString ((Boolean) o);
1045 return XmlConvert.ToString ((Byte) o);
1047 return XmlConvert.ToString ((Char) o);
1048 case TypeCode.DateTime:
1049 return XmlConvert.ToString ((DateTime) o);
1050 case TypeCode.Decimal:
1051 return XmlConvert.ToString ((Decimal) o);
1052 case TypeCode.Double:
1053 return XmlConvert.ToString ((Double) o);
1054 case TypeCode.Int16:
1055 return XmlConvert.ToString ((Int16) o);
1056 case TypeCode.Int32:
1057 return XmlConvert.ToString ((Int32) o);
1058 case TypeCode.Int64:
1059 return XmlConvert.ToString ((Int64) o);
1060 case TypeCode.SByte:
1061 return XmlConvert.ToString ((SByte) o);
1062 case TypeCode.Single:
1063 return XmlConvert.ToString ((Single) o);
1064 case TypeCode.UInt16:
1065 return XmlConvert.ToString ((UInt16) o);
1066 case TypeCode.UInt32:
1067 return XmlConvert.ToString ((UInt32) o);
1068 case TypeCode.UInt64:
1069 return XmlConvert.ToString ((UInt64) o);
1071 if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1072 if (o is Guid) return XmlConvert.ToString ((Guid) o);
1073 if (o is byte[]) return Convert.ToBase64String ((byte[])o);
1074 return o.ToString ();
1077 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1079 //Write out each table in order, providing it is not
1080 //part of another table structure via a nested parent relationship
1081 foreach (DataTable table in tableCollection) {
1082 bool isTopLevel = true;
1083 foreach (DataRelation rel in table.ParentRelations) {
1091 WriteTable ( writer, table, mode, version);
1096 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1098 DataRow[] rows = new DataRow [table.Rows.Count];
1099 table.Rows.CopyTo (rows, 0);
1100 WriteTable (writer, rows, mode, version);
1103 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version)
1105 //The columns can be attributes, hidden, elements, or simple content
1106 //There can be 0-1 simple content cols or 0-* elements
1107 System.Collections.ArrayList atts;
1108 System.Collections.ArrayList elements;
1109 DataColumn simple = null;
1111 if (rows.Length == 0) return;
1112 DataTable table = rows[0].Table;
1113 SplitColumns (table, out atts, out elements, out simple);
1114 //sort out the namespacing
1115 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1117 foreach (DataRow row in rows) {
1118 if (!row.HasVersion(version) ||
1119 (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
1120 && version == DataRowVersion.Original))
1123 // First check are all the rows null. If they are we just write empty element
1124 bool AllNulls = true;
1125 foreach (DataColumn dc in table.Columns) {
1127 if (row [dc.ColumnName, version] != DBNull.Value) {
1133 // If all of the columns were null, we have to write empty element
1135 writer.WriteElementString (table.TableName, "");
1139 WriteTableElement (writer, mode, table, row, version);
1141 foreach (DataColumn col in atts) {
1142 WriteColumnAsAttribute (writer, mode, col, row, version);
1145 if (simple != null) {
1146 writer.WriteString (WriteObjectXml (row[simple, version]));
1149 foreach (DataColumn col in elements) {
1150 WriteColumnAsElement (writer, mode, col, row, version);
1154 foreach (DataRelation relation in table.ChildRelations) {
1155 if (relation.Nested) {
1156 WriteTable (writer, row.GetChildRows (relation), mode, version);
1160 writer.WriteEndElement ();
1165 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1167 string colnspc = null;
1168 object rowObject = row [col, version];
1170 if (rowObject == null || rowObject == DBNull.Value)
1173 if (col.Namespace != String.Empty)
1174 colnspc = col.Namespace;
1176 //TODO check if I can get away with write element string
1177 WriteStartElement (writer, mode, colnspc, col.Prefix, col.ColumnName);
1178 writer.WriteString (WriteObjectXml (rowObject));
1179 writer.WriteEndElement ();
1182 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1184 WriteAttributeString (writer, mode, col.Namespace, col.Prefix, col.ColumnName, row[col, version].ToString ());
1187 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1189 //sort out the namespacing
1190 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1192 WriteStartElement (writer, mode, nspc, table.Prefix, table.TableName);
1194 if (mode == XmlWriteMode.DiffGram) {
1195 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
1196 WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", row.XmlRowID.ToString());
1197 string modeName = null;
1198 if (row.RowState == DataRowState.Modified)
1199 modeName = "modified";
1200 else if (row.RowState == DataRowState.Added)
1201 modeName = "inserted";
1203 if (version != DataRowVersion.Original && modeName != null)
1204 WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
1208 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1210 writer.WriteStartElement (prefix, name, nspc);
1213 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1216 case XmlWriteMode.WriteSchema:
1217 writer.WriteAttributeString (prefix, name, nspc);
1219 case XmlWriteMode.DiffGram:
1220 writer.WriteAttributeString (prefix, name, nspc,stringValue);
1223 writer.WriteAttributeString (name, stringValue);
1228 internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
1230 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
1232 if (mode == XmlWriteMode.DiffGram) {
1233 SetTableRowsID (table);
1234 WriteDiffGramElement (writer);
1237 WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
1239 WriteTable (writer, table, mode, DataRowVersion.Default);
1241 if (mode == XmlWriteMode.DiffGram) {
1242 writer.WriteEndElement (); //DataSet name
1243 if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
1245 DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
1246 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
1247 WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
1248 writer.WriteEndElement ();
1251 writer.WriteEndElement (); // DataSet name or diffgr:diffgram
1254 private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
1256 if (ns == String.Empty)
1258 if (ns != nsmgr.DefaultNamespace) {
1259 if (nsmgr.LookupNamespace (prefix) != ns) {
1260 for (int i = 1; i < int.MaxValue; i++) {
1261 string p = nsmgr.NameTable.Add ("app" + i);
1262 if (!nsmgr.HasNamespace (p)) {
1263 nsmgr.AddNamespace (p, ns);
1264 HandleExternalNamespace (p, ns, schema);
1272 XmlSchema IXmlSerializable.GetSchema ()
1274 return BuildSchema ();
1277 XmlSchema BuildSchema ()
1279 return BuildSchema (Tables, Relations);
1282 internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
1284 string constraintPrefix = "";
1285 XmlSchema schema = new XmlSchema ();
1286 XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
1288 if (Namespace != "") {
1289 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1290 schema.ElementFormDefault = XmlSchemaForm.Qualified;
1291 schema.TargetNamespace = Namespace;
1292 constraintPrefix = XmlConstants.TnsPrefix + ":";
1295 // set the schema id
1296 string xmlNSURI = "http://www.w3.org/2000/xmlns/";
1297 schema.Id = DataSetName;
1298 XmlDocument doc = new XmlDocument ();
1299 XmlAttribute attr = null;
1300 ArrayList atts = new ArrayList ();
1302 nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
1303 nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1304 if (Namespace != "") {
1305 nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
1306 nsmgr.AddNamespace (String.Empty, Namespace);
1310 schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1312 XmlSchemaElement elem = new XmlSchemaElement ();
1313 elem.Name = XmlConvert.EncodeName (DataSetName);
1315 // Add namespaces used in DataSet components (tables, columns, ...)
1316 foreach (DataTable dt in Tables) {
1317 foreach (DataColumn col in dt.Columns)
1318 CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
1319 CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
1322 // Attributes for DataSet element
1324 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1325 attr.Value = "true";
1328 attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1329 attr.Value = locale.Name;
1332 elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
1334 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1335 elem.SchemaType = complex;
1337 XmlSchemaChoice choice = new XmlSchemaChoice ();
1338 complex.Particle = choice;
1339 choice.MaxOccursString = XmlConstants.Unbounded;
1341 //Write out schema for each table in order
1342 foreach (DataTable table in tables) {
1343 bool isTopLevel = true;
1344 foreach (DataRelation rel in table.ParentRelations) {
1352 if (table.Namespace != SafeNS (schema.TargetNamespace)) {
1353 XmlSchemaElement extElem = new XmlSchemaElement ();
1354 extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
1355 choice.Items.Add (extElem);
1358 choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
1362 schema.Items.Add (elem);
1364 AddConstraintsToSchema (elem, constraintPrefix, tables, relations);
1365 foreach (string prefix in nsmgr) {
1366 string ns = nsmgr.LookupNamespace (prefix);
1367 if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
1368 schema.Namespaces.Add (prefix, ns);
1374 // Add all constraints in all tables to the schema.
1375 private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations)
1377 // first add all unique constraints.
1378 Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables);
1379 // Add all foriegn key constraints.
1380 AddForeignKeys (uniqueNames, elem, constraintPrefix, relations);
1383 // Add unique constaraints to the schema.
1384 // return hashtable with the names of all XmlSchemaUnique elements we created.
1385 private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables)
1387 XmlDocument doc = new XmlDocument();
1388 Hashtable uniqueNames = new Hashtable();
1389 foreach (DataTable table in tables) {
1391 foreach (Constraint constaint in table.Constraints) {
1393 if (constaint is UniqueConstraint) {
1394 ArrayList attrs = new ArrayList ();
1395 XmlAttribute attrib;
1396 UniqueConstraint uqConst = (UniqueConstraint)constaint;
1397 XmlSchemaUnique uniq = new XmlSchemaUnique ();
1399 // if column of the constraint is hidden do not write the constraint.
1400 bool isHidden = false;
1401 foreach (DataColumn column in uqConst.Columns) {
1402 if (column.ColumnMapping == MappingType.Hidden) {
1411 // if constaraint name do not exist in the hashtable we can use it.
1412 if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
1413 uniq.Name = uqConst.ConstraintName;
1415 // generate new constraint name for the XmlSchemaUnique element.
1417 uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
1418 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1419 attrib.Value = uqConst.ConstraintName;
1422 if (uqConst.IsPrimaryKey) {
1423 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
1424 attrib.Value = "true";
1428 uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1430 uniq.Selector = new XmlSchemaXPath();
1431 uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
1432 XmlSchemaXPath field;
1433 foreach (DataColumn column in uqConst.Columns) {
1434 field = new XmlSchemaXPath();
1435 field.XPath = constraintPrefix+column.ColumnName;
1436 uniq.Fields.Add(field);
1439 elem.Constraints.Add (uniq);
1440 uniqueNames.Add (uniq.Name, null);
1447 // Add the foriegn keys to the schema.
1448 private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations)
1450 if (relations == null) return;
1452 XmlDocument doc = new XmlDocument();
1453 foreach (DataRelation rel in relations) {
1455 if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
1458 ArrayList attrs = new ArrayList ();
1459 XmlAttribute attrib;
1460 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1461 keyRef.Name = rel.RelationName;
1462 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1463 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1465 string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
1466 // first try to find the concatenated name. If we didn't find it - use constraint name.
1467 if (uniqueNames.ContainsKey (concatName)) {
1468 keyRef.Refer = new XmlQualifiedName(concatName);
1471 keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
1475 attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1476 attrib.Value = "true";
1480 keyRef.Selector = new XmlSchemaXPath();
1481 keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
1482 XmlSchemaXPath field;
1483 foreach (DataColumn column in rel.ChildColumns) {
1484 field = new XmlSchemaXPath();
1485 field.XPath = constraintPrefix+column.ColumnName;
1486 keyRef.Fields.Add(field);
1488 keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
1489 elem.Constraints.Add (keyRef);
1493 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
1499 SplitColumns (table, out atts, out elements, out simple);
1501 XmlSchemaElement elem = new XmlSchemaElement ();
1502 elem.Name = table.TableName;
1504 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1505 elem.SchemaType = complex;
1507 //TODO - what about the simple content?
1508 if (simple != null) {
1509 // add simpleContent
1510 XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
1511 complex.ContentModel = simpleContent;
1513 // add column name attribute
1514 XmlAttribute[] xlmAttrs = new XmlAttribute [2];
1515 xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
1516 xlmAttrs[0].Value = simple.ColumnName;
1518 // add ordinal attribute
1519 xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
1520 xlmAttrs[1].Value = simple.Ordinal.ToString();
1521 simpleContent.UnhandledAttributes = xlmAttrs;
1525 XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
1526 simpleContent.Content = extension;
1527 extension.BaseTypeName = MapType (simple.DataType);
1531 //A sequence of element types or a simple content node
1533 XmlSchemaSequence seq = new XmlSchemaSequence ();
1535 foreach (DataColumn col in elements) {
1537 // Add element for the column.
1538 XmlSchemaElement colElem = new XmlSchemaElement ();
1539 ArrayList xattrs = new ArrayList();
1541 colElem.Name = col.ColumnName;
1543 if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
1544 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1545 xattr.Value = col.Caption;
1549 if (col.AutoIncrement == true) {
1550 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
1551 xattr.Value = "true";
1555 if (col.AutoIncrementSeed != 0) {
1556 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
1557 xattr.Value = col.AutoIncrementSeed.ToString();
1561 if (col.DefaultValue.ToString () != String.Empty)
1562 colElem.DefaultValue = col.DefaultValue.ToString ();
1564 if (col.MaxLength < 0)
1565 colElem.SchemaTypeName = MapType (col.DataType);
1567 if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string)
1568 && col.DataType != typeof (char)) {
1569 xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
1570 xattr.Value = col.DataType.AssemblyQualifiedName;
1574 if (col.AllowDBNull) {
1575 colElem.MinOccurs = 0;
1578 //writer.WriteAttributeString (XmlConstants.MsdataPrefix,
1579 // XmlConstants.Ordinal,
1580 // XmlConstants.MsdataNamespace,
1581 // col.Ordinal.ToString ());
1583 // Write SimpleType if column have MaxLength
1584 if (col.MaxLength > -1) {
1585 colElem.SchemaType = GetTableSimpleType (doc, col);
1588 colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
1589 seq.Items.Add (colElem);
1591 if (seq.Items.Count > 0)
1592 complex.Particle = seq;
1594 foreach (DataRelation rel in table.ChildRelations) {
1596 if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
1597 XmlSchemaElement el = new XmlSchemaElement ();
1598 el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
1600 XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
1601 XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
1603 el.SchemaType = null;
1604 el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
1605 schemaToAdd.Items.Add (ct);
1612 //Then a list of attributes
1613 foreach (DataColumn col in atts) {
1614 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1615 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1616 att.Name = col.ColumnName;
1617 if (col.Namespace != String.Empty) {
1618 att.Form = XmlSchemaForm.Qualified;
1619 string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
1620 att.Name = prefix + ":" + col.ColumnName;
1621 // FIXME: Handle prefix mapping correctly.
1622 schemaToAdd.Namespaces.Add (prefix, col.Namespace);
1624 att.SchemaTypeName = MapType (col.DataType);
1625 complex.Attributes.Add (att);
1631 private string SafeNS (string ns)
1633 return ns != null ? ns : String.Empty;
1636 private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
1638 foreach (XmlSchemaExternal ext in schema.Includes) {
1639 XmlSchemaImport imp = ext as XmlSchemaImport;
1640 if (imp != null && imp.Namespace == ns)
1641 return; // nothing to do
1643 XmlSchemaImport i = new XmlSchemaImport ();
1645 i.SchemaLocation = "_" + prefix + ".xsd";
1646 schema.Includes.Add (i);
1649 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1652 XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1655 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1656 restriction.BaseTypeName = MapType (col.DataType);
1659 XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1660 max.Value = XmlConvert.ToString (col.MaxLength);
1661 restriction.Facets.Add (max);
1663 simple.Content = restriction;
1667 private void DoWriteXmlSchema (XmlWriter writer)
1669 BuildSchema ().Write (writer);
1673 /// Helper function to split columns into attributes elements and simple
1676 private void SplitColumns (DataTable table,
1678 out ArrayList elements,
1679 out DataColumn simple)
1681 //The columns can be attributes, hidden, elements, or simple content
1682 //There can be 0-1 simple content cols or 0-* elements
1683 atts = new System.Collections.ArrayList ();
1684 elements = new System.Collections.ArrayList ();
1687 //Sort out the columns
1688 foreach (DataColumn col in table.Columns) {
1689 switch (col.ColumnMapping) {
1690 case MappingType.Attribute:
1693 case MappingType.Element:
1696 case MappingType.SimpleContent:
1697 if (simple != null) {
1698 throw new System.InvalidOperationException ("There may only be one simple content element");
1703 //ignore Hidden elements
1709 private void WriteDiffGramElement(XmlWriter writer)
1711 WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
1712 WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1715 private void SetRowsID()
1717 foreach (DataTable Table in Tables)
1718 SetTableRowsID (Table);
1721 private void SetTableRowsID (DataTable Table)
1724 foreach (DataRow Row in Table.Rows) {
1725 Row.XmlRowID = dataRowID;
1731 private XmlQualifiedName MapType (Type type)
1733 switch (Type.GetTypeCode (type)) {
1734 case TypeCode.String: return XmlConstants.QnString;
1735 case TypeCode.Int16: return XmlConstants.QnShort;
1736 case TypeCode.Int32: return XmlConstants.QnInt;
1737 case TypeCode.Int64: return XmlConstants.QnLong;
1738 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1739 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1740 //case TypeCode.Char: return XmlConstants.QnChar;
1741 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1742 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1743 case TypeCode.Double: return XmlConstants.QnDouble;
1744 case TypeCode.SByte: return XmlConstants.QnSbyte;
1745 case TypeCode.Single: return XmlConstants.QnFloat;
1746 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1747 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1748 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1751 if (typeof (TimeSpan) == type)
1752 return XmlConstants.QnDuration;
1753 else if (typeof (System.Uri) == type)
1754 return XmlConstants.QnUri;
1755 else if (typeof (byte[]) == type)
1756 return XmlConstants.QnBase64Binary;
1757 else if (typeof (XmlQualifiedName) == type)
1758 return XmlConstants.QnXmlQualifiedName;
1760 return XmlConstants.QnString;
1763 #endregion //Private Xml Serialisation