Example #1
0
        /// <summary>
        /// Creates a CodeDOM namespace Teraque.DataModelGenerator contains the strongly typed DataSet.
        /// </summary>
        /// <param name="schema">The schema description of the strongly typed DataSet.</param>
        public Namespace(DataModelSchema dataModelSchema)
        {
            //namespace Teraque.DataModelGenerator
            //{
            this.Name = dataModelSchema.TargetNamespace;

            // The interface provides the contracts for this service.
            this.Types.Add(new TargetInterface.TargetInterface(dataModelSchema));

            // Types
            List <CodeTypeDeclaration> typeList = new List <CodeTypeDeclaration>();

            typeList.Add(new TenantTargetClass.TenantTargetClass(dataModelSchema));
            typeList.Add(new FieldCollectorClass.FieldCollectorClass(dataModelSchema));
            typeList.Add(new TargetClass.TargetClass(dataModelSchema));
            typeList.Add(new TransactionClass.TransactionClass(dataModelSchema));
            typeList.Add(new TransactionLogItemClass.TransactionLogItemClass(dataModelSchema));
            typeList.Sort(
                delegate(CodeTypeDeclaration firstDeclaration, CodeTypeDeclaration secondDeclaration)
                { return(firstDeclaration.Name.CompareTo(secondDeclaration.Name)); });
            foreach (CodeTypeDeclaration codeTypeDeclaration in typeList)
            {
                this.Types.Add(codeTypeDeclaration);
            }

            //}
        }
 /// <summary>
 /// Initializes a new instance of the CodeCreateTransactionStatement class.
 /// </summary>
 /// <param name="dataModelSchema">The data model schema.</param>
 /// <param name="transactionExpression">The name of the local variable to which the transaction is assigned.</param>
 public CodeCreateTransactionStatement(DataModelSchema dataModelSchema, CodeVariableReferenceExpression transactionExpression)
 {
     //                    DataModelTransaction o1881 = DataModel.CurrentTransaction;
     this.Type           = new CodeTypeReference(String.Format("{0}Transaction", dataModelSchema.Name));
     this.Name           = transactionExpression.VariableName;
     this.InitExpression = new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(dataModelSchema.Name), "CurrentTransaction");
 }
Example #3
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;
                }
            }
        }
Example #4
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);
        }
        /// <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);
        }
Example #6
0
        /// <summary>
        /// Creates a CodeDOM namespace Teraque.ClientGenerator contains the strongly typed DataSet.
        /// </summary>
        /// <param name="schema">The schema description of the strongly typed DataSet.</param>
        public Namespace(DataModelSchema dataModelSchema)
        {
            //namespace Teraque.ClientGenerator
            //{
            this.Name = dataModelSchema.TargetNamespace;

            // The target class.
            this.Types.Add(new Teraque.DataModelGenerator.TargetClass.TargetClass(dataModelSchema));

            //}
        }
Example #7
0
        /// <summary>
        /// Generate the code from the custom tool.
        /// </summary>
        /// <param name="wszInputFilePath">The name of the input file.</param>
        /// <param name="bstrInputFileContents">The contents of the input file.</param>
        /// <param name="wszDefaultNamespace">The namespace Teraque.ClientGenerator the generated code.</param>
        /// <param name="pbstrOutputFileContents">The generated code.</param>
        /// <param name="pbstrOutputFileContentSize">The buffer size of the generated code.</param>
        /// <param name="pGenerateProgress">An indication of the tools progress.</param>
        /// <returns>0 indicates the tool handled the command.</returns>
        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace,
                            IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            // Throw an execption if there is nothing to process.
            if (bstrInputFileContents == null)
            {
                throw new ArgumentNullException(bstrInputFileContents);
            }

            // This schema describes the data model that is to be generated.
            DataModelSchema dataModelSchema = new DataModelSchema(bstrInputFileContents);

            dataModelSchema.GeneratorType   = typeof(ClientGenerator);
            dataModelSchema.TargetNamespace = wszDefaultNamespace;

            // This is where all the work is done to translate the input schema into the CodeDOM for the data model and the CodeDOM
            // for the interface to that data model.
            CodeCompileUnit codeCompileUnit = new CodeCompileUnit();

            codeCompileUnit.Namespaces.Add(new Namespace(dataModelSchema));
            CodeNamespace emptyNamespace = new CodeNamespace();

            emptyNamespace.Types.Add(new TargetInterface.TargetInterface(dataModelSchema));
            emptyNamespace.Types.Add(new TargetClientClass.TargetClientClass(dataModelSchema));
            codeCompileUnit.Namespaces.Add(emptyNamespace);

            // If a handler was provided for the generation of the code, then call it with an update.
            if (pGenerateProgress != null)
            {
                pGenerateProgress.Progress(50, 100);
            }

            // This will generate the target source code in the language described by the CodeDOM provider.
            StringWriter stringWriter = new StringWriter();

            this.codeProvider.GenerateCodeFromCompileUnit(codeCompileUnit, stringWriter, this.codeGeneratorOptions);

            // If a handler was provided for the progress, then let it know that the task is complete.
            if (pGenerateProgress != null)
            {
                pGenerateProgress.Progress(100, 100);
            }

            // This will pack the generated buffer into an unmanaged block of memory that can be passed back to Visual Studio.
            byte[] generatedBuffer = System.Text.Encoding.UTF8.GetBytes(stringWriter.ToString());
            rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(generatedBuffer.Length);
            Marshal.Copy(generatedBuffer, 0, rgbOutputFileContents[0], generatedBuffer.Length);
            pcbOutput = (uint)generatedBuffer.Length;

            // At this point the code generation was a success.
            return(VSConstants.S_OK);
        }
        /// <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));
                }
            }
        }
        /// <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;
                }
            }
        }
