Exemple #1
0
        /// <summary>
        /// Create a foreign key constraint on two tables.
        /// </summary>
        /// <param name="dataModelSchema">The parent data model schema.</param>
        /// <param name="xmlSchemaKeyref">The XmlSchema object that describes the foreignn key relation.</param>
        public RelationSchema(DataModelSchema dataModelSchema, XmlSchemaKeyref xmlSchemaKeyref)
        {
            // Initialize the object.
            this.name = xmlSchemaKeyref.Name;

            // This will search through each of the tables looking for the parent and child components of the relation.
            foreach (KeyValuePair <string, TableSchema> keyValuePair in dataModelSchema.Tables)
            {
                ConstraintSchema constraintSchema;

                // This is the parent component of the relation.
                if (keyValuePair.Value.Constraints.TryGetValue(xmlSchemaKeyref.Refer.Name, out constraintSchema))
                {
                    UniqueConstraintSchema uniqueConstraintSchema = constraintSchema as UniqueConstraintSchema;
                    this.parentColumns       = uniqueConstraintSchema.Columns;
                    this.parentTable         = uniqueConstraintSchema.Table;
                    this.parentKeyConstraint = uniqueConstraintSchema;
                }

                // This is the child part of the relation.
                if (keyValuePair.Value.Constraints.TryGetValue(xmlSchemaKeyref.Name, out constraintSchema))
                {
                    ForeignKeyConstraintSchema foreignKeyConstraintSchema = constraintSchema as ForeignKeyConstraintSchema;
                    this.childTable         = foreignKeyConstraintSchema.Table;
                    this.childColumns       = foreignKeyConstraintSchema.Columns;
                    this.childKeyConstraint = foreignKeyConstraintSchema;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Create a foreign key constraint on two tables.
        /// </summary>
        /// <param name="dataModelSchema">The parent data model schema.</param>
        /// <param name="xmlSchemaKeyref">The XmlSchema object that describes the foreignn key relation.</param>
        public ForeignKeyConstraintSchema(DataModelSchema dataModelSchema, XmlSchemaKeyref xmlSchemaKeyref)
            : base(dataModelSchema, xmlSchemaKeyref)
        {
            // This will search through each of the tables looking for a key that matches the name of the reference.  Note that
            // there is no checking to make sure the 'Refer' key exists.  If it didn't exist, the XmlSchema would have caught it
            // and never have validated the schema.
            foreach (KeyValuePair <string, TableSchema> keyValuePair in dataModelSchema.Tables)
            {
                ConstraintSchema constraintSchema;
                if (keyValuePair.Value.Constraints.TryGetValue(xmlSchemaKeyref.Refer.Name, out constraintSchema))
                {
                    this.relatedTable   = constraintSchema.Table;
                    this.relatedColumns = constraintSchema.Columns;
                }
            }

            // Parse the cascading update rule out of the keyref specification.
            XmlAttribute updateRuleAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaKeyref, QualifiedName.UpdateRule);

            this.updateRule = updateRuleAttribute == null ? CascadeRules.Cascade : (CascadeRules)Enum.Parse(typeof(CascadeRules), updateRuleAttribute.Value);

            // Parse the cascading delete rule out of the keyref specification.
            XmlAttribute deleteRuleAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaKeyref, QualifiedName.DeleteRule);

            this.deleteRule = deleteRuleAttribute == null ? CascadeRules.Cascade : (CascadeRules)Enum.Parse(typeof(CascadeRules), deleteRuleAttribute.Value);
        }
Exemple #3
0
        /// <summary>
        /// Creates a constraint that forces a set of columns to be unique.
        /// </summary>
        /// <param name="dataModelSchema">The parent data model schema.</param>
        /// <param name="xmlSchemaUnique">The XmlSchema description of the constraint.</param>
        public UniqueConstraintSchema(DataModelSchema dataModelSchema, XmlSchemaUnique xmlSchemaUnique)
            : base(dataModelSchema, xmlSchemaUnique)
        {
            // This determines whether the constraint should be used as the primary key for a table.
            XmlAttribute xmlAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaUnique, QualifiedName.PrimaryKey);

            this.isPrimaryKey = xmlAttribute == null ? false : Convert.ToBoolean(xmlAttribute.Value);
        }
        /// <summary>
        /// Constructs a schema from the contents of an XML specification.
        /// </summary>
        /// <param name="fileContents">The contents of a file that specifies the schema in XML.</param>
        public AnnotationSchema(DataModelSchema dataModelSchema, XmlSchemaAnnotation xmlSchemaAnnotation)
            : base(dataModelSchema, xmlSchemaAnnotation)
        {
            this.itemList = new List <Object>();

            foreach (XmlSchemaObject xmlSchemaObject in xmlSchemaAnnotation.Items)
            {
                if (xmlSchemaObject is XmlSchemaAppInfo)
                {
                    this.itemList.Add(new AppInfoSchema(dataModelSchema, xmlSchemaObject as XmlSchemaAppInfo));
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Create a description of a constraint on a table.
        /// </summary>
        /// <param name="schema">The Schema of the entire data model.</param>
        /// <param name="xmlSchemaIdentityConstraint">The schema of a constraint.</param>
        public ConstraintSchema(DataModelSchema dataModelSchema, XmlSchemaIdentityConstraint xmlSchemaIdentityConstraint)
        {
            // Initialize the object.
            this.name = xmlSchemaIdentityConstraint.Name;

            // Pull apart the selector and construct a table name from the XPath specification.  Since we flatten out the
            // hierarchy of the XmlSchema, there is no need to navigate a tree of nodes.  Only the table name is important for the
            // selector and there are no namespaces to be sorted out.
            string[] selectorXPath = xmlSchemaIdentityConstraint.Selector.XPath.Split(':');
            string   tableName     = selectorXPath.Length == 1 ? selectorXPath[0] : selectorXPath[1];

            tableName  = tableName.Replace(".", string.Empty);
            tableName  = tableName.Replace("/", string.Empty);
            this.table = dataModelSchema.Tables[tableName];

            // The fields of the constraint are collected in this object.
            List <ColumnSchema> columnList = new List <ColumnSchema>();

            // The raw schema contains the qualified names of all the columns in this constraint.  The tables are defined before
            // the constraints are evaluated, so it's safe to reference the table and its columns while collecting the fields in
            // the constraint.
            foreach (XmlSchemaXPath xmlSchemaXPath in xmlSchemaIdentityConstraint.Fields)
            {
                // Pull apart the field and construct a qualified name from the XPath specification.  The qualified name can be used
                // to find the equivalent column in the selector's table.
                string[] fieldXPath = xmlSchemaXPath.XPath.Split(':');
                string   columnName = fieldXPath.Length == 1 ? fieldXPath[0] : fieldXPath[1];
                if (!this.table.Columns.ContainsKey(columnName))
                {
                    throw new Exception(string.Format("The column {0} doesn't belong to the table {1} in constraint {2}", columnName, this.table.Name, xmlSchemaIdentityConstraint.Name));
                }
                columnList.Add(this.table.Columns[columnName]);
            }

            // The list of fields is converted to an array of columns for the lifetime of this object.
            this.columns = columnList.ToArray();

            // This indicates that all of the elements of the constraint can be nulled.
            this.isNullable = true;
            foreach (ColumnSchema columnSchema in this.columns)
            {
                if (!columnSchema.IsNullable)
                {
                    this.isNullable = false;
                }
            }
        }
        /// <summary>
        /// Create a table schema from the XML Schema specification.
        /// </summary>
        /// <param name="dataModelSchema">The data model to which this table belongs.</param>
        /// <param name="xmlSchemaElement">The root of the XmlSchema element that describes the table.</param>
        public TableSchema(DataModelSchema dataModelSchema, XmlSchemaElement xmlSchemaElement)
            : base(dataModelSchema, xmlSchemaElement)
        {
            // Initialize the object.
            this.dataModelSchema    = dataModelSchema;
            this.isPersistent       = GetPersistentIndicator(xmlSchemaElement);
            this.name               = xmlSchemaElement.Name;
            this.columnList         = new SortedList <string, ColumnSchema>();
            this.constraintList     = new SortedList <string, ConstraintSchema>();
            this.childRelationList  = new SortedList <string, RelationSchema>();
            this.parentRelationList = new SortedList <string, RelationSchema>();

            // Every table has a row version column which tracks the history of changes to the row.
            ColumnSchema rowVersionSchema = new ColumnSchema(this, "RowVersion", typeof(long), false, true,
                                                             DBNull.Value, int.MaxValue);

            this.columnList.Add(rowVersionSchema.Name, rowVersionSchema);

            // Initialize the columns of the table.
            Initialize(xmlSchemaElement);
        }
Exemple #7
0
        /// <summary>
        /// Initializes the column from an XmlSchemaElement or XmlSchemaAttribute.
        /// </summary>
        /// <param name="xmlSchemaAnnotated">An XmlSchema object containing the attributes of the column.</param>
        private void Initialize(XmlSchemaAnnotated xmlSchemaAnnotated)
        {
            // Extract the column properties from an XmlSchemaElement.
            if (xmlSchemaAnnotated is XmlSchemaElement)
            {
                // This element is used to describe the column.
                XmlSchemaElement xmlSchemaElement = xmlSchemaAnnotated as XmlSchemaElement;

                // This information is taken directly from the known XmlSchema attributes.  The rest of the information about the
                // column needs to be extracted using unhandled attributes and element facets.
                this.name       = xmlSchemaElement.Name;
                this.isNullable = xmlSchemaElement.MinOccurs == 0.0m;

                // Extract the string that contains the type information from the 'DataType' custom attribute.  This is a
                // Microsoft extension to the XML Schema definition.
                XmlAttribute dataTypeAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaElement, QualifiedName.DataType);
                if (dataTypeAttribute != null)
                {
                    // The type information is stored as a string.  This will rip apart the string to get the type,
                    // assembly, version, etc. information that can be used to access the type through reflection.
                    string   typeName = dataTypeAttribute.Value;
                    string[] parts    = typeName.Split(',');

                    // There's no a lot of fancy parsing going on here.  If it doesn't match the expected format, then
                    // reject the type.
                    if (parts.Length != 5)
                    {
                        throw new Exception(string.Format("Can't analyze the data type found on line {0}, {1}", xmlSchemaElement.LineNumber, typeName));
                    }

                    // This will load the assembly into memory and use reflection to get the data type that was specified
                    // in the XML file as a string.
                    string   assemblyFullName = string.Format("{0},{1},{2},{3}", parts[1], parts[2], parts[3], parts[4]);
                    Assembly assembly         = Assembly.Load(assemblyFullName);
                    if (assembly == null)
                    {
                        throw new Exception(string.Format("Unable to load the type {0} from assembly {1}", parts[0], assemblyFullName));
                    }
                    this.dataType = assembly.GetType(parts[0]);
                    if (this.dataType == null)
                    {
                        throw new Exception(string.Format("Unable to load the type {0} from assembly {1}", parts[0], assemblyFullName));
                    }
                }
                else
                {
                    // This will extract the simple data type and the maximum field length from the facets associated with the element.
                    if (xmlSchemaElement.ElementSchemaType is XmlSchemaSimpleType)
                    {
                        XmlSchemaSimpleType xmlSchemaSimpleType = xmlSchemaElement.ElementSchemaType as XmlSchemaSimpleType;
                        this.dataType = xmlSchemaSimpleType.Datatype.ValueType;
                        if (xmlSchemaSimpleType.Content is XmlSchemaSimpleTypeRestriction)
                        {
                            XmlSchemaSimpleTypeRestriction xmlSchemaSimpleTypeRestriction = xmlSchemaSimpleType.Content as XmlSchemaSimpleTypeRestriction;
                            foreach (XmlSchemaFacet xmlSchemaFacet in xmlSchemaSimpleTypeRestriction.Facets)
                            {
                                if (xmlSchemaFacet is XmlSchemaMaxLengthFacet)
                                {
                                    XmlSchemaMaxLengthFacet xmlSchemaMaxLengthFacet = xmlSchemaFacet as XmlSchemaMaxLengthFacet;
                                    this.maximumLength = Convert.ToInt32(xmlSchemaMaxLengthFacet.Value);
                                }
                            }
                        }
                    }
                }

                // The defalt value can only be evaluated after the data type has been determined.  Otherwise, there's no way to
                // know to which data type the default value is converted.
                this.defaultValue = DataModelSchema.ConvertValue(this.dataType, xmlSchemaElement.DefaultValue);
            }

            // Extract the column properties from an Attribute.
            if (xmlSchemaAnnotated is XmlSchemaAttribute)
            {
                // This attribute describes the column.
                XmlSchemaAttribute xmlSchemaAttribute = xmlSchemaAnnotated as XmlSchemaAttribute;

                // This information is taken directly from the known XmlSchema attributes.  The rest of the information about the
                // column needs to be extracted using unhandled attributes and element facets.
                this.name         = xmlSchemaAttribute.Name;
                this.dataType     = xmlSchemaAttribute.AttributeSchemaType.Datatype.ValueType;
                this.defaultValue = DataModelSchema.ConvertValue(this.dataType, xmlSchemaAttribute.DefaultValue);
            }

            // Determine the IsEncryptedColumn property.
            XmlAttribute isColumnEncrytedAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaAnnotated,
                                                                                        QualifiedName.IsEncrypted);

            this.isEncrypted = isColumnEncrytedAttribute == null ? false : Convert.ToBoolean(isColumnEncrytedAttribute.Value);

            // Determine the IsIdentityColumn property.
            XmlAttribute autoIncrementAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaAnnotated,
                                                                                     QualifiedName.AutoIncrement);

            this.isAutoIncrement = autoIncrementAttribute == null ? false : Convert.ToBoolean(autoIncrementAttribute.Value);

            // Determine the IsPersistent property.
            XmlAttribute isColumnPersistentAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaAnnotated,
                                                                                          QualifiedName.IsPersistent);

            this.isPersistent = isColumnPersistentAttribute == null ? true : Convert.ToBoolean(isColumnPersistentAttribute.Value);

            // Determine the AutoIncrementSeed property.
            XmlAttribute autoIncrementSeedAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaAnnotated,
                                                                                         QualifiedName.AutoIncrementSeed);

            this.autoIncrementSeed = autoIncrementSeedAttribute == null ? 0 : Convert.ToInt32(autoIncrementSeedAttribute.Value);

            // Determine the AutoIncrementStop property
            XmlAttribute autoIncrementStepAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaAnnotated,
                                                                                         QualifiedName.AutoIncrementStep);

            this.autoIncrementStep = autoIncrementStepAttribute == null ? 0 : Convert.ToInt32(autoIncrementStepAttribute.Value);
        }
 /// <summary>
 /// Constructs a schema from the contents of an XML specification.
 /// </summary>
 /// <param name="fileContents">The contents of a file that specifies the schema in XML.</param>
 public AppInfoSchema(DataModelSchema dataModelSchema, XmlSchemaAppInfo xmlSchemaAppInfo)
     : base(dataModelSchema, xmlSchemaAppInfo)
 {
     this.source = xmlSchemaAppInfo.Source;
     this.markup = xmlSchemaAppInfo.Markup;
 }
