XmlSchemaDataImporter.cs :  » 2.6.4-mono-.net-core » System.Data » System » Data » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Data 
System.Data » System » Data » XmlSchemaDataImporter.cs
//
// XmlSchemaDataImporter.cs
//
// Author:
//  Atsushi Enomoto <atsushi@ximian.com>
//
// (C)2004 Novell Inc.
//
//
// ***** The design note became somewhat obsolete. Should be rewritten. *****
//
// * Design Notes
//
// ** Abstract
//
//  This class is used to import an XML Schema into a DataSet schema.
//
//  Only XmlReader is acceptable as the input to the class.
//  This class is not expected to read XML Schema multi time.
//
// ** Targetable Schema Components
//
//  Only global global elements that hold complex type are converted 
//  into a table. 
//  <del>
//  The components of the type of the element are subsequently converted
//  into a table, BUT there is an exception. As for "DataSet elements",
//  the type is just ignored (see "DataSet Element definition" below).
//  </del><ins>
//  The components of the type of the element are subsequently converted
//  into a table. As for "DataSet elements", its complex type is also 
//  handled.
//  </ins>
//
//  Unused complex types are never be converted.
//
//  Global simple types and global attributes are never converted.
//  They cannot be a table.
//  Local complex types are also converted into a table.
//
//  Local elements are converted into either a table or a column in
//  the "context DataTable". Simple-typed element is not always converted
//  into a DataColumn; if maxOccurs > 1, it will be converted as a table.
//
// ** Name Convention
//
//  Ignore this section. Microsoft.NET was buggy enough to confuse
//  against these name conflicts.
//
//  Since local complex types are anonymous, we have to name for each
//  component. Thus, and since complex types and elements can have the 
//  same name each other, we have to manage a table for mappings from 
//  a name to a component. The names must be also used in DataRelation
//  definitions correctly.
//
// ** DataSet element definition
//
//  "DataSet element" is 1) such element that has an attribute 
//  msdata:IsDataSet (where prefix "msdata" is bound to 
//  urn:schemas-microsoft-com:xml-msdata), or 2) the only one
//  element definition in the schema.
//
//  There is another complicated rule. 1) If there is only one element EL 
//  in the schema, and 2) if the type of EL is complex named CT, and 3)
//  the content of the CT is a group base, and 4) the group base contains 
//  an element EL2, and finally 5) if EL2 is complex, THEN the element is
//  the DataSet element.
//
//  Only the first global element that matches the condition above is
//  regarded as DataSet element (by necessary design or just a bug?) 
//  instead of handling as an error.
//
//  All global elements are considered as an alternative in the dataset
//  element.
//
//  For local elements, msdata:IsDataSet are just ignored.
//
// ** Importing Complex Types as Columns
//
//  When an xs:element is going to be mapped, its complex type (remember
//  that only complex-typed elements are targettable) are expanded to
//  DataColumn.
//
//  DataColumn has a property MappingType that shows whether this column
//   came from attribute or element.
//
//  [Question: How about MappingType.Simple? How is it used?]
//
//  Additionally, for particle elements, it might also create another
//  DataTable (but for the particle elements in context DataTable, it
//  will create an index to the new table).
//
//  For group base particles (XmlSchemaGroupBase; sequence, choice, all)
//  each component in those groups are mapped to a column. Even if you
//  import "choice" or "all" components, DataSet.WriteXmlSchema() will
//  output them just as a "sequence".
//
//  Columns cannot be added directly to current context DataTable; they
//  need to be added after processing all the columns, because they may
//  have msdata:Ordinal attribute that specifies the order of the columns
//  in the DataTable.
//
//  "Nested elements" are not allowed. (Clarification required?)
//
// ** Identity Constraints and DataRelations
//
// *** DataRelations from element identity constraints
//
//  Only constraints on "DataSet element" is considered. All other
//  constraint definitions are ignored. Note that it is DataSet that has
//  the property Relations (of type DataRelationCollection).
//
//  xs:key and xs:unique are handled as the same (then both will be
//  serialized as xs:unique).
//
//  The XPath expressions in the constraints are strictly limited; they
//  are expected to be expandable enough to be mappable for each
//
//    * selector to "any_valid_XPath/is/OK/blah" 
//      where "blah" is one of the DataTable name. It looks that
//      only the last QName section is significant and any heading
//      XPath step is OK (even if the mapped node does not exist).
//    * field to QName that is mapped to DataColumn in the DataTable
//      (even ./QName is not allowed)
//
// *** DataRelations from annotations
//
//  See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/_mapping_relationship_specified_for_nested_elements.asp and http://msdn.microsoft.com/library/en-us/cpguide/html/_specifying_relationship_between_elements_with_no_nesting.asp
//
// ** Informative References
//
// Generating DataSet Relational Structure from XML Schema (XSD)
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/_generating_dataset_relational_structure_from_xsd.asp
//

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.Xml;
using System.Xml.Schema;


namespace System.Data{
  internal class TableStructureCollection : CollectionBase
  {
    public void Add (TableStructure table)
    {
      List.Add (table);
    }

    public TableStructure this [int i] {
      get { return List [i] as TableStructure; }
    }

    public TableStructure this [string name] {
      get {
        foreach (TableStructure ts in List)
          if (ts.Table.TableName == name)
            return ts;
        return null;
      }
    }
  }

  internal class RelationStructureCollection : CollectionBase
  {
    public void Add (RelationStructure rel)
    {
      List.Add (rel);
    }

    public RelationStructure this [int i] {
      get { return List [i] as RelationStructure; }
    }

    public RelationStructure this [string parent, string child] {
      get {
        foreach (RelationStructure rel in List)
          if (rel.ParentTableName == parent && rel.ChildTableName == child)
            return rel;
        return null;
      }
    }
  }
  
  internal class TableStructure
  {
    public TableStructure (DataTable table)
    {
      this.Table = table;
    }

    // The columns and orders which will be added to the context
    // table (See design notes; Because of the ordinal problem)
    public DataTable Table;
    public Hashtable OrdinalColumns = new Hashtable ();
    public ArrayList NonOrdinalColumns = new ArrayList ();
    public DataColumn PrimaryKey;

    public bool ContainsColumn (string name)
    {
      foreach (DataColumn col in NonOrdinalColumns)
        if (col.ColumnName == name)
          return true;
      foreach (DataColumn col in OrdinalColumns.Keys)
        if (col.ColumnName == name)
          return true;
      return false;
    }
  }

  internal class RelationStructure
  {
    public string ExplicitName;
    public string ParentTableName;
    public string ChildTableName;
    public string ParentColumnName;
    public string ChildColumnName;
    public bool IsNested;
    public bool CreateConstraint;
  }

  internal class ConstraintStructure
  {
    public readonly string TableName;
    public readonly string [] Columns;
    public readonly bool [] IsAttribute;
    public readonly string ConstraintName;
    public readonly bool IsPrimaryKey;
    public readonly string ReferName;
    public readonly bool IsNested;
    public readonly bool IsConstraintOnly;

    public ConstraintStructure (string tname, string [] cols, bool [] isAttr, string cname, bool isPK, string refName, bool isNested, bool isConstraintOnly)
    {
      TableName = tname;
      Columns = cols;
      IsAttribute = isAttr;
      ConstraintName = XmlHelper.Decode (cname);
      IsPrimaryKey = isPK;
      ReferName = refName;
      IsNested = isNested;
      IsConstraintOnly = isConstraintOnly;
    }
  }