Example #10
0
        /// <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);
        }
Example #11
0
 public ObjectSchema(DataModelSchema dataModelSchema, XmlSchemaObject xmlSchemaObject)
 {
     // Initialize the object.
     this.DataModelSchema = dataModelSchema;
     this.xmlSchemaObject = xmlSchemaObject;
 }
 /// <summary>
 /// Creates a statement method invocation that adds a record to an ADO transaction.
 /// </summary>
 /// <param name="transactionExpression">The MiddleTierContext used for the transaction.</param>
 /// <param name="columnSchema">The record that is held for the duration of the transaction.</param>
 public CodeAcquireRecordReaderLockExpression(CodeExpression transactionExpression, CodeExpression rowExpression, DataModelSchema dataModelSchema)
 {
     //            departmentRow.ObjectRow.AcquireReaderLock(middleTierTransaction.AdoResourceManager.Guid, Teraque.UnitTest.Server.DataModel.lockTimeout);
     this.Method = new CodeMethodReferenceExpression(rowExpression, "AcquireReaderLock");
     this.Parameters.Add(new CodePropertyReferenceExpression(transactionExpression, "TransactionId"));
     this.Parameters.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(String.Format("Tenant{0}", dataModelSchema.Name)), "lockTimeout"));
 }
Example #13
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);
        }
Example #14
0
 /// <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;
 }
