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>
12 // (C) Ximian, Inc. 2002
13 // Copyright (C) Tim Coleman, 2002
17 using System.Collections;
18 using System.ComponentModel;
19 using System.Globalization;
20 using System.Threading;
22 using System.Runtime.Serialization;
24 using System.Xml.Schema;
25 using System.Xml.Serialization;
26 using System.Data.Common;
28 namespace System.Data {
30 /// an in-memory cache of data
34 [DefaultProperty ("DataSetName")]
36 public class DataSet : MarshalByValueComponent, IListSource,
37 ISupportInitialize, ISerializable, IXmlSerializable {
38 private string dataSetName;
39 private string _namespace = "";
40 private string prefix;
41 private bool caseSensitive;
42 private bool enforceConstraints = true;
43 private DataTableCollection tableCollection;
44 private DataRelationCollection relationCollection;
45 private PropertyCollection properties;
46 private DataViewManager defaultView;
47 private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
51 public DataSet() : this ("NewDataSet") {
54 public DataSet(string name) {
56 tableCollection = new DataTableCollection (this);
57 relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
58 properties = new PropertyCollection();
62 protected DataSet(SerializationInfo info, StreamingContext context) : this () {
63 throw new NotImplementedException ();
66 #endregion // Constructors
68 #region Public Properties
70 [DataCategory ("Data")]
71 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
72 [DefaultValue (false)]
73 public bool CaseSensitive {
74 get { return caseSensitive; }
76 foreach (DataTable T in Tables) {
77 if (T.VirginCaseSensitive)
78 T.CaseSensitive = value;
81 caseSensitive = value;
85 [DataCategory ("Data")]
86 [DataSysDescription ("The name of this DataSet.")]
88 public string DataSetName {
89 get { return dataSetName; }
90 set { dataSetName = value; }
93 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
95 public DataViewManager DefaultViewManager {
97 if (defaultView == null)
98 defaultView = new DataViewManager (this);
103 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
104 [DefaultValue (true)]
105 public bool EnforceConstraints {
106 get { return enforceConstraints; }
107 set { enforceConstraints = value; }
111 [DataCategory ("Data")]
112 [DataSysDescription ("The collection that holds custom user information.")]
113 public PropertyCollection ExtendedProperties {
114 get { return properties; }
118 [DataSysDescription ("Indicates that the DataSet has errors.")]
119 public bool HasErrors {
122 for (int i = 0; i < Tables.Count; i++)
124 if (Tables[i].HasErrors)
131 [DataCategory ("Data")]
132 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
133 public CultureInfo Locale {
138 if (locale == null || !locale.Equals(value)) {
139 // TODO: check if the new locale is valid
140 // TODO: update locale of all tables
146 public void Merge (DataRow[] rows)
148 Merge (rows, false, MissingSchemaAction.Add);
151 public void Merge (DataSet dataSet)
153 Merge (dataSet, false, MissingSchemaAction.Add);
156 public void Merge (DataTable table)
158 Merge (table, false, MissingSchemaAction.Add);
161 public void Merge (DataSet dataSet, bool preserveChanges)
163 Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
167 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
170 throw new ArgumentNullException("rows");
171 if(!IsLegalSchemaAction(missingSchemaAction))
172 throw new ArgumentOutOfRangeException("missingSchemaAction");
174 MergeManager.Merge(this, rows, preserveChanges, missingSchemaAction);
178 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
181 throw new ArgumentNullException("dataSet");
182 if(!IsLegalSchemaAction(missingSchemaAction))
183 throw new ArgumentOutOfRangeException("missingSchemaAction");
185 MergeManager.Merge(this, dataSet, preserveChanges, missingSchemaAction);
189 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
192 throw new ArgumentNullException("table");
193 if(!IsLegalSchemaAction(missingSchemaAction))
194 throw new ArgumentOutOfRangeException("missingSchemaAction");
196 MergeManager.Merge(this, table, preserveChanges, missingSchemaAction);
199 private static bool IsLegalSchemaAction(MissingSchemaAction missingSchemaAction)
201 if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
202 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
207 [DataCategory ("Data")]
208 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
210 public string Namespace {
212 get { return _namespace; }
215 //TODO - trigger an event if this happens?
220 [DataCategory ("Data")]
221 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
223 public string Prefix {
225 get { return prefix; }
228 //TODO - trigger an event if this happens?
233 [DataCategory ("Data")]
234 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
235 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
236 public DataRelationCollection Relations {
238 return relationCollection;
243 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244 public override ISite Site {
247 throw new NotImplementedException ();
252 throw new NotImplementedException ();
256 [DataCategory ("Data")]
257 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
258 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
259 public DataTableCollection Tables {
260 get { return tableCollection; }
263 #endregion // Public Properties
265 #region Public Methods
268 public void AcceptChanges()
270 foreach (DataTable tempTable in tableCollection)
271 tempTable.AcceptChanges ();
276 // TODO: if currently bound to a XmlDataDocument
277 // throw a NotSupportedException
278 for (int t = 0; t < tableCollection.Count; t++) {
279 tableCollection[t].Clear ();
283 public virtual DataSet Clone()
285 DataSet Copy = new DataSet ();
286 CopyProperties (Copy);
288 foreach (DataTable Table in Tables) {
289 Copy.Tables.Add (Table.Clone ());
292 //Copy Relationships between tables after existance of tables
293 //and setting properties correctly
299 // Copies both the structure and data for this DataSet.
300 public DataSet Copy()
302 DataSet Copy = new DataSet ();
303 CopyProperties (Copy);
305 // Copy DatSet's tables
306 foreach (DataTable Table in Tables) {
307 Copy.Tables.Add (Table.Copy ());
310 //Copy Relationships between tables after existance of tables
311 //and setting properties correctly
318 private void CopyProperties (DataSet Copy)
320 Copy.CaseSensitive = CaseSensitive;
321 //Copy.Container = Container
322 Copy.DataSetName = DataSetName;
323 //Copy.DefaultViewManager
325 Copy.EnforceConstraints = EnforceConstraints;
326 //Copy.ExtendedProperties
328 //Copy.Locale = Locale;
329 Copy.Namespace = Namespace;
330 Copy.Prefix = Prefix;
336 private void CopyRelations (DataSet Copy)
339 //Creation of the relation contains some of the properties, and the constructor
\r
340 //demands these values. instead changing the DataRelation constructor and behaviour the
\r
341 //parameters are pre-configured and sent to the most general constructor
343 foreach (DataRelation MyRelation in this.Relations)
\r
345 string pTable = MyRelation.ParentTable.TableName;
\r
346 string cTable = MyRelation.ChildTable.TableName;
\r
347 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
\r
348 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
\r
350 foreach(DataColumn DC in MyRelation.ParentColumns)
\r
352 P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
\r
358 foreach(DataColumn DC in MyRelation.ChildColumns)
\r
360 C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
\r
365 DataRelation cRel = new DataRelation(MyRelation.RelationName,P_DC,C_DC);
\r
366 //cRel.ChildColumns = MyRelation.ChildColumns;
\r
367 //cRel.ChildTable = MyRelation.ChildTable;
\r
368 //cRel.ExtendedProperties = cRel.ExtendedProperties;
\r
369 //cRel.Nested = MyRelation.Nested;
\r
370 //cRel.ParentColumns = MyRelation.ParentColumns;
\r
371 //cRel.ParentTable = MyRelation.ParentTable;
\r
373 Copy.Relations.Add(cRel);
\r
380 public DataSet GetChanges()
382 return GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
386 public DataSet GetChanges(DataRowState rowStates)
388 if(!HasChanges(rowStates))
391 DataSet copySet = Clone();
392 IEnumerator tableEnumerator = Tables.GetEnumerator();
395 while (tableEnumerator.MoveNext())
397 origTable = (DataTable)tableEnumerator.Current;
398 copyTable = copySet.Tables[origTable.TableName];
400 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator();
401 while (rowEnumerator.MoveNext())
403 DataRow row = (DataRow)rowEnumerator.Current;
404 if (row.IsRowChanged(rowStates))
406 DataRow newRow = copyTable.NewRow();
407 copyTable.Rows.Add(newRow);
408 row.CopyValuesToRow(newRow);
416 public string GetXml()
418 StringWriter Writer = new StringWriter ();
419 WriteXml (Writer, XmlWriteMode.IgnoreSchema);
420 return Writer.ToString ();
423 public string GetXmlSchema()
425 StringWriter Writer = new StringWriter ();
426 WriteXmlSchema (Writer);
427 return Writer.ToString ();
431 public bool HasChanges()
433 return HasChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
437 public bool HasChanges(DataRowState rowState)
439 if(((int)rowState & 0xffffffe0) != 0)
440 throw new ArgumentOutOfRangeException("rowState");
442 DataTableCollection tableCollection = Tables;
444 DataRowCollection rowCollection;
446 for (int i = 0; i < tableCollection.Count; i++)
448 table = tableCollection[i];
449 rowCollection = table.Rows;
450 for (int j = 0; j < rowCollection.Count; j++)
452 row = rowCollection[j];
453 if((row.RowState & rowState) != 0)
462 public void InferXmlSchema(XmlReader reader, string[] nsArray)
466 public void InferXmlSchema(Stream stream, string[] nsArray)
468 InferXmlSchema (new XmlTextReader(stream), nsArray);
471 public void InferXmlSchema(TextReader reader, string[] nsArray)
473 InferXmlSchema (new XmlTextReader(reader), nsArray);
476 public void InferXmlSchema(string fileName, string[] nsArray)
478 XmlTextReader reader = new XmlTextReader(fileName);
480 InferXmlSchema (reader, nsArray);
486 public virtual void RejectChanges()
488 throw new NotImplementedException();
491 public virtual void Reset()
493 IEnumerator constraintEnumerator;
494 // first we remove all ForeignKeyConstraints (if we will not do that
495 // we will get an exception when clearing the tables).
496 for (int i = 0; i < Tables.Count; i++)
498 ConstraintCollection cc = Tables[i].Constraints;
499 for (int j = 0; j < cc.Count; j++)
501 if (cc[j] is ForeignKeyConstraint)
511 public void WriteXml(Stream stream)
513 XmlWriter writer = new XmlTextWriter(stream, null );
519 /// Writes the current data for the DataSet to the specified file.
521 /// <param name="filename">Fully qualified filename to write to</param>
522 public void WriteXml(string fileName)
524 XmlWriter writer = new XmlTextWriter(fileName, null );
531 public void WriteXml(TextWriter writer)
533 XmlWriter xwriter = new XmlTextWriter(writer );
538 public void WriteXml(XmlWriter writer)
540 WriteXml( writer, XmlWriteMode.IgnoreSchema );
543 public void WriteXml(Stream stream, XmlWriteMode mode)
545 XmlWriter writer = new XmlTextWriter(stream, null );
547 WriteXml( writer, mode );
550 public void WriteXml(string fileName, XmlWriteMode mode)
552 XmlWriter writer = new XmlTextWriter(fileName, null );
554 WriteXml( writer, mode );
559 public void WriteXml(TextWriter writer, XmlWriteMode mode)
561 XmlWriter xwriter = new XmlTextWriter(writer);
563 WriteXml( xwriter, mode );
566 public void WriteXml(XmlWriter writer, XmlWriteMode mode)
568 if (writer.WriteState == WriteState.Start)
569 writer.WriteStartDocument (true);
571 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
572 WriteStartElement( writer, mode, Namespace, Prefix, DataSetName );
574 if( mode == XmlWriteMode.WriteSchema )
576 DoWriteXmlSchema( writer );
579 //Write out each table in order, providing it is not
580 //part of another table structure via a nested parent relationship
581 foreach( DataTable table in Tables )
583 bool isTopLevel = true;
584 foreach( DataRelation rel in table.ParentRelations )
595 WriteTable( writer, table, mode );
599 writer.WriteEndElement();
602 public void WriteXmlSchema(Stream stream)
604 XmlWriter writer = new XmlTextWriter(stream, null );
606 WriteXmlSchema( writer );
609 public void WriteXmlSchema(string fileName)
611 XmlWriter writer = new XmlTextWriter( fileName, null );
613 WriteXmlSchema( writer );
616 public void WriteXmlSchema(TextWriter writer)
618 XmlWriter xwriter = new XmlTextWriter( writer );
620 WriteXmlSchema( xwriter );
623 public void WriteXmlSchema(XmlWriter writer)
625 ((XmlTextWriter)writer).Formatting = Formatting.Indented;
626 //Create a skeleton doc and then write the schema
627 //proper which is common to the WriteXml method in schema mode
628 writer.WriteStartDocument();
630 DoWriteXmlSchema( writer );
632 writer.WriteEndDocument();
635 public void ReadXmlSchema(Stream stream)
637 XmlReader reader = new XmlTextReader( stream, null );
638 ReadXmlSchema( reader);
641 public void ReadXmlSchema(string str)
643 XmlReader reader = new XmlTextReader( str );
644 ReadXmlSchema( reader );
647 public void ReadXmlSchema(TextReader treader)
649 XmlReader reader = new XmlTextReader( treader );
650 ReadXmlSchema( reader );
653 public void ReadXmlSchema(XmlReader reader)
655 XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
656 SchemaMapper.Read (reader);
659 public XmlReadMode ReadXml (Stream stream)
661 return ReadXml (new XmlTextReader (stream));
664 public XmlReadMode ReadXml (string str)
666 return ReadXml (new XmlTextReader (str));
669 public XmlReadMode ReadXml (TextReader reader)
671 return ReadXml (new XmlTextReader (reader));
674 public XmlReadMode ReadXml (XmlReader r)
676 XmlDataLoader Loader = new XmlDataLoader (this);
677 // FIXME: somekinda exception?
679 return XmlReadMode.Auto; // FIXME
682 * If document is diffgram we will use diffgram
684 if (r.LocalName == "diffgram")
685 return ReadXml (r, XmlReadMode.DiffGram);
688 * If we already have a schema, or the document
689 * contains an in-line schema, sets XmlReadMode to ReadSchema.
692 // FIXME: is this always true: "if we have tables we have to have schema also"
693 if (Tables.Count > 0)
694 return ReadXml (r, XmlReadMode.ReadSchema);
697 * If we dont have a schema yet and document
698 * contains no inline-schema mode is XmlReadMode.InferSchema
701 return ReadXml (r, XmlReadMode.InferSchema);
705 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
707 return ReadXml (new XmlTextReader (stream), mode);
710 public XmlReadMode ReadXml (string str, XmlReadMode mode)
712 return ReadXml (new XmlTextReader (str), mode);
715 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
717 return ReadXml (new XmlTextReader (reader), mode);
721 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
723 XmlReadMode Result = XmlReadMode.Auto;
725 if (mode == XmlReadMode.DiffGram) {
726 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
727 DiffLoader.Load (reader);
728 Result = XmlReadMode.DiffGram;
731 XmlDataLoader Loader = new XmlDataLoader (this);
732 Result = Loader.LoadData (reader, mode);
738 #endregion // Public Methods
740 #region Public Events
742 [DataCategory ("Action")]
743 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
744 public event MergeFailedEventHandler MergeFailed;
746 #endregion // Public Events
754 #endregion Destructors
756 #region IListSource methods
757 IList IListSource.GetList ()
759 return DefaultViewManager;
762 bool IListSource.ContainsListCollection {
767 #endregion IListSource methods
769 #region ISupportInitialize methods
770 public void BeginInit ()
772 throw new NotImplementedException ();
775 public void EndInit ()
777 throw new NotImplementedException ();
781 #region ISerializable
782 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
784 throw new NotImplementedException ();
788 #region Protected Methods
789 protected void GetSerializationData(SerializationInfo info, StreamingContext context)
791 string s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
792 if (s != null) ReadXmlSerializable (new XmlTextReader(new StringReader(s)));
796 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable()
798 return BuildSchema ();
801 protected virtual void ReadXmlSerializable(XmlReader reader)
803 ReadXml(reader, XmlReadMode.DiffGram); // FIXME
806 void IXmlSerializable.ReadXml(XmlReader reader)
808 reader.MoveToContent ();
809 reader.ReadStartElement (); // <DataSet>
811 reader.MoveToContent ();
812 ReadXmlSchema (reader);
814 reader.MoveToContent ();
815 ReadXml(reader, XmlReadMode.IgnoreSchema);
817 reader.MoveToContent ();
818 reader.ReadEndElement (); // </DataSet>
821 void IXmlSerializable.WriteXml(XmlWriter writer)
823 DoWriteXmlSchema (writer);
824 WriteXml(writer, XmlWriteMode.IgnoreSchema);
827 protected virtual bool ShouldSerializeRelations ()
832 protected virtual bool ShouldSerializeTables ()
838 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
843 protected virtual void OnRemoveRelation (DataRelation relation)
848 protected virtual void OnRemoveTable (DataTable table)
852 protected internal virtual void OnMergeFailed (MergeFailedEventArgs e)
854 if (MergeFailed != null)
855 MergeFailed(this, e);
859 protected internal void RaisePropertyChanging (string name)
864 #region Private Xml Serialisation
866 private string WriteObjectXml( object o ) {
867 switch (Type.GetTypeCode (o.GetType ())) {
868 case TypeCode.Boolean:
869 return XmlConvert.ToString ((Boolean) o);
871 return XmlConvert.ToString ((Byte) o);
873 return XmlConvert.ToString ((Char) o);
874 case TypeCode.DateTime:
875 return XmlConvert.ToString ((DateTime) o);
876 case TypeCode.Decimal:
877 return XmlConvert.ToString ((Decimal) o);
878 case TypeCode.Double:
879 return XmlConvert.ToString ((Double) o);
881 return XmlConvert.ToString ((Int16) o);
883 return XmlConvert.ToString ((Int32) o);
885 return XmlConvert.ToString ((Int64) o);
887 return XmlConvert.ToString ((SByte) o);
888 case TypeCode.Single:
889 return XmlConvert.ToString ((Single) o);
890 case TypeCode.UInt16:
891 return XmlConvert.ToString ((UInt16) o);
892 case TypeCode.UInt32:
893 return XmlConvert.ToString ((UInt32) o);
894 case TypeCode.UInt64:
895 return XmlConvert.ToString ((UInt64) o);
897 if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
898 if (o is Guid) return XmlConvert.ToString ((Guid) o);
902 private void WriteTable( XmlWriter writer, DataTable table, XmlWriteMode mode )
904 DataRow[] rows = new DataRow [table.Rows.Count];
905 table.Rows.CopyTo (rows, 0);
906 WriteTable (writer, rows, mode);
909 private void WriteTable( XmlWriter writer, DataRow[] rows, XmlWriteMode mode )
911 //The columns can be attributes, hidden, elements, or simple content
912 //There can be 0-1 simple content cols or 0-* elements
913 System.Collections.ArrayList atts;
914 System.Collections.ArrayList elements;
915 DataColumn simple = null;
917 if (rows.Length == 0) return;
918 DataTable table = rows[0].Table;
919 SplitColumns( table, out atts, out elements, out simple );
921 foreach( DataRow row in rows )
923 //sort out the namespacing
924 string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
926 // First check are all the rows null. If they are we just write empty element
927 bool AllNulls = true;
928 foreach (DataColumn dc in table.Columns) {
930 if (row [dc.ColumnName] != DBNull.Value) {
936 // If all of the columns were null, we have to write empty element
938 writer.WriteElementString (table.TableName, "");
942 WriteStartElement( writer, mode, nspc, table.Prefix, table.TableName );
944 foreach( DataColumn col in atts )
946 WriteAttributeString( writer, mode, col.Namespace, col.Prefix, col.ColumnName, row[col].ToString() );
951 writer.WriteString( WriteObjectXml(row[simple]) );
955 foreach( DataColumn col in elements )
957 string colnspc = nspc;
958 object rowObject = row [col];
960 if (rowObject == null || rowObject == DBNull.Value)
963 if( col.Namespace != null )
965 colnspc = col.Namespace;
968 //TODO check if I can get away with write element string
969 WriteStartElement( writer, mode, colnspc, col.Prefix, col.ColumnName );
970 writer.WriteString( WriteObjectXml(rowObject) );
971 writer.WriteEndElement();
975 foreach (DataRelation relation in table.ChildRelations) {
976 if (relation.Nested) {
977 WriteTable (writer, row.GetChildRows(relation), mode);
981 writer.WriteEndElement();
986 private void WriteStartElement( XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name )
990 case XmlWriteMode.WriteSchema:
991 if( nspc == null || nspc == "" )
993 writer.WriteStartElement( name );
995 else if( prefix != null )
997 writer.WriteStartElement(prefix, name, nspc );
1001 writer.WriteStartElement( writer.LookupPrefix( nspc ), name, nspc );
1004 case XmlWriteMode.DiffGram:
1005 throw new NotImplementedException();
1007 writer.WriteStartElement(name );
1012 private void WriteAttributeString( XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue )
1016 case XmlWriteMode.WriteSchema:
1017 writer.WriteAttributeString(prefix, name, nspc );
1019 case XmlWriteMode.DiffGram:
1020 throw new NotImplementedException();
1022 writer.WriteAttributeString(name, stringValue );
1027 XmlSchema IXmlSerializable.GetSchema()
1029 return BuildSchema ();
1032 XmlSchema BuildSchema()
1034 XmlSchema schema = new XmlSchema ();
1035 schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1037 XmlSchemaElement elem = new XmlSchemaElement ();
1038 elem.Name = DataSetName;
1040 XmlDocument doc = new XmlDocument ();
1042 XmlAttribute[] atts = new XmlAttribute [2];
1043 atts[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1044 atts[0].Value = "true";
1046 atts[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1047 atts[1].Value = locale.Name;
1048 elem.UnhandledAttributes = atts;
1050 schema.Items.Add (elem);
1052 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1053 elem.SchemaType = complex;
1055 XmlSchemaChoice choice = new XmlSchemaChoice ();
1056 complex.Particle = choice;
1057 choice.MaxOccursString = XmlConstants.Unbounded;
1059 //Write out schema for each table in order, providing it is not
1060 //part of another table structure via a nested parent relationship
1061 foreach( DataTable table in Tables )
1063 bool isTopLevel = true;
1064 foreach( DataRelation rel in table.ParentRelations )
1075 choice.Items.Add (GetTableSchema (doc, table));
1079 //TODO - now add in the relationships as key and unique constraints etc
1084 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table)
1090 SplitColumns (table, out atts, out elements, out simple);
1092 XmlSchemaElement elem = new XmlSchemaElement ();
1093 elem.Name = table.TableName;
1095 XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1096 elem.SchemaType = complex;
1098 //TODO - what about the simple content?
1099 if( elements.Count == 0 )
1104 //A sequence of element types or a simple content node
1106 XmlSchemaSequence seq = new XmlSchemaSequence ();
1107 complex.Particle = seq;
1109 foreach( DataColumn col in elements )
1111 //<xs:element name=ColumnName type=MappedType Ordinal=index>
1112 XmlSchemaElement colElem = new XmlSchemaElement ();
1113 colElem.Name = col.ColumnName;
1115 if (col.ColumnName != col.Caption && col.Caption != string.Empty)
1117 XmlAttribute[] xatts = new XmlAttribute[1];
1118 xatts[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1119 xatts[0].Value = col.Caption;
1120 colElem.UnhandledAttributes = xatts;
1123 if (col.DefaultValue.ToString () != string.Empty)
1124 colElem.DefaultValue = col.DefaultValue.ToString ();
1126 colElem.SchemaTypeName = MapType (col.DataType);
1128 if( col.AllowDBNull )
1130 colElem.MinOccurs = 0;
1133 //writer.WriteAttributeString( XmlConstants.MsdataPrefix,
1134 // XmlConstants.Ordinal,
1135 // XmlConstants.MsdataNamespace,
1136 // col.Ordinal.ToString() );
1138 // Write SimpleType if column have MaxLength
1139 if (col.MaxLength > -1)
\r
1141 colElem.SchemaType = GetTableSimpleType (doc, col);
1144 seq.Items.Add (colElem);
1148 //Then a list of attributes
1149 foreach( DataColumn col in atts )
1151 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1152 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1153 att.Name = col.ColumnName;
1154 att.Form = XmlSchemaForm.Unqualified;
1155 att.SchemaTypeName = MapType (col.DataType);
1156 complex.Attributes.Add (att);
1161 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1164 XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1167 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1168 restriction.BaseTypeName = MapType (col.DataType);
1171 XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1172 max.Value = XmlConvert.ToString (col.MaxLength);
1173 restriction.Facets.Add (max);
1178 private void DoWriteXmlSchema( XmlWriter writer )
1180 GetSchemaSerializable ().Write (writer);
1184 /// Helper function to split columns into attributes elements and simple
1187 private void SplitColumns( DataTable table,
1189 out ArrayList elements,
1190 out DataColumn simple)
1192 //The columns can be attributes, hidden, elements, or simple content
1193 //There can be 0-1 simple content cols or 0-* elements
1194 atts = new System.Collections.ArrayList();
1195 elements = new System.Collections.ArrayList();
1198 //Sort out the columns
1199 foreach( DataColumn col in table.Columns )
1201 switch( col.ColumnMapping )
1203 case MappingType.Attribute:
1206 case MappingType.Element:
1207 elements.Add( col );
1209 case MappingType.SimpleContent:
1210 if( simple != null )
1212 throw new System.InvalidOperationException( "There may only be one simple content element" );
1217 //ignore Hidden elements
1223 private XmlQualifiedName MapType (Type type)
1225 switch (Type.GetTypeCode (type))
1227 case TypeCode.String: return XmlConstants.QnString;
1228 case TypeCode.Int16: return XmlConstants.QnShort;
1229 case TypeCode.Int32: return XmlConstants.QnInt;
1230 case TypeCode.Int64: return XmlConstants.QnLong;
1231 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1232 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1233 case TypeCode.Char: return XmlConstants.QnChar;
1234 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1235 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1236 case TypeCode.Double: return XmlConstants.QnDouble;
1237 case TypeCode.SByte: return XmlConstants.QnSbyte;
1238 case TypeCode.Single: return XmlConstants.QnFloat;
1239 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1240 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1241 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1244 if (typeof (TimeSpan) == type) return XmlConstants.QnDuration;
1245 else if (typeof (System.Uri) == type) return XmlConstants.QnUri;
1246 else if (typeof (byte[]) == type) return XmlConstants.QnBase64Binary;
1247 else if (typeof (XmlQualifiedName) == type) return XmlConstants.QnXmlQualifiedName;
1248 else return XmlConstants.QnString;
1251 #endregion //Private Xml Serialisation