/// <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;
                }
            }
        }
        /// <summary>
        /// Creates an array of values from a unique constraint that can be used for finding records.
        /// </summary>
        /// <param name="uniqueConstraintSchema">A description of a unique constraint.</param>
        /// <returns>An array of expressions that can be used as a key for finding records in a table.</returns>
        public CodeExpression[] CreateKey(UniqueConstraintSchema uniqueConstraintSchema)
        {
            // This will cycle through all the foreign and simple parameters looking for any columns that match up to the child
            // columns of the constraint.  When found, they are placed in the array in the proper order to match up against the
            // given unique constraint.
            List <CodeExpression> keys = new List <CodeExpression>();

            foreach (ColumnSchema uniqueColumn in uniqueConstraintSchema.Columns)
            {
                foreach (KeyValuePair <string, ExternalParameterItem> parameterPair in this.ExternalParameterItems)
                {
                    // This correlates the unique constraint columns with the variables that have been created in the method to
                    // hold the key values from the foreign tables.  These variables exist outside of the conditional logic that
                    // finds the parent row, so if the parent key is null, these values will also be null.  However, since they're
                    // still declared, they can be used to construct keys, which is useful when they're optional values.
                    if (parameterPair.Value is ForeignKeyConstraintParameterItem)
                    {
                        ForeignKeyConstraintParameterItem foreignKeyConstraintParameterItem = parameterPair.Value as ForeignKeyConstraintParameterItem;
                        ForeignKeyConstraintSchema        foreignKeyConstraintSchema        = foreignKeyConstraintParameterItem.ForeignKeyConstraintSchema;
                        for (int columnIndex = 0; columnIndex < foreignKeyConstraintSchema.Columns.Length; columnIndex++)
                        {
                            if (uniqueColumn == foreignKeyConstraintSchema.Columns[columnIndex])
                            {
                                foreach (ForeignKeyVariableItem foreignKeyVariableItem in foreignKeyConstraintParameterItem.ForeignKeyVariables)
                                {
                                    if (foreignKeyConstraintSchema.Columns[columnIndex] == foreignKeyVariableItem.ColumnSchema)
                                    {
                                        keys.Add(foreignKeyVariableItem.Expression);
                                    }
                                }
                            }
                        }
                    }

                    // This will match the columns described in the simple parameters to the columns in the unique constraint.
                    if (parameterPair.Value is SimpleParameterItem)
                    {
                        SimpleParameterItem simpleParameterItem = parameterPair.Value as SimpleParameterItem;
                        if (uniqueColumn == simpleParameterItem.ColumnSchema)
                        {
                            keys.Add(new CodeVariableReferenceExpression(CommonConversion.ToCamelCase(simpleParameterItem.ColumnSchema.Name)));
                        }
                    }
                }
            }

            // This array can be used as a key to find the record in a table.
            return(keys.ToArray());
        }
        /// <summary>
        /// The foreign constraints can only be evaluated after all the tables, keys and unique constraints have been evaluated.
        /// </summary>
        /// <param name="xmlSchema"></param>
        private void SecondPass(XmlSchemaSet xmlSchemaSet)
        {
            // This is the second pass through the schemas.  Once the tables, keys and unique constraints have been evaluated,
            // then the foreign constraints can be constructed and applied to the parent and child tables.
            foreach (XmlSchemaElement xmlSchemaElement in xmlSchemaSet.GlobalElements.Values)
            {
                // Only the Microsoft DataSet element is evaluated for foreign keys.
                if (ObjectSchema.IsDataSetElement(xmlSchemaElement))
                {
                    // This will examine each of the constraints looking for a foreign key description.
                    foreach (XmlSchemaIdentityConstraint xmlSchemaIdentityConstraint in xmlSchemaElement.Constraints)
                    {
                        // Evaluate the foreign keys in the data model.
                        if (xmlSchemaIdentityConstraint is XmlSchemaKeyref)
                        {
                            // This object can be used as a foreign key constraint and, optionally, can be used to describe a
                            // parent/child relationship.
                            XmlSchemaKeyref xmlSchemaKeyref = xmlSchemaIdentityConstraint as XmlSchemaKeyref;

                            // This creates a foreign key.
                            ForeignKeyConstraintSchema foreignKeyConstraintSchema = new ForeignKeyConstraintSchema(this, xmlSchemaIdentityConstraint as XmlSchemaKeyref);

                            // Foreign constraint schemas are always added to the list of constraints on a table.  They can also
                            // conditionally become the source for a relationship between two tables.
                            foreignKeyConstraintSchema.Table.Add(foreignKeyConstraintSchema);

                            // Unless specifically instructed to supress the relation, it will be created add added to both the
                            // parent and child tables as well as the data model.
                            XmlAttribute isConstraintOnlyAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaIdentityConstraint, QualifiedName.ConstraintOnly);
                            if (isConstraintOnlyAttribute == null || !Convert.ToBoolean(isConstraintOnlyAttribute.Value))
                            {
                                RelationSchema relationSchema = new RelationSchema(this, xmlSchemaKeyref);
                                relationSchema.ParentTable.ChildRelations.Add(relationSchema.Name, relationSchema);
                                relationSchema.ChildTable.ParentRelations.Add(relationSchema.Name, relationSchema);
                                this.Relations.Add(relationSchema.Name, relationSchema);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Creates the element that describes a foreign constraint.
        /// </summary>
        /// <param name="foreignConstraintSchema">A description of a foreign constraint.</param>
        /// <returns>An element that can be used in an XML Schema document to describe a foreign constraint.</returns>
        private static XElement CreateForeignKey(ForeignKeyConstraintSchema foreignKeyConstraintSchema)
        {
            //    <xs:keyref name="FK_Entity_AccessControl" refer="EntityKey" msprop:rel_Generator_UserRelationName="FK_Entity_AccessControl"
            //		msprop:rel_Generator_RelationVarName="relationFK_Entity_AccessControl" msprop:rel_Generator_UserChildTable="AccessControl"
            //		msprop:rel_Generator_UserParentTable="Entity" msprop:rel_Generator_ParentPropName="EntityRow"
            //		msprop:rel_Generator_ChildPropName="GetAccessControlRows">
            //      <xs:selector xpath=".//mstns:AccessControl" />
            //      <xs:field xpath="mstns:EntityId" />
            //    </xs:keyref>
            XElement foreignElement = new XElement(
                SchemaScrubber.xs + "keyref",
                new XAttribute("name", foreignKeyConstraintSchema.Name),
                new XAttribute("refer", foreignKeyConstraintSchema.RelatedTable.GetUniqueConstraint(foreignKeyConstraintSchema.RelatedColumns).Name),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_UserRelationName", foreignKeyConstraintSchema.Name),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_RelationVarName", String.Format("relation{0}", foreignKeyConstraintSchema.Name)),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_UserChildTable", foreignKeyConstraintSchema.Table.Name),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_UserParentTable", foreignKeyConstraintSchema.RelatedTable.Name),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_ParentPropName", String.Format("{0}Row", foreignKeyConstraintSchema.RelatedTable.Name)),
                new XAttribute(SchemaScrubber.msprop + "rel_Generator_ChildPropName", String.Format("Get{0}Rows", foreignKeyConstraintSchema.Table.Name)));

            foreignElement.Add(
                new XElement(
                    SchemaScrubber.xs + "selector",
                    new XAttribute("xpath", String.Format(".//mstns:{0}", foreignKeyConstraintSchema.Table.Name))));

            foreach (ColumnSchema columnSchema in foreignKeyConstraintSchema.Columns)
            {
                foreignElement.Add(
                    new XElement(
                        SchemaScrubber.xs + "field",
                        new XAttribute("xpath", String.Format("mstns:{0}", columnSchema.Name))));
            }

            // This describes a foreign constraint on a table.
            return(foreignElement);
        }