/// <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); }
public bool GetPrimaryKeyStatus(XmlSchemaIdentityConstraint xmlSchemaIdentityConstraint) { XmlAttribute xmlAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaIdentityConstraint, QualifiedName.PrimaryKey); if (xmlAttribute != null) { return(Convert.ToBoolean(xmlAttribute.Value)); } return(false); }
/// <summary> /// Indicates whether the column is persisted in a data store. /// </summary> /// <param name="xmlSchemaElement">The XML Element.</param> /// <returns>true if the column should be stored in a persistent database.</returns> private bool GetPersistentIndicator(XmlSchemaElement xmlSchemaElement) { // Extract the persistence attribute of a column. XmlAttribute xmlAttribute = ObjectSchema.GetUnhandledAttribute(xmlSchemaElement, QualifiedName.IsPersistent); if (xmlAttribute != null) { return(Convert.ToBoolean(xmlAttribute.Value)); } // The default attribute is to generate a persistent table. return(true); }
/// <summary> /// Creates a collection of tables found in the schema. /// </summary> /// <param name="xmlSchema">The schema that describes the data model.</param> /// <returns>A list of TableSchema objects that describe the tables found in the data model schema.</returns> private void FirstPass(XmlSchemaSet xmlSchemaSet) { // Scan through the schema set looking for table elements. These can either be defined at the root element for a standard // schema or they can be found as choices of a special element describing a 'DataSet' for the Microsoft version of a // schema. foreach (XmlSchemaElement xmlSchemaElement in xmlSchemaSet.GlobalElements.Values) { // If the element read from the schema is the Microsoft DataSet element, then the tables are described as choices // associated with an implicit complex type on that element. if (ObjectSchema.IsDataSetElement(xmlSchemaElement)) { // The tables are described as an choices of an implicit (nested) complex type. if (xmlSchemaElement.SchemaType is XmlSchemaComplexType) { // The complex type describes the table. XmlSchemaComplexType xmlSchemaComplexType = xmlSchemaElement.SchemaType as XmlSchemaComplexType; // The data model is described as a set of one or more choices of tables. if (xmlSchemaComplexType.Particle is XmlSchemaChoice) { // The data model is described as a set of choices. Each choice represents a table. XmlSchemaChoice xmlSchemaChoice = xmlSchemaComplexType.Particle as XmlSchemaChoice; // Create a table for each of the choices described in the complex type. foreach (XmlSchemaObject choiceObject in xmlSchemaChoice.Items) { if (choiceObject is XmlSchemaElement) { XmlSchemaElement tableElement = choiceObject as XmlSchemaElement; this.tableList.Add(tableElement.Name, new TableSchema(this, tableElement)); } } } } // The constraints describe the columns that are unique for a table. foreach (XmlSchemaIdentityConstraint xmlSchemaIdentityConstraint in xmlSchemaElement.Constraints) { // This describes the columns that must be unique within a table. if (xmlSchemaIdentityConstraint is XmlSchemaUnique) { XmlSchemaUnique xmlSchemaUnique = xmlSchemaIdentityConstraint as XmlSchemaUnique; UniqueConstraintSchema uniqueConstraintSchema = new UniqueConstraintSchema(this, xmlSchemaUnique); uniqueConstraintSchema.Table.Add(uniqueConstraintSchema); } } } } }
/// <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> /// 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); }