  internal class XmlSchemaDataImporter
  {
    static readonly XmlSchemaDatatype schemaIntegerType;
    static readonly XmlSchemaDatatype schemaDecimalType;
    static readonly XmlSchemaComplexType schemaAnyType;

    static XmlSchemaDataImporter ()
    {
      XmlSchema s = new XmlSchema ();
      XmlSchemaAttribute a = new XmlSchemaAttribute ();
      a.Name = "foo";
      a.SchemaTypeName = new XmlQualifiedName ("integer", XmlSchema.Namespace);
      s.Items.Add (a);
      XmlSchemaAttribute b = new XmlSchemaAttribute ();
      b.Name = "bar";
      b.SchemaTypeName = new XmlQualifiedName ("decimal", XmlSchema.Namespace);
      s.Items.Add (b);
      XmlSchemaElement e = new XmlSchemaElement ();
      e.Name = "bar";
      s.Items.Add (e);
      s.Compile (null);
#if NET_2_0
      schemaIntegerType = ((XmlSchemaSimpleType) a.AttributeSchemaType).Datatype;
      schemaDecimalType = ((XmlSchemaSimpleType) b.AttributeSchemaType).Datatype;
      schemaAnyType = e.ElementSchemaType as XmlSchemaComplexType;
#else
      schemaIntegerType = a.AttributeType as XmlSchemaDatatype;
      schemaDecimalType = b.AttributeType as XmlSchemaDatatype;
      schemaAnyType = e.ElementType as XmlSchemaComplexType;
#endif
    }

    #region Fields

    DataSet dataset;
    bool forDataSet;
    XmlSchema schema;

    ArrayList relations = new ArrayList ();
    Hashtable reservedConstraints = new Hashtable ();

    // such element that has an attribute msdata:IsDataSet="true"
    XmlSchemaElement datasetElement;

    // choice alternatives in the "dataset element"
    ArrayList topLevelElements = new ArrayList ();

    // import target elements
    ArrayList targetElements = new ArrayList ();

    TableStructure currentTable;
  
#if NET_2_0
    // TODO: Do we need a collection here?
    TableAdapterSchemaInfo currentAdapter;
#endif
    #endregion

    // .ctor()

    public XmlSchemaDataImporter (DataSet dataset, XmlReader reader, bool forDataSet)
    {
      this.dataset = dataset;
      this.forDataSet = forDataSet;
      dataset.DataSetName = "NewDataSet"; // Initialize always
      schema = XmlSchema.Read (reader, null);
      if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace)
        reader.ReadEndElement ();
      schema.Compile (null);
    }

#if NET_2_0
    // properties
    internal TableAdapterSchemaInfo CurrentAdapter {
      get { return currentAdapter; }
    }
#endif
    
    // methods

    public void Process ()
    {
      if (schema.Id != null)
        dataset.DataSetName = schema.Id; // default. Overridable by "DataSet element"
      dataset.Namespace = schema.TargetNamespace;

      // Find dataset element
      foreach (XmlSchemaObject obj in schema.Items) {
        XmlSchemaElement el = obj as XmlSchemaElement;
        if (el != null) {
          if (datasetElement == null &&
            IsDataSetElement (el))
            datasetElement = el;
#if NET_2_0
          if (el.ElementSchemaType is XmlSchemaComplexType &&
              el.ElementSchemaType != schemaAnyType)
#else
          if (el.ElementType is XmlSchemaComplexType &&
              el.ElementType != schemaAnyType)
#endif
            targetElements.Add (obj);
        }
      }

      // make reservation of identity constraints
      if (datasetElement != null) {
        // keys/uniques.
        foreach (XmlSchemaObject obj in datasetElement.Constraints)
          if (! (obj is XmlSchemaKeyref))
            ReserveSelfIdentity ((XmlSchemaIdentityConstraint) obj);
        // keyrefs.
        foreach (XmlSchemaObject obj in datasetElement.Constraints)
          if (obj is XmlSchemaKeyref)
            ReserveRelationIdentity (datasetElement, (XmlSchemaKeyref) obj);
      }

      foreach (XmlSchemaObject obj in schema.Items) {
        if (obj is XmlSchemaElement) {
          XmlSchemaElement el = obj as XmlSchemaElement;
#if NET_2_0
          if (el.ElementSchemaType is XmlSchemaComplexType &&
              el.ElementSchemaType != schemaAnyType)
#else
          if (el.ElementType is XmlSchemaComplexType &&
              el.ElementType != schemaAnyType)
#endif
            targetElements.Add (obj);
        }
      }

      // This collection will grow up while processing elements.
      int globalElementCount = targetElements.Count;

      for (int i = 0; i < globalElementCount; i++)
        ProcessGlobalElement ((XmlSchemaElement) targetElements [i]);

      // Rest are local elements.
      for (int i = globalElementCount; i < targetElements.Count; i++)
        ProcessDataTableElement ((XmlSchemaElement) targetElements [i]);

      // Handle relation definitions written as xs:annotation.
      // See detail: http://msdn.microsoft.com/library/shared/happyUrl/fnf_msdn.asp?Redirect=%22http://msdn.microsoft.com/404/default.asp%22
      foreach (XmlSchemaObject obj in schema.Items)
        if (obj is XmlSchemaAnnotation)
          HandleAnnotations ((XmlSchemaAnnotation) obj, false);

      if (datasetElement != null) {
        // Handle constraints in the DataSet element. First keys.
        foreach (XmlSchemaObject obj in datasetElement.Constraints)
          if (! (obj is XmlSchemaKeyref))
            ProcessSelfIdentity (reservedConstraints [obj] as ConstraintStructure);
        // Then keyrefs.
        foreach (XmlSchemaObject obj in datasetElement.Constraints)
          if (obj is XmlSchemaKeyref)
            ProcessRelationIdentity (datasetElement, reservedConstraints [obj] as ConstraintStructure);
      }

      foreach (RelationStructure rs in this.relations)
        dataset.Relations.Add (GenerateRelationship (rs));
    }

    private bool IsDataSetElement (XmlSchemaElement el)
    {
      if (el.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in el.UnhandledAttributes) {
          if (attr.LocalName == "IsDataSet" &&
            attr.NamespaceURI == XmlConstants.MsdataNamespace) {
            switch (attr.Value) {
            case "true": // case sensitive
              return true;
            case "false":
              break;
            default:
              throw new DataException (String.Format ("Value {0} is invalid for attribute 'IsDataSet'.", attr.Value));
            }
          }
        }
      }