Example #15
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:
                        inputFilePath = 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 (inputFilePath == null)
                {
                    throw new Exception("Usage: SchemaScrubber -i <InputFileName>");
                }
                inputFilePath = Environment.ExpandEnvironmentVariables(inputFilePath);

                // Expand the environment variables for the outpt file path.
                if (outputFileName == null)
                {
                    outputFileName = String.Format("{0}.cs", Path.GetFileNameWithoutExtension(inputFilePath));
                }
                outputFileName = Environment.ExpandEnvironmentVariables(outputFileName);

                // 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.
                StreamReader    streamReader    = new StreamReader(inputFilePath);
                DataModelSchema 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("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);
        }
        /// <summary>
        /// Generate the code from the inputs.
        /// </summary>
        /// <param name=\"inputFileName\">The name of the input file.</param>
        /// <param name=\"inputFileContent\">The contents of the input file.</param>
        /// <returns>A buffer containing the generated code.</returns>
        private static byte[] GenerateDdl(DataModelSchema dataModelSchema)
        {
            // The generated data is written to a memeory stream using a writer.
            MemoryStream memoryStream = new MemoryStream();
            StreamWriter streamWriter = new StreamWriter(memoryStream);

            // Generate the file header.
            streamWriter.WriteLine("/*******************************************************************************");
            streamWriter.WriteLine("*	<auto-generated>");
            streamWriter.WriteLine("*	This code was generated by a tool.");
            streamWriter.WriteLine("*	Runtime Version:1.0.0.0");
            streamWriter.WriteLine("*");
            streamWriter.WriteLine("*	Changes to this file may cause incorrect behavior and will be lost if");
            streamWriter.WriteLine("*	the code is regenerated.");
            streamWriter.WriteLine("*	</auto-generated>");
            streamWriter.WriteLine("*******************************************************************************/");
            streamWriter.WriteLine();
            streamWriter.WriteLine("/* Set the environment */");
            streamWriter.WriteLine("set nocount on");
            streamWriter.WriteLine("set quoted_identifier on");
            streamWriter.WriteLine();

            // If this is the first version, then generate the version control schema.
            if (dataModelSchema.Version == 0.0m)
            {
                GenerateVersionControl(streamWriter);
            }

            // The tables must be written out to the DDL file so that parent tables are written out before child tables.  As tables
            // are emitted into the DDL file, they are removed from the list.  This continues until the list of tables is empty.
            SortedList <string, TableSchema> tables = new SortedList <string, TableSchema>();

            foreach (KeyValuePair <string, TableSchema> keyValuePair in dataModelSchema.Tables)
            {
                if (keyValuePair.Value.IsPersistent)
                {
                    tables.Add(keyValuePair.Key, keyValuePair.Value);
                }
            }

            // Write the tables out such that the parent tables are written before the children to prevent forward reference errors
            // when creating the foreign indices.  As tables are emitted to the DDL, they are removed from the list until the list
            // is empty.
            while (tables.Count > 0)
            {
                foreach (KeyValuePair <string, TableSchema> tablePair in tables)
                {
                    // This table will be examined to see if it qualified to be emitted to the DDL.  All the parents must be
                    // emitted before the children to avoid having the generation of the foreign keys fail.
                    TableSchema tableSchema = tablePair.Value;

                    // This will search the tables to see if the current table has any parent dependancies that haven't been
                    // written yet.
                    bool isParentDefined = true;
                    foreach (KeyValuePair <string, RelationSchema> parentRelationPair in tableSchema.ParentRelations)
                    {
                        if (tables.ContainsKey(parentRelationPair.Value.ParentTable.Name))
                        {
                            isParentDefined = false;
                            break;
                        }
                    }

                    // If there are parent dependancies that have not yet been generated, then skip this table for now.
                    if (!isParentDefined)
                    {
                        continue;
                    }

                    // The table schema is removed from the list after it is written to the stream.
                    if (tableSchema.IsPersistent)
                    {
                        GenerateTable(streamWriter, tableSchema);
                    }
                    tables.Remove(tablePair.Key);
                    break;
                }
            }

            // This will flush all the generated code into an array of bytes that can be written back to a file.  The choice of a
            // byte array as a means of returning the generated data is intended to emulate the interface of the Visual Studio
            // tools.
            streamWriter.Flush();
            return(memoryStream.ToArray());
        }
        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).
                    switch (argument)
                    {
                    case "-i":
                        argumentState = ArgumentState.InputFileName;
                        continue;

                    case "-out":
                        argumentState = ArgumentState.OutputFileName;
                        continue;
                    }

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

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

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

                // Throw a usage message back at the user if no file name was given.
                if (inputFileName == null)
                {
                    throw new Exception("Usage: \"Database Generator\" -i <input file name> -out <DDL file>");
                }
                inputFileName = Environment.ExpandEnvironmentVariables(inputFileName);

                // If no output file name was specified, create one from the input file specification.
                if (outputFileName == null)
                {
                    outputFileName = String.Format("{0}.sql", Path.GetFileNameWithoutExtension(inputFileName));
                }
                outputFileName = Environment.ExpandEnvironmentVariables(outputFileName);

                // Read the schema into a string.  This emulates the way that the IDE would normally call a code generator.  Create
                // the MiddleTierSchema (like a Schema, but with extra helping functions and relations for this type of code generation).
                StreamReader streamReader = new StreamReader(inputFileName);
                // This will generate a buffer of source code from the input schema.
                DataModelSchema dataModelSchema = new DataModelSchema(streamReader.ReadToEnd());
                byte[]          buffer          = GenerateDdl(dataModelSchema);

                // Write the buffer to the specified output file.
                FileStream outputStream = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.Write);
                outputStream.Write(buffer, 0, buffer.Length);
                outputStream.SetLength(buffer.Length);
                outputStream.Close();
            }
            catch (Exception exception)
            {
                // Write the error to the console.
                Console.WriteLine(exception.Message);
            }

            return(0);
        }