Exemple #9
0
 public ObjectSchema(DataModelSchema dataModelSchema, XmlSchemaObject xmlSchemaObject)
 {
     // Initialize the object.
     this.DataModelSchema = dataModelSchema;
     this.xmlSchemaObject = xmlSchemaObject;
 }
Exemple #10
0
        static int Main(string[] args)
        {
            try
            {
                // The command line parser is driven by different states that are triggered by the flags read.  Unless a flag has
                // been read, the command line parser assumes that it's reading the file name from the command line.
                argumentState = ArgumentState.InputFileName;

                // Parse the command line for arguments.
                foreach (string argument in args)
                {
                    // Decode the current argument into a state change (or some other action).
                    if (argument == "-i")
                    {
                        argumentState = ArgumentState.InputFileName; continue;
                    }
                    if (argument == "-out")
                    {
                        argumentState = ArgumentState.OutputFileName; continue;
                    }

                    // The parsing state will determine which variable is read next.
                    switch (argumentState)
                    {
                    case ArgumentState.InputFileName:
                        inputFileName = argument;
                        break;

                    case ArgumentState.OutputFileName:
                        outputFileName = argument;
                        break;
                    }

                    // The default state is to look for the input file name on the command line.
                    argumentState = ArgumentState.InputFileName;
                }

                // Expand the environment variables for the input file path.
                if (inputFileName == null)
                {
                    throw new Exception("Usage: SchemaScrubber -i <InputFileName> -out <OutputFileName>");
                }
                inputFileName = Environment.ExpandEnvironmentVariables(inputFileName);

                // Expand the environment variables for the outpt file path.
                if (outputFileName == null)
                {
                    outputFileName = inputFileName;
                }

                // The main idea here is to emulate the interface that Visual Studio uses to generate a file.  The first step is to
                // read the schema from the input file into a string.  This emulates the way that the IDE would normally call a
                // code generator.  Then create a 'MiddleTierGenerator' to compile the schema.
                DataModelSchema dataModelSchema;
                using (StreamReader streamReader = new StreamReader(inputFileName))
                    dataModelSchema = new DataModelSchema(streamReader.ReadToEnd());

                // Regurgitate the schema as an XDocument
                XDocument xDocument     = new XDocument();
                XElement  schemaElement = new XElement(
                    SchemaScrubber.xs + "schema",
                    new XAttribute("id", dataModelSchema.Name),
                    new XAttribute("targetNamespace", dataModelSchema.TargetNamespace),
                    new XAttribute(XNamespace.Xmlns + "mstns", "http://tempuri.org/DataModel.xsd"),
                    new XAttribute("xmlns", "http://tempuri.org/DataModel.xsd"),
                    new XAttribute(XNamespace.Xmlns + "xs", "http://www.w3.org/2001/XMLSchema"),
                    new XAttribute(XNamespace.Xmlns + "msdata", "urn:schemas-microsoft-com:xml-msdata"),
                    new XAttribute(XNamespace.Xmlns + "msprop", "urn:schemas-microsoft-com:xml-msprop"),
                    new XAttribute(XNamespace.Xmlns + "tdata", "urn:schemas-teraque-com:xml-tdata"),
                    new XAttribute("attributeFormDefault", "qualified"),
                    new XAttribute("elementFormDefault", "qualified")
                    );


                // Emit Annotations
                foreach (ObjectSchema itemSchema0 in dataModelSchema.Items)
                {
                    if (itemSchema0 is AnnotationSchema)
                    {
                        AnnotationSchema annotationSchema  = itemSchema0 as AnnotationSchema;
                        XElement         annotationElement = new XElement(SchemaScrubber.xs + "annotation");
                        foreach (ObjectSchema itemSchema1 in annotationSchema.Items)
                        {
                            if (itemSchema1 is AppInfoSchema)
                            {
                                AppInfoSchema appInfoSchema  = itemSchema1 as AppInfoSchema;
                                XElement      appInfoElement = new XElement(SchemaScrubber.xs + "appinfo");
                                if (appInfoSchema.Source != String.Empty)
                                {
                                    appInfoElement.Add(new XAttribute("source", appInfoSchema.Source));
                                }
                                foreach (XmlNode xmlNode in appInfoSchema.Markup)
                                {
                                    appInfoElement.Add(XElement.Parse(xmlNode.OuterXml));
                                }
                                annotationElement.Add(appInfoElement);
                            }
                        }
                        schemaElement.Add(annotationElement);
                    }
                }

                // Data Model
                //   <xs:element name="DataModel" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="DataModel"
                //		msprop:Generator_DataSetName="DataModel" msprop:EnableTableAdapterManager="true">
                XElement dataModelElement = new XElement(
                    SchemaScrubber.xs + "element",
                    new XAttribute("name", dataModelSchema.Name),
                    new XAttribute(msdata + "IsDataSet", true),
                    new XAttribute(msdata + "UseCurrentLocale", true),
                    new XAttribute(SchemaScrubber.msprop + "Generator_UserDSName", dataModelSchema.Name),
                    new XAttribute(SchemaScrubber.msprop + "Generator_DataSetName", dataModelSchema.Name),
                    new XAttribute(SchemaScrubber.msprop + "EnableTableAdapterManager", true));

                //    <xs:complexType>
                XElement dataModelComlexTypeElement = new XElement(SchemaScrubber.xs + "complexType");

                //      <xs:choice minOccurs="0" maxOccurs="unbounded">
                XElement dataModelChoices = new XElement(
                    SchemaScrubber.xs + "choice",
                    new XAttribute("minOccurs", 0),
                    new XAttribute("maxOccurs", "unbounded"));

                // This will scrub and add each of the tables to the schema in alphabetical order.
                foreach (KeyValuePair <String, TableSchema> keyValuePair in dataModelSchema.Tables)
                {
                    dataModelChoices.Add(CreateTable(keyValuePair.Value));
                }

                // The complex types that define the tables.
                dataModelComlexTypeElement.Add(dataModelChoices);
                dataModelElement.Add(dataModelComlexTypeElement);

                // This will order the primary keys.
                List <UniqueConstraintSchema> primaryKeyList = new List <UniqueConstraintSchema>();
                foreach (KeyValuePair <String, TableSchema> keyValuePair in dataModelSchema.Tables)
                {
                    primaryKeyList.AddRange(keyValuePair.Value.UniqueConstraintSchemas);
                }
                primaryKeyList.Sort((first, second) => { return(first.Name.CompareTo(second.Name)); });
                foreach (UniqueConstraintSchema uniqueConstraintSchema in primaryKeyList)
                {
                    dataModelElement.Add(CreateUniqueKey(uniqueConstraintSchema));
                }

                // This will order the foreign primary keys.
                List <ForeignKeyConstraintSchema> foreignKeyList = new List <ForeignKeyConstraintSchema>();
                foreach (KeyValuePair <String, TableSchema> keyValuePair in dataModelSchema.Tables)
                {
                    foreignKeyList.AddRange(keyValuePair.Value.ForeignKeyConstraintSchemas);
                }
                foreignKeyList.Sort((first, second) => { return(first.Name.CompareTo(second.Name)); });
                foreach (ForeignKeyConstraintSchema foreignConstraintSchema in foreignKeyList)
                {
                    dataModelElement.Add(CreateForeignKey(foreignConstraintSchema));
                }

                // Add the data model element to the document.
                schemaElement.Add(dataModelElement);

                // Create the document from the root.
                xDocument.Add(schemaElement);

                // Save the regurgitated output.

                xDocument.Save(outputFileName);
            }
            catch (Exception exception)
            {
                // Dump any exceptions to the console.
                Console.WriteLine(exception.Message);
            }

            // At this point the code generated created the code-behind for the source schema successfully.
            return(0);
        }