      if (schema.Elements.Count != 1)
        return false;
      if (!(el.SchemaType is XmlSchemaComplexType))
        return false;
      XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
      if (ct.AttributeUses.Count > 0)
        return false;
      XmlSchemaGroupBase gb = ct.ContentTypeParticle as XmlSchemaGroupBase;
      if (gb == null || gb.Items.Count == 0)
        return false;
      foreach (XmlSchemaParticle p in gb.Items) {
        if (ContainsColumn (p))
          return false;
      }
      return true;
    }

    private bool ContainsColumn (XmlSchemaParticle p)
    {
      XmlSchemaElement el = p as XmlSchemaElement;
      if (el != null) {
        XmlSchemaComplexType ct = null;
#if NET_2_0
        ct = el.ElementSchemaType as XmlSchemaComplexType;
#else
        ct = el.ElementType as XmlSchemaComplexType;
#endif
        if (ct == null || ct == schemaAnyType)
          return true; // column element
        if (ct.AttributeUses.Count > 0)
          return false; // table element
        if (ct.ContentType == XmlSchemaContentType.TextOnly)
          return true; // column element
        else
          return false; // table element
      }
      XmlSchemaGroupBase gb = p as XmlSchemaGroupBase;
      for (int i = 0; i < gb.Items.Count; i++) {
        if (ContainsColumn ((XmlSchemaParticle) gb.Items [i]))
          return true;
      }
      return false;
    }

    private void ProcessGlobalElement (XmlSchemaElement el)
    {
      // If it is already registered (by resolving reference
      // in previously-imported elements), just ignore.
      if (dataset.Tables.Contains (el.QualifiedName.Name))
        return;

      // If type is not complex, just skip this element
#if NET_2_0
      if (! (el.ElementSchemaType is XmlSchemaComplexType && el.ElementSchemaType != schemaAnyType))
#else
      if (! (el.ElementType is XmlSchemaComplexType && el.ElementType != schemaAnyType))
#endif
        return;

      if (IsDataSetElement (el)) {
        ProcessDataSetElement (el);
        return;
      }
      else
        dataset.Locale = CultureInfo.CurrentCulture;

      // Register as a top-level element
      topLevelElements.Add (el);
      // Create DataTable for this element
      ProcessDataTableElement (el);
    }

    private void ProcessDataSetElement (XmlSchemaElement el)
    {
      dataset.DataSetName = el.Name;
      this.datasetElement = el;

      // Search for locale attributes
      bool useCurrent = false;
      if (el.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in el.UnhandledAttributes) {
#if NET_2_0
          if (attr.LocalName == "UseCurrentLocale" &&
            attr.NamespaceURI == XmlConstants.MsdataNamespace)
            useCurrent = true;
#endif
          if (attr.LocalName == "Locale" &&
            attr.NamespaceURI == XmlConstants.MsdataNamespace) {
            CultureInfo ci = new CultureInfo (attr.Value);
            dataset.Locale = ci;
          }
        }
      }
#if NET_2_0
      if (!useCurrent && !dataset.LocaleSpecified) // then set current culture instance _explicitly_
        dataset.Locale = CultureInfo.CurrentCulture;
#endif

      // Process content type particle (and create DataTable)
      XmlSchemaComplexType ct = null;
#if NET_2_0
      ct = el.ElementSchemaType as XmlSchemaComplexType;
#else
      ct = el.ElementType as XmlSchemaComplexType;
#endif
      XmlSchemaParticle p = ct != null ? ct.ContentTypeParticle : null;
      if (p != null)
        HandleDataSetContentTypeParticle (p);
    }

    private void HandleDataSetContentTypeParticle (XmlSchemaParticle p)
    {
      XmlSchemaElement el = p as XmlSchemaElement;
      if (el != null) {
#if NET_2_0
        if (el.ElementSchemaType is XmlSchemaComplexType && el.RefName != el.QualifiedName)
#else
        if (el.ElementType is XmlSchemaComplexType && el.RefName != el.QualifiedName)
#endif
          ProcessDataTableElement (el);
      }
      else if (p is XmlSchemaGroupBase) {
        foreach (XmlSchemaParticle pc in ((XmlSchemaGroupBase) p).Items)
          HandleDataSetContentTypeParticle (pc);
      }
    }

    private void ProcessDataTableElement (XmlSchemaElement el)
    {
      string tableName = XmlHelper.Decode (el.QualifiedName.Name);
      // If it is already registered, just ignore.
      if (dataset.Tables.Contains (tableName))
        return;

      DataTable table = new DataTable (tableName);
      table.Namespace = el.QualifiedName.Namespace;
      TableStructure oldTable = currentTable;
      currentTable = new TableStructure (table);

      dataset.Tables.Add (table);

      // Find Locale
      if (el.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in el.UnhandledAttributes) {
          if (attr.LocalName == "Locale" &&
            attr.NamespaceURI == XmlConstants.MsdataNamespace)
            table.Locale = new CultureInfo (attr.Value);
        }
      }

      // Handle complex type (NOTE: It is (or should be)
      // impossible the type is other than complex type).
      XmlSchemaComplexType ct = null;
#if NET_2_0
      ct = (XmlSchemaComplexType) el.ElementSchemaType;
#else
      ct = (XmlSchemaComplexType) el.ElementType;
