/// <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> /// 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); }