#endif

      // Handle attributes
      foreach (DictionaryEntry de in ct.AttributeUses)
        ImportColumnAttribute ((XmlSchemaAttribute) de.Value);

      // Handle content type particle
      if (ct.ContentTypeParticle is XmlSchemaElement)
        ImportColumnElement (el, (XmlSchemaElement) ct.ContentTypeParticle);
      else if (ct.ContentTypeParticle is XmlSchemaGroupBase)
        ImportColumnGroupBase (el, (XmlSchemaGroupBase) ct.ContentTypeParticle);
      // else if null then do nothing.

      // Handle simple content
      switch (ct.ContentType) {
      case XmlSchemaContentType.TextOnly:
//      case XmlSchemaContentType.Mixed:
        // LAMESPEC: When reading from XML Schema, it maps to "_text", while on the data inference, it is mapped to "_Text" (case ignorant).
        string simpleName = el.QualifiedName.Name + "_text";
        DataColumn simple = new DataColumn (simpleName);
        simple.Namespace = el.QualifiedName.Namespace;
        simple.AllowDBNull = (el.MinOccurs == 0);
        simple.ColumnMapping = MappingType.SimpleContent;
        simple.DataType = ConvertDatatype (ct.Datatype);
        currentTable.NonOrdinalColumns.Add (simple);
        break;
      }

      // add columns to the table in specified order 
      // (by msdata:Ordinal attributes)
      SortedList sd = new SortedList ();
      foreach (DictionaryEntry de in currentTable.OrdinalColumns)
        sd.Add (de.Value, de.Key);
      foreach (DictionaryEntry de in sd)
        table.Columns.Add ((DataColumn) de.Value);
      foreach (DataColumn dc in currentTable.NonOrdinalColumns)
        table.Columns.Add (dc);

      currentTable = oldTable;
    }

    private DataRelation GenerateRelationship (RelationStructure rs)
    {
      DataTable ptab = dataset.Tables [rs.ParentTableName];
      DataTable ctab = dataset.Tables [rs.ChildTableName];

      DataRelation rel ;
      string name = rs.ExplicitName != null ? rs.ExplicitName : XmlHelper.Decode (ptab.TableName) + '_' + XmlHelper.Decode (ctab.TableName);

      // Annotation Relations belonging to a DataSet can contain multiple colnames
      // in parentkey and childkey.
      if (datasetElement != null) {
        String[] pcolnames = rs.ParentColumnName.Split (null);
        String[] ccolnames = rs.ChildColumnName.Split (null);

        DataColumn[] pcol = new DataColumn [pcolnames.Length];
        for (int i=0; i<pcol.Length; ++i)
          pcol [i] = ptab.Columns [XmlHelper.Decode (pcolnames [i])];

        DataColumn[] ccol = new DataColumn [ccolnames.Length];
        for (int i=0; i < ccol.Length; ++i) {
          ccol [i] = ctab.Columns [XmlHelper.Decode (ccolnames [i])];
          if (ccol [i] == null)
            ccol [i] = CreateChildColumn (pcol [i], ctab);
        }
        rel = new DataRelation (name, pcol, ccol, rs.CreateConstraint);
      } else {
        DataColumn pcol = ptab.Columns [XmlHelper.Decode (rs.ParentColumnName)];
        DataColumn ccol = ctab.Columns [XmlHelper.Decode (rs.ChildColumnName)];
        if (ccol == null) 
          ccol = CreateChildColumn (pcol, ctab);
        rel = new DataRelation (name, pcol, ccol, rs.CreateConstraint);
      }
      rel.Nested = rs.IsNested;
      if (rs.CreateConstraint)
        rel.ParentTable.PrimaryKey = rel.ParentColumns;
      return rel;
    }

    private DataColumn CreateChildColumn (DataColumn parentColumn, DataTable childTable)
    {
      DataColumn col = childTable.Columns.Add (parentColumn.ColumnName, 
                parentColumn.DataType);
      col.Namespace = String.Empty;
      col.ColumnMapping = MappingType.Hidden;
      return col;
    }

    private void ImportColumnGroupBase (XmlSchemaElement parent, XmlSchemaGroupBase gb)
    {
      foreach (XmlSchemaParticle p in gb.Items) {
        XmlSchemaElement el = p as XmlSchemaElement;
        if (el != null)
          ImportColumnElement (parent, el);
        else if (p is XmlSchemaGroupBase)
          ImportColumnGroupBase (parent, (XmlSchemaGroupBase) p);
        // otherwise p is xs:any
      }
    }

    private XmlSchemaDatatype GetSchemaPrimitiveType (object type)
    {
      if (type is XmlSchemaComplexType)
        return null; // It came here, so that maybe it is xs:anyType
      XmlSchemaDatatype dt = type as XmlSchemaDatatype;
      if (dt == null && type != null)
        dt = ((XmlSchemaSimpleType) type).Datatype;
      return dt;
    }

    // Note that this column might be Hidden
    private void ImportColumnAttribute (XmlSchemaAttribute attr)
    {
      DataColumn col = new DataColumn ();
      col.ColumnName = attr.QualifiedName.Name;
      col.Namespace = attr.QualifiedName.Namespace;
      XmlSchemaDatatype dt = null;
#if NET_2_0
      dt = GetSchemaPrimitiveType (((XmlSchemaSimpleType) attr.AttributeSchemaType).Datatype);
#else
      dt = GetSchemaPrimitiveType (attr.AttributeType);
#endif
      // This complicated check comes from the fact that
      // MS.NET fails to map System.Object to anyType (that
      // will cause ReadTypedObject() fail on XmlValidatingReader).
      // ONLY In DataSet context, we set System.String for
      // simple ur-type.
      col.DataType = ConvertDatatype (dt);
      if (col.DataType == typeof (object))
        col.DataType = typeof (string);
      // When attribute use="prohibited", then it is regarded as 
      // Hidden column.
      if (attr.Use == XmlSchemaUse.Prohibited)
        col.ColumnMapping = MappingType.Hidden;
      else {
        col.ColumnMapping = MappingType.Attribute;
        col.DefaultValue = GetAttributeDefaultValue (attr);
      }
      if (attr.Use == XmlSchemaUse.Required)
        col.AllowDBNull = false;

#if NET_2_0
      FillFacet (col, attr.AttributeSchemaType as XmlSchemaSimpleType);
#else
      FillFacet (col, attr.AttributeType as XmlSchemaSimpleType);
#endif

      // Call this method after filling the name
      ImportColumnMetaInfo (attr, attr.QualifiedName, col);
      AddColumn (col);
    }

    private void ImportColumnElement (XmlSchemaElement parent, XmlSchemaElement el)
    {
      // FIXME: element nest check

      DataColumn col = new DataColumn ();
      col.DefaultValue = GetElementDefaultValue (el);
      col.AllowDBNull = (el.MinOccurs == 0);

#if NET_2_0
      if (el.ElementSchemaType is XmlSchemaComplexType && el.ElementSchemaType != schemaAnyType)
#else
      if (el.ElementType is XmlSchemaComplexType && el.ElementType != schemaAnyType)
#endif
        FillDataColumnComplexElement (parent, el, col);
      else if (el.MaxOccurs != 1)
        FillDataColumnRepeatedSimpleElement (parent, el, col);
      else
        FillDataColumnSimpleElement (el, col);
    }

    // common process for element and attribute
    private void ImportColumnMetaInfo (XmlSchemaAnnotated obj, XmlQualifiedName name, DataColumn col)
    {
      if (obj.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in obj.UnhandledAttributes) {
          if (attr.NamespaceURI != XmlConstants.MsdataNamespace)
            continue;
          switch (attr.LocalName) {
          case XmlConstants.Caption:
            col.Caption = attr.Value;
            break;
          case XmlConstants.DataType:
            col.DataType = Type.GetType (attr.Value);
            break;
          case XmlConstants.AutoIncrement:
            col.AutoIncrement = bool.Parse (attr.Value);
            break;
          case XmlConstants.AutoIncrementSeed:
            col.AutoIncrementSeed = int.Parse (attr.Value);
            break;
          case XmlConstants.AutoIncrementStep:
            col.AutoIncrementStep = int.Parse (attr.Value);
            break;
          case XmlConstants.ReadOnly:
            col.ReadOnly = XmlConvert.ToBoolean (attr.Value);
            break;
          case XmlConstants.Ordinal:
            int ordinal = int.Parse (attr.Value);
            break;
          }
        }
      }
    }

    private void FillDataColumnComplexElement (XmlSchemaElement parent, XmlSchemaElement el, DataColumn col)
    {
      if (targetElements.Contains (el))
        return; // do nothing

      string elName = XmlHelper.Decode (el.QualifiedName.Name);
      if (elName == dataset.DataSetName)
        // Well, why it is ArgumentException :-?
        throw new ArgumentException ("Nested element must not have the same name as DataSet's name.");

      if (el.Annotation != null)
        HandleAnnotations (el.Annotation, true);
      // If xsd:keyref xsd:key for this table exists, then don't add
      // relation here manually.
      else if (!DataSetDefinesKey (elName)) {
        AddParentKeyColumn (parent, el, col);

        RelationStructure rel = new RelationStructure ();
        rel.ParentTableName = XmlHelper.Decode (parent.QualifiedName.Name);
        rel.ChildTableName = elName;
        rel.ParentColumnName = col.ColumnName;
        rel.ChildColumnName = col.ColumnName;
        rel.CreateConstraint = true;
        rel.IsNested = true;
        relations.Add (rel);
      }

      // If the element is not referenced one, the element will be handled later.
      if (el.RefName == XmlQualifiedName.Empty)
        ProcessDataTableElement (el);

    }

    private bool DataSetDefinesKey (string name)
    {
      foreach (ConstraintStructure c in reservedConstraints.Values)
        if (c.TableName == name && (c.IsPrimaryKey || c.IsNested))
          return true;
      return false;
    }

    private void AddParentKeyColumn (XmlSchemaElement parent, XmlSchemaElement el, DataColumn col)
    {
      // check existing primary key
      if (currentTable.Table.PrimaryKey.Length > 0)
        throw new DataException (String.Format ("There is already primary key columns in the table \"{0}\".", currentTable.Table.TableName));

      if (currentTable.PrimaryKey != null) {
        // fill pk column info and return
        col.ColumnName = currentTable.PrimaryKey.ColumnName;
        col.ColumnMapping = currentTable.PrimaryKey.ColumnMapping;
        col.Namespace = currentTable.PrimaryKey.Namespace;
        col.DataType = currentTable.PrimaryKey.DataType;
        col.AutoIncrement = currentTable.PrimaryKey.AutoIncrement;
        col.AllowDBNull = currentTable.PrimaryKey.AllowDBNull;
        
        ImportColumnMetaInfo (el, el.QualifiedName, col);
        return;
      }

      // check name identity
      string name = XmlHelper.Decode (parent.QualifiedName.Name) + "_Id";
      int count = 0;
      while (currentTable.ContainsColumn (name))
        name = String.Format ("{0}_{1}", name, count++);

      col.ColumnName = name;
      col.ColumnMapping = MappingType.Hidden;
      col.Namespace = parent.QualifiedName.Namespace;
      col.DataType = typeof (int);
      col.AutoIncrement = true;
      col.AllowDBNull = false;
      ImportColumnMetaInfo (el, el.QualifiedName, col);
      
      AddColumn (col);
      currentTable.PrimaryKey = col;
    }

    private void FillDataColumnRepeatedSimpleElement (XmlSchemaElement parent, XmlSchemaElement el, DataColumn col)
    {
      if (targetElements.Contains (el))
        return; // do nothing

      AddParentKeyColumn (parent, el, col);
      DataColumn pkey = currentTable.PrimaryKey;

      string elName = XmlHelper.Decode (el.QualifiedName.Name);
      string parentName = XmlHelper.Decode (parent.QualifiedName.Name);

      DataTable dt = new DataTable ();
      dt.TableName = elName;
      dt.Namespace = el.QualifiedName.Namespace;
      // reference key column to parent
      DataColumn cc = new DataColumn ();
      cc.ColumnName = parentName + "_Id";
      cc.Namespace = parent.QualifiedName.Namespace;
      cc.ColumnMapping = MappingType.Hidden;
      cc.DataType = typeof (int);

      // repeatable content simple element
      DataColumn cc2 = new DataColumn ();
      cc2.ColumnName = elName + "_Column";
      cc2.Namespace = el.QualifiedName.Namespace;
      cc2.ColumnMapping = MappingType.SimpleContent;
      cc2.AllowDBNull = false;
#if NET_2_0
      cc2.DataType = ConvertDatatype (GetSchemaPrimitiveType (el.ElementSchemaType));
#else
      cc2.DataType = ConvertDatatype (GetSchemaPrimitiveType (el.ElementType));
#endif

      dt.Columns.Add (cc2);
      dt.Columns.Add (cc);
      dataset.Tables.Add (dt);

      RelationStructure rel = new RelationStructure ();
      rel.ParentTableName = parentName;
      rel.ChildTableName = dt.TableName;
      rel.ParentColumnName = pkey.ColumnName;
      rel.ChildColumnName = cc.ColumnName;
      rel.IsNested = true;
      rel.CreateConstraint = true;
      relations.Add (rel);
    }

    private void FillDataColumnSimpleElement (XmlSchemaElement el, DataColumn col)
    {
      col.ColumnName = XmlHelper.Decode (el.QualifiedName.Name);
      col.Namespace = el.QualifiedName.Namespace;
      col.ColumnMapping = MappingType.Element;
#if NET_2_0
      col.DataType = ConvertDatatype (GetSchemaPrimitiveType (el.ElementSchemaType));
      FillFacet (col, el.ElementSchemaType as XmlSchemaSimpleType);
#else
      col.DataType = ConvertDatatype (GetSchemaPrimitiveType (el.ElementType));
      FillFacet (col, el.ElementType as XmlSchemaSimpleType);
#endif

      ImportColumnMetaInfo (el, el.QualifiedName, col);

      AddColumn (col);
    }

    private void AddColumn (DataColumn col)
    {
      if (col.Ordinal < 0)
        currentTable.NonOrdinalColumns.Add (col);
      else
        currentTable.OrdinalColumns.Add (col, col.Ordinal);
    }

    private void FillFacet (DataColumn col, XmlSchemaSimpleType st)
    {
      if (st == null || st.Content == null)
        return;

      // Handle restriction facets

      XmlSchemaSimpleTypeRestriction restriction = st == null ? null : st.Content as XmlSchemaSimpleTypeRestriction;
      if (restriction == null)
        throw new DataException ("DataSet does not suport 'list' nor 'union' simple type.");

      foreach (XmlSchemaFacet f in restriction.Facets) {
        if (f is XmlSchemaMaxLengthFacet)
          // There is no reason why MaxLength is limited to int, except for the fact that DataColumn.MaxLength property is int.
          col.MaxLength = int.Parse (f.Value);
      }
    }

    private Type ConvertDatatype (XmlSchemaDatatype dt)
    {
      if (dt == null)
        return typeof (string);
      else if (dt.ValueType == typeof (decimal)) {
        // LAMESPEC: MSDN documentation says it is based 
        // on ValueType. However, in the System.Xml.Schema
        // context, xs:integer is mapped to Decimal, while
        // in DataSet context it is mapped to Int64.
        if (dt == schemaDecimalType)
          return typeof (decimal);
        else if (dt == schemaIntegerType)
          return typeof (long);
        else
          return typeof (ulong);
      }
      else
        return dt.ValueType;
    }

    // This method cuts out the local name of the last step from XPath.
    // It is nothing more than hack. However, MS looks to do similar.
    private string GetSelectorTarget (string xpath)
    {
      string tableName = xpath;
      int index = tableName.LastIndexOf ('/');
      // '>' is enough. If XPath [0] = '/', it is invalid. 
      // Selector can specify only element axes.
      if (index > 0)
        tableName = tableName.Substring (index + 1);

      // Round QName to NSName
      index = tableName.LastIndexOf (':');
      if (index > 0)
        tableName = tableName.Substring (index + 1);

      return XmlHelper.Decode (tableName);
    }

    private void ReserveSelfIdentity (XmlSchemaIdentityConstraint ic)
    {
      string tableName = GetSelectorTarget (ic.Selector.XPath);

      string [] cols = new string [ic.Fields.Count];
      bool [] isAttrSpec = new bool [cols.Length];

      int i = 0;
      foreach (XmlSchemaXPath Field in ic.Fields) {
        string colName = Field.XPath;
        bool isAttr = colName.Length > 0 && colName [0] == '@';
        int index = colName.LastIndexOf (':');
        if (index > 0)
          colName = colName.Substring (index + 1);
        else if (isAttr)
          colName = colName.Substring (1);

        colName = XmlHelper.Decode (colName);
        cols [i] = colName;
        isAttrSpec [i] = isAttr;
        i++;
      }
      
      bool isPK = false;
      // find if there is an attribute with the constraint name
      // if not use the XmlSchemaConstraint's name.
      string constraintName = ic.Name;
      if (ic.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in ic.UnhandledAttributes) {
          if (attr.NamespaceURI != XmlConstants.MsdataNamespace)
            continue;
          switch (attr.LocalName) {
          case XmlConstants.ConstraintName:
            constraintName = attr.Value;
            break;
          case XmlConstants.PrimaryKey:
            isPK = bool.Parse(attr.Value);
            break;
          }
        }
      }
      reservedConstraints.Add (ic,
        new ConstraintStructure (tableName, cols,
          isAttrSpec, constraintName, isPK, null, false, false));
    }

    private void ProcessSelfIdentity (ConstraintStructure c)
    {
      // Basic concept came from XmlSchemaMapper.cs

      string tableName = c.TableName;
      
      DataTable dt = dataset.Tables [tableName];
      if (dt == null) {
        if (forDataSet)
          throw new DataException (String.Format ("Invalid XPath selection inside selector. Cannot find: {0}", tableName));
        else
          // nonexistent table name. .NET ignores it for DataTable.ReadXmlSchema().
          return;
      }

      DataColumn [] cols = new DataColumn [c.Columns.Length];
      for (int i = 0; i < cols.Length; i++) {
        string colName = c.Columns [i];
        bool isAttr = c.IsAttribute [i];
        DataColumn col = dt.Columns [colName];
        if (col == null)
          throw new DataException (String.Format ("Invalid XPath selection inside field. Cannot find: {0}", tableName));
        if (isAttr && col.ColumnMapping != MappingType.Attribute)
          throw new DataException ("The XPath specified attribute field, but mapping type is not attribute.");
        if (!isAttr && col.ColumnMapping != MappingType.Element)
          throw new DataException ("The XPath specified simple element field, but mapping type is not simple element.");

        cols [i] = dt.Columns [colName];
      }
      
      bool isPK = c.IsPrimaryKey;
      string constraintName = c.ConstraintName;
      dt.Constraints.Add (new UniqueConstraint (
        constraintName, cols, isPK));
    }

    private void ReserveRelationIdentity (XmlSchemaElement element, XmlSchemaKeyref keyref)
    {
      // Basic concept came from XmlSchemaMapper.cs

      string tableName = GetSelectorTarget (keyref.Selector.XPath);

      string [] cols = new string [keyref.Fields.Count];
      bool [] isAttrSpec = new bool [cols.Length];
      int i = 0;
      foreach (XmlSchemaXPath Field in keyref.Fields) {
        string colName = Field.XPath;
        bool isAttr = colName.Length > 0 && colName [0] == '@';
        int index = colName.LastIndexOf (':');
        if (index > 0)
          colName = colName.Substring (index + 1);
        else if (isAttr)
          colName = colName.Substring (1);

        colName = XmlHelper.Decode (colName);
        cols [i] = colName;
        isAttrSpec [i] = isAttr;
        i++;
      }
      string constraintName = keyref.Name;
      bool isNested = false;
      bool isConstraintOnly = false;
      if (keyref.UnhandledAttributes != null) {
        foreach (XmlAttribute attr in keyref.UnhandledAttributes) {
          if (attr.NamespaceURI != XmlConstants.MsdataNamespace)
            continue;
          switch (attr.LocalName) {
          case XmlConstants.ConstraintName:
            constraintName = attr.Value;
            break;
          case XmlConstants.IsNested:
            if (attr.Value == "true")
              isNested = true;
            break;
          case XmlConstants.ConstraintOnly:
            if (attr.Value == "true")
              isConstraintOnly = true;
            break;
          }
        }
      }

      reservedConstraints.Add (keyref, new ConstraintStructure (
        tableName, cols, isAttrSpec, constraintName,
        false, keyref.Refer.Name, isNested, isConstraintOnly));
    }

    private void ProcessRelationIdentity (XmlSchemaElement element, ConstraintStructure c)
    {
      // Basic concept came from XmlSchemaMapper.cs

      string tableName = c.TableName;

      DataColumn [] cols;
      DataTable dt = dataset.Tables [tableName];
      if (dt == null)
        throw new DataException (String.Format ("Invalid XPath selection inside selector. Cannot find: {0}", tableName));

      cols = new DataColumn [c.Columns.Length];
      for (int i = 0; i < cols.Length; i++) {
        string colName = c.Columns [i];
        bool isAttr = c.IsAttribute [i];
        DataColumn col = dt.Columns [colName];
        if (isAttr && col.ColumnMapping != MappingType.Attribute)
          throw new DataException ("The XPath specified attribute field, but mapping type is not attribute.");
        if (!isAttr && col.ColumnMapping != MappingType.Element)
          throw new DataException ("The XPath specified simple element field, but mapping type is not simple element.");
        cols [i] = col;
      }
      string name = c.ReferName;
      // get the unique constraint for the releation
      UniqueConstraint uniq = FindConstraint (name, element);
      // generate the FK.
      ForeignKeyConstraint fkc = new ForeignKeyConstraint(c.ConstraintName, uniq.Columns, cols);
      dt.Constraints.Add (fkc);

      if (!c.IsConstraintOnly) {
        // generate the relation.
        DataRelation rel = new DataRelation (c.ConstraintName, uniq.Columns, cols, true);
        rel.Nested = c.IsNested;
        rel.SetParentKeyConstraint (uniq);
        rel.SetChildKeyConstraint (fkc);

        dataset.Relations.Add (rel);
      }
    }

    // get the unique constraint for the relation.
    // name - the name of the XmlSchemaUnique element
    private UniqueConstraint FindConstraint (string name, XmlSchemaElement element)
    {
      // Copied from XmlSchemaMapper.cs

      // find the element in the constraint collection.
      foreach (XmlSchemaIdentityConstraint c in element.Constraints) {
        if (c is XmlSchemaKeyref)
          continue;

        if (c.Name == name) {
          string tableName = GetSelectorTarget (c.Selector.XPath);

          // find the table in the dataset.
          DataTable dt = dataset.Tables [tableName];

          string constraintName = c.Name;
          // find if there is an attribute with the constraint name
          // if not use the XmlSchemaUnique name.
          if (c.UnhandledAttributes != null)
            foreach (XmlAttribute attr in c.UnhandledAttributes)
              if (attr.LocalName == "ConstraintName" && attr.NamespaceURI == XmlConstants.MsdataNamespace)
                constraintName = attr.Value;
          return (UniqueConstraint) dt.Constraints [constraintName];
        }
      }
      throw new DataException ("Target identity constraint was not found: " + name);
    }

    private void HandleAnnotations (XmlSchemaAnnotation an, bool nested)
    {
      foreach (XmlSchemaObject content in an.Items) {
        XmlSchemaAppInfo ai = content as XmlSchemaAppInfo;
        if (ai != null) {
          foreach (XmlNode n in ai.Markup) {
            XmlElement el = n as XmlElement;
            
            // #325464 debugging
            //Console.WriteLine ("Name: " + el.LocalName + " NS: " + el.NamespaceURI + " Const: " + XmlConstants.MsdataNamespace);
            if (el != null && el.LocalName == "Relationship" && el.NamespaceURI == XmlConstants.MsdataNamespace)
              HandleRelationshipAnnotation (el, nested);
#if NET_2_0
            if (el != null && el.LocalName == "DataSource" && el.NamespaceURI == XmlConstants.MsdatasourceNamespace)
              HandleDataSourceAnnotation (el, nested);
#endif
          }
        }
      }
    }

#if NET_2_0
    private void HandleDataSourceAnnotation (XmlElement el, bool nested)
    {
      // Handle: Connections and Tables
      // For Tables: extract the provider information from connection and use
      // the corresponding providerfactory to create the adapter and et al objects 
      // and populate them
      
      // #325464 debugging
      //Console.WriteLine ("In HandleDataSourceAnnotation... ");
      string providerName = null;
      string connString = null;
      DbProviderFactory provider = null;
      XmlElement e, tablesElement = null, firstChild;
      
      foreach (XmlNode n in el.ChildNodes) {
        e = n as XmlElement;
        
        if (e == null)
          continue;
        
#if !MONOTOUCH
        if (e.LocalName == "Connections" && (firstChild = e.FirstChild as XmlElement) != null) {
          providerName = firstChild.GetAttribute ("Provider");
          connString = firstChild.GetAttribute ("AppSettingsPropertyName");
          provider = DbProviderFactories.GetFactory (providerName);
          continue;
        }
#endif // !MONOTOUCH
        // #325464 debugging
        //Console.WriteLine ("ProviderName: " + providerName + "Connstr: " + connString);
        
        if (e.LocalName == "Tables")
          tablesElement = e;
      }
        
      if (tablesElement != null && provider != null) {
        foreach (XmlNode node in tablesElement.ChildNodes) {
          ProcessTableAdapter (node as XmlElement, provider, connString);
        }
      }
    }
    
    private void ProcessTableAdapter (XmlElement el, DbProviderFactory provider, string connStr)
    {
      XmlElement e;
      string datasetTableName = null;
      
      if (el == null)
        return;
      
      // #325464 debugging
      //Console.WriteLine ("in ProcessTableAdapters...");
      currentAdapter = new TableAdapterSchemaInfo (provider); 
      currentAdapter.ConnectionString = connStr;
      
      //Console.WriteLine ("Provider: {0}, connection: {1}, adapter: {2}", 
      //                   provider, currentAdapter.Connection, currentAdapter.Adapter);
      currentAdapter.BaseClass = el.GetAttribute ("BaseClass");
      datasetTableName = el.GetAttribute ("Name");
      currentAdapter.Name = el.GetAttribute ("GeneratorDataComponentClassName");
      
      if (String.IsNullOrEmpty (currentAdapter.Name))
        currentAdapter.Name = el.GetAttribute ("DataAccessorName");

      //Console.WriteLine ("Name: "+currentAdapter.Name);
      foreach (XmlNode n in el.ChildNodes) {
        e = n as XmlElement;
        
        //Console.WriteLine ("Children of Tables: "+e.LocalName);
        if (e == null)
          continue;
        
        switch (e.LocalName) {
          case "MainSource": 
          case "Sources": 
            foreach (XmlNode msn in e.ChildNodes)
              ProcessDbSource (msn as XmlElement);
            break;
          
          case "Mappings":
            DataTableMapping tableMapping = new DataTableMapping ();
            tableMapping.SourceTable = "Table";
            tableMapping.DataSetTable = datasetTableName;
            
            foreach (XmlNode mps in e.ChildNodes)
              ProcessColumnMapping (mps as XmlElement, tableMapping);
            
            currentAdapter.Adapter.TableMappings.Add (tableMapping);
            break;            
        }
      }
    }
    
    private void ProcessDbSource (XmlElement el)
    {
      
      string cmdType;
      string tmp = null;
      XmlElement e;
      
      if (el == null)
        return;
      
      //Console.WriteLine ("ProcessDbSources: "+el.LocalName);

      tmp = el.GetAttribute ("GenerateShortCommands");
      //Console.WriteLine ("GenerateShortCommands: {0}", tmp);
      if (!String.IsNullOrEmpty (tmp))
        currentAdapter.ShortCommands = Convert.ToBoolean (tmp);
    
      DbCommandInfo cmdInfo = new DbCommandInfo ();
      tmp = el.GetAttribute ("GenerateMethods");
      if (!String.IsNullOrEmpty (tmp)) {
        DbSourceMethodInfo mthdInfo = null;
        
        switch ((GenerateMethodsType) Enum.Parse (typeof (GenerateMethodsType), tmp)) {
        case GenerateMethodsType.Get:
          mthdInfo = new DbSourceMethodInfo ();
          mthdInfo.Name = el.GetAttribute ("GetMethodName");
          mthdInfo.Modifier = el.GetAttribute ("GetMethodModifier");
          if (String.IsNullOrEmpty (mthdInfo.Modifier))
            mthdInfo.Modifier = "Public";
          mthdInfo.ScalarCallRetval = el.GetAttribute ("ScalarCallRetval");
          mthdInfo.QueryType = el.GetAttribute ("QueryType");
          mthdInfo.MethodType = GenerateMethodsType.Get;
          cmdInfo.Methods = new DbSourceMethodInfo [1];
          cmdInfo.Methods[0] = mthdInfo;
          break;
          
        case GenerateMethodsType.Fill:
          mthdInfo = new DbSourceMethodInfo ();
          mthdInfo.Name = el.GetAttribute ("FillMethodName");
          mthdInfo.Modifier = el.GetAttribute ("FillMethodModifier");
          if (String.IsNullOrEmpty (mthdInfo.Modifier))
            mthdInfo.Modifier = "Public";
          mthdInfo.ScalarCallRetval = null;
          mthdInfo.QueryType = null;
          mthdInfo.MethodType = GenerateMethodsType.Fill;
          cmdInfo.Methods = new DbSourceMethodInfo [1];
          cmdInfo.Methods[0] = mthdInfo;
          break;
          
        case GenerateMethodsType.Both:
          mthdInfo = new DbSourceMethodInfo ();
          // Get
          mthdInfo.Name = el.GetAttribute ("GetMethodName");
          mthdInfo.Modifier = el.GetAttribute ("GetMethodModifier");
          if (String.IsNullOrEmpty (mthdInfo.Modifier))
            mthdInfo.Modifier = "Public";
          mthdInfo.ScalarCallRetval = el.GetAttribute ("ScalarCallRetval");
          mthdInfo.QueryType = el.GetAttribute ("QueryType");
          mthdInfo.MethodType = GenerateMethodsType.Get;
          cmdInfo.Methods = new DbSourceMethodInfo [2];
          cmdInfo.Methods[0] = mthdInfo;
          
          // Fill
          mthdInfo = new DbSourceMethodInfo ();
          mthdInfo.Name = el.GetAttribute ("FillMethodName");
          mthdInfo.Modifier = el.GetAttribute ("FillMethodModifier");
          if (String.IsNullOrEmpty (mthdInfo.Modifier))
            mthdInfo.Modifier = "Public";
          mthdInfo.ScalarCallRetval = null;
          mthdInfo.QueryType = null;
          mthdInfo.MethodType = GenerateMethodsType.Fill;
          cmdInfo.Methods[1] = mthdInfo;
          break;
        }
      } else {
        // no Get or Fill methods - non <MainSource> sources
        DbSourceMethodInfo mthdInfo = new DbSourceMethodInfo ();
        mthdInfo.Name = el.GetAttribute ("Name");
        mthdInfo.Modifier = el.GetAttribute ("Modifier");
        if (String.IsNullOrEmpty (mthdInfo.Modifier))
          mthdInfo.Modifier = "Public";
        mthdInfo.ScalarCallRetval = el.GetAttribute ("ScalarCallRetval");
        mthdInfo.QueryType = el.GetAttribute ("QueryType");
        mthdInfo.MethodType = GenerateMethodsType.None;
        // Add MethodInfo to DbCommandInfo
        cmdInfo.Methods = new DbSourceMethodInfo [1];
        cmdInfo.Methods[0] = mthdInfo;
      }
      
      foreach (XmlNode n in el.ChildNodes) {
        e = n as XmlElement;
        
        if (e == null) 
          continue;
        
        switch (e.LocalName) {
          case "SelectCommand": 
            cmdInfo.Command = ProcessDbCommand (e.FirstChild as XmlElement);
            currentAdapter.Commands.Add (cmdInfo);
            break;
          case "InsertCommand": 
            currentAdapter.Adapter.InsertCommand = ProcessDbCommand (e.FirstChild as XmlElement);
            break;
          case "UpdateCommand": 
            currentAdapter.Adapter.UpdateCommand = ProcessDbCommand (e.FirstChild as XmlElement);
            break;
          case "DeleteCommand": 
            currentAdapter.Adapter.DeleteCommand = ProcessDbCommand (e.FirstChild as XmlElement);
            break;
        }
      }
    }
    
    private DbCommand ProcessDbCommand (XmlElement el)
    {
      XmlElement e;
      //Console.WriteLine (el.LocalName);
      string cmdText = null;
      string cmdType = null;
      ArrayList parameters = null;
      
      if (el == null)
        return null;
      
      cmdType = el.GetAttribute ("CommandType");
      foreach (XmlNode n in el.ChildNodes) {
        e = n as XmlElement;
        if (e != null && e.LocalName == "CommandText")
          cmdText = e.InnerText;
        else if (e != null && e.LocalName == "Parameters" && !e.IsEmpty)
          parameters = ProcessDbParameters (e);
      }
      
      DbCommand cmd = currentAdapter.Provider.CreateCommand ();
      cmd.CommandText = cmdText;
      if (cmdType == "StoredProcedure")
        cmd.CommandType = CommandType.StoredProcedure;
      else
        cmd.CommandType = CommandType.Text;

      if (parameters != null)
        cmd.Parameters.AddRange (parameters.ToArray ());
      
      //Console.WriteLine ("Parameters count: {0}", cmd.Parameters.Count);
      return cmd;
    }
    
    private ArrayList ProcessDbParameters (XmlElement el)
    {
      //Console.WriteLine ("ProcessDbParameters: "+el.LocalName);
      string tmp = null;
      XmlElement e;
      DbParameter param = null;
      ArrayList parameters = new ArrayList ();
      
      if (el == null)
        return parameters;
      
      foreach (XmlNode n in el.ChildNodes) {
        e = n as XmlElement;
        
        if (e == null)
          continue;
        param = currentAdapter.Provider.CreateParameter ();

        tmp = e.GetAttribute ("AllowDbNull");
        if (!String.IsNullOrEmpty (tmp))
          param.IsNullable = Convert.ToBoolean (tmp);
        
        param.ParameterName = e.GetAttribute ("ParameterName");
        tmp = e.GetAttribute ("ProviderType");
        if (!String.IsNullOrEmpty (tmp))
          tmp = e.GetAttribute ("DbType");
        param.FrameworkDbType = tmp;
        
        tmp = e.GetAttribute ("Direction");
        param.Direction = (ParameterDirection) Enum.Parse (typeof (ParameterDirection), tmp);
        
        ((IDbDataParameter)param).Precision = Convert.ToByte (e.GetAttribute ("Precision"));
        ((IDbDataParameter)param).Scale = Convert.ToByte (e.GetAttribute ("Scale"));
        param.Size = Convert.ToInt32 (e.GetAttribute ("Size"));
        param.SourceColumn = e.GetAttribute ("SourceColumn");
        
        tmp = e.GetAttribute ("SourceColumnNullMapping");
        if (!String.IsNullOrEmpty (tmp))
          param.SourceColumnNullMapping = Convert.ToBoolean (tmp);
        
        tmp = e.GetAttribute ("SourceVersion");
        param.SourceVersion = (DataRowVersion) Enum.Parse (typeof (DataRowVersion), tmp);        
        parameters.Add (param);
      }
      
      return parameters;
    }

    private void ProcessColumnMapping (XmlElement el, DataTableMapping tableMapping)
    {
      if (el == null)
        return;
      
      tableMapping.ColumnMappings.Add (el.GetAttribute ("SourceColumn"), 
                                       el.GetAttribute ("DataSetColumn"));
    }
    
#endif
    
    private void HandleRelationshipAnnotation (XmlElement el, bool nested)
    {
      string name = el.GetAttribute ("name");
      string ptn = el.GetAttribute ("parent", XmlConstants.MsdataNamespace);
      string ctn = el.GetAttribute ("child", XmlConstants.MsdataNamespace);
      string pkn = el.GetAttribute ("parentkey", XmlConstants.MsdataNamespace);
      string fkn = el.GetAttribute ("childkey", XmlConstants.MsdataNamespace);

      RelationStructure rel = new RelationStructure ();
      rel.ExplicitName = XmlHelper.Decode (name);
      rel.ParentTableName = XmlHelper.Decode (ptn);
      rel.ChildTableName = XmlHelper.Decode (ctn);
      // ColumnNames will be decoded wherever they are used as they can
      // contain 'space' separated list of column-names.
      rel.ParentColumnName = pkn;
      rel.ChildColumnName = fkn;
      rel.IsNested = nested;
      rel.CreateConstraint = false; // by default?
      relations.Add (rel);
    }

    private object GetElementDefaultValue (XmlSchemaElement elem)
    {
      // Unlike attribute, element cannot have a default value.
      if (elem.RefName == XmlQualifiedName.Empty)
        return elem.DefaultValue;
      XmlSchemaElement referenced = schema.Elements [elem.RefName] as XmlSchemaElement;
      if (referenced == null) // considering missing sub components
        return null;
      return referenced.DefaultValue;
    }

    private object GetAttributeDefaultValue (XmlSchemaAttribute attr)
    {
#if BUGGY_MS_COMPATIBLE
      if (attr == null)
        return null;
      else if (attr.RefName != XmlQualifiedName.Empty) {
        XmlSchemaAttribute referenced = schema.Attributes [attr.RefName] as XmlSchemaAttribute;
        if (referenced != null)
          return referenced.DefaultValue;
        else
          return null;
      }
      if (attr.DefaultValue != null)
        return attr.DefaultValue;
      return attr.FixedValue;
#else
      if (attr.DefaultValue != null)
        return attr.DefaultValue;
      else if (attr.FixedValue != null)
        return attr.FixedValue;
      else if (attr.RefName == XmlQualifiedName.Empty)
        return null;
      XmlSchemaAttribute referenced = schema.Attributes [attr.RefName] as XmlSchemaAttribute;
      if (referenced == null) // considering missing sub components
        return null;
      if (referenced.DefaultValue != null)
        return referenced.DefaultValue;
      return referenced.FixedValue;
#endif
    }
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.