// effects: Creates the base cell relation and view cell relations // for each cellquery/cell. Also generates the C-Side and S-side // basic constraints and stores them into cConstraints and // sConstraints. Stores them in cConstraints and sConstraints private void ConstructCellRelationsWithConstraints(BasicSchemaConstraints cConstraints, BasicSchemaConstraints sConstraints) { // Populate single cell constraints int cellNumber = 0; foreach (Cell cell in m_cells) { // We have to create the ViewCellRelation so that the // BasicCellRelations can be created. cell.CreateViewCellRelation(cellNumber); BasicCellRelation cCellRelation = cell.CQuery.BasicCellRelation; BasicCellRelation sCellRelation = cell.SQuery.BasicCellRelation; // Populate the constraints for the C relation and the S Relation PopulateBaseConstraints(cCellRelation, cConstraints); PopulateBaseConstraints(sCellRelation, sConstraints); cellNumber++; } // Populate two-cell constraints, i.e., inclusion foreach (Cell firstCell in m_cells) { foreach (Cell secondCell in m_cells) { if (Object.ReferenceEquals(firstCell, secondCell)) { // We do not want to set up self-inclusion constraints unnecessarily continue; } } } }
// effects: Performs the validation of the cells in this and returns // an error log of all the errors/warnings that were discovered internal ErrorLog Validate() { // Check for errors not checked by "C-implies-S principle" if (m_config.IsValidationEnabled) { if (PerformSingleCellChecks() == false) { return(m_errorLog); } } else //Note that Metadata loading guarantees that DISTINCT flag is not present { // when update views (and validation) is disabled if (CheckCellsWithDistinctFlag() == false) { return(m_errorLog); } } BasicSchemaConstraints cConstraints = new BasicSchemaConstraints(); BasicSchemaConstraints sConstraints = new BasicSchemaConstraints(); // Construct intermediate "view relations" and the basic cell // relations along with the basic constraints ConstructCellRelationsWithConstraints(cConstraints, sConstraints); if (m_config.IsVerboseTracing) { // Trace Basic constraints Trace.WriteLine(String.Empty); Trace.WriteLine("C-Level Basic Constraints"); Trace.WriteLine(cConstraints); Trace.WriteLine("S-Level Basic Constraints"); Trace.WriteLine(sConstraints); } // Propagate the constraints m_cViewConstraints = PropagateConstraints(cConstraints); m_sViewConstraints = PropagateConstraints(sConstraints); // Make some basic checks on the view and basic cell constraints CheckConstraintSanity(cConstraints, sConstraints, m_cViewConstraints, m_sViewConstraints); if (m_config.IsVerboseTracing) { // Trace View constraints Trace.WriteLine(String.Empty); Trace.WriteLine("C-Level View Constraints"); Trace.WriteLine(m_cViewConstraints); Trace.WriteLine("S-Level View Constraints"); Trace.WriteLine(m_sViewConstraints); } // Check for implication if (m_config.IsValidationEnabled) { CheckImplication(m_cViewConstraints, m_sViewConstraints); } return(m_errorLog); }
private static void CheckConstraintSanity(BasicSchemaConstraints cConstraints, BasicSchemaConstraints sConstraints, ViewSchemaConstraints cViewConstraints, ViewSchemaConstraints sViewConstraints) { Debug.Assert(cConstraints.KeyConstraints.Count() == cViewConstraints.KeyConstraints.Count(), "Mismatch in number of C basic and view key constraints"); Debug.Assert(sConstraints.KeyConstraints.Count() == sViewConstraints.KeyConstraints.Count(), "Mismatch in number of S basic and view key constraints"); }
// requires: this to correspond to a cell relation for an entityset (m_cellQuery.Extent) // effects: Adds any key constraints present in this to constraints private void PopulateKeyConstraintsForEntitySet(BasicSchemaConstraints constraints) { MemberPath prefix = new MemberPath(m_cellQuery.Extent); EntityType entityType = (EntityType)m_cellQuery.Extent.ElementType; // Get all the keys for the entity type and create the key constraints List<ExtentKey> keys = ExtentKey.GetKeysForEntityType(prefix, entityType); AddKeyConstraints(keys, constraints); }
// requires: this to correspond to a cell relation for an entityset (m_cellQuery.Extent) // effects: Adds any key constraints present in this to constraints private void PopulateKeyConstraintsForEntitySet(BasicSchemaConstraints constraints) { MemberPath prefix = new MemberPath(m_cellQuery.Extent); EntityType entityType = (EntityType)m_cellQuery.Extent.ElementType; // Get all the keys for the entity type and create the key constraints List <ExtentKey> keys = ExtentKey.GetKeysForEntityType(prefix, entityType); AddKeyConstraints(keys, constraints); }
// effects: Given keys for this relation, adds one key constraint for // each key present in keys private void AddKeyConstraints(IEnumerable <ExtentKey> keys, BasicSchemaConstraints constraints) { foreach (ExtentKey key in keys) { // If the key is being projected, only then do we add the key constraint List <MemberProjectedSlot> keySlots = MemberProjectedSlot.GetSlots(m_slots, key.KeyFields); if (keySlots != null) { BasicKeyConstraint keyConstraint = new BasicKeyConstraint(this, keySlots); constraints.Add(keyConstraint); } } }
// effects: Modifies constraints to contain the key constraints that // are present in this relation internal void PopulateKeyConstraints(BasicSchemaConstraints constraints) { Debug.Assert(this == m_cellQuery.BasicCellRelation, "Cellquery does not point to the correct BasicCellRelation?"); Debug.Assert(m_cellQuery.Extent is EntitySet || m_cellQuery.Extent is AssociationSet, "Top level extents handled is currently entityset or association set"); if (m_cellQuery.Extent is EntitySet) { PopulateKeyConstraintsForEntitySet(constraints); } else { PopulateKeyConstraintsForRelationshipSet(constraints); } }
// effects: Propagates baseConstraints derived from the cellrelations // to the corresponding viewCellRelations and returns the list of // propagated constraints private static ViewSchemaConstraints PropagateConstraints(BasicSchemaConstraints baseConstraints) { ViewSchemaConstraints propagatedConstraints = new ViewSchemaConstraints(); // Key constraint propagation foreach (BasicKeyConstraint keyConstraint in baseConstraints.KeyConstraints) { ViewKeyConstraint viewConstraint = keyConstraint.Propagate(); if (viewConstraint != null) { propagatedConstraints.Add(viewConstraint); } } return(propagatedConstraints); }
// requires: this to correspond to a cell relation for an association set (m_cellQuery.Extent) // effects: Adds any key constraints present in this relation in // constraints private void PopulateKeyConstraintsForRelationshipSet(BasicSchemaConstraints constraints) { AssociationSet relationshipSet = m_cellQuery.Extent as AssociationSet; // Gather all members of all keys // CHANGE_Microsoft_FEATURE_KEYS: assume that an Entity has exactly one key. Otherwise we // have to take a cross-product of all keys // Keep track of all the key members for the association in a set // so that if no end corresponds to a key, we use all the members // to form the key Set <MemberPath> associationKeyMembers = new Set <MemberPath>(MemberPath.EqualityComparer); bool hasAnEndThatFormsKey = false; // Determine the keys of each end. If the end forms a key, add it // as a key to the set foreach (AssociationSetEnd end in relationshipSet.AssociationSetEnds) { AssociationEndMember endMember = end.CorrespondingAssociationEndMember; MemberPath prefix = new MemberPath(relationshipSet, endMember); List <ExtentKey> keys = ExtentKey.GetKeysForEntityType(prefix, end.EntitySet.ElementType); Debug.Assert(keys.Count > 0, "No keys for entity?"); Debug.Assert(keys.Count == 1, "Currently, we only support primary keys"); if (MetadataHelper.DoesEndFormKey(relationshipSet, endMember)) { // This end has is a key end AddKeyConstraints(keys, constraints); hasAnEndThatFormsKey = true; } // Add the members of the (only) key to associationKey associationKeyMembers.AddRange(keys[0].KeyFields); } // If an end forms a key then that key implies the full key if (false == hasAnEndThatFormsKey) { // No end is a key -- take all the end members and make a key // based on that ExtentKey key = new ExtentKey(associationKeyMembers); ExtentKey[] keys = new ExtentKey[] { key }; AddKeyConstraints(keys, constraints); } }
// effects: Given keys for this relation, adds one key constraint for // each key present in keys private void AddKeyConstraints(IEnumerable<ExtentKey> keys, BasicSchemaConstraints constraints) { foreach (ExtentKey key in keys) { // If the key is being projected, only then do we add the key constraint List<MemberProjectedSlot> keySlots = MemberProjectedSlot.GetSlots(m_slots, key.KeyFields); if (keySlots != null) { BasicKeyConstraint keyConstraint = new BasicKeyConstraint(this, keySlots); constraints.Add(keyConstraint); } } }
// effects: Generates the single-cell key+domain constraints for // baseRelation and adds them to constraints private static void PopulateBaseConstraints(BasicCellRelation baseRelation, BasicSchemaConstraints constraints) { // Populate key constraints baseRelation.PopulateKeyConstraints(constraints); }
// requires: this to correspond to a cell relation for an association set (m_cellQuery.Extent) // effects: Adds any key constraints present in this relation in // constraints private void PopulateKeyConstraintsForRelationshipSet(BasicSchemaConstraints constraints) { AssociationSet relationshipSet = m_cellQuery.Extent as AssociationSet; // Gather all members of all keys // CHANGE_Microsoft_FEATURE_KEYS: assume that an Entity has exactly one key. Otherwise we // have to take a cross-product of all keys // Keep track of all the key members for the association in a set // so that if no end corresponds to a key, we use all the members // to form the key Set<MemberPath> associationKeyMembers = new Set<MemberPath>(MemberPath.EqualityComparer); bool hasAnEndThatFormsKey = false; // Determine the keys of each end. If the end forms a key, add it // as a key to the set foreach (AssociationSetEnd end in relationshipSet.AssociationSetEnds) { AssociationEndMember endMember = end.CorrespondingAssociationEndMember; MemberPath prefix = new MemberPath(relationshipSet, endMember); List<ExtentKey> keys = ExtentKey.GetKeysForEntityType(prefix, end.EntitySet.ElementType); Debug.Assert(keys.Count > 0, "No keys for entity?"); Debug.Assert(keys.Count == 1, "Currently, we only support primary keys"); if (MetadataHelper.DoesEndFormKey(relationshipSet, endMember)) { // This end has is a key end AddKeyConstraints(keys, constraints); hasAnEndThatFormsKey = true; } // Add the members of the (only) key to associationKey associationKeyMembers.AddRange(keys[0].KeyFields); } // If an end forms a key then that key implies the full key if (false == hasAnEndThatFormsKey) { // No end is a key -- take all the end members and make a key // based on that ExtentKey key = new ExtentKey(associationKeyMembers); ExtentKey[] keys = new ExtentKey[] { key }; AddKeyConstraints(keys, constraints); } }
// effects: Performs the validation of the cells in this and returns // an error log of all the errors/warnings that were discovered internal ErrorLog Validate() { // Check for errors not checked by "C-implies-S principle" if (m_config.IsValidationEnabled) { if (PerformSingleCellChecks() == false) { return m_errorLog; } } else //Note that Metadata loading guarantees that DISTINCT flag is not present { // when update views (and validation) is disabled if (CheckCellsWithDistinctFlag() == false) { return m_errorLog; } } BasicSchemaConstraints cConstraints = new BasicSchemaConstraints(); BasicSchemaConstraints sConstraints = new BasicSchemaConstraints(); // Construct intermediate "view relations" and the basic cell // relations along with the basic constraints ConstructCellRelationsWithConstraints(cConstraints, sConstraints); if (m_config.IsVerboseTracing) { // Trace Basic constraints Trace.WriteLine(String.Empty); Trace.WriteLine("C-Level Basic Constraints"); Trace.WriteLine(cConstraints); Trace.WriteLine("S-Level Basic Constraints"); Trace.WriteLine(sConstraints); } // Propagate the constraints m_cViewConstraints = PropagateConstraints(cConstraints); m_sViewConstraints = PropagateConstraints(sConstraints); // Make some basic checks on the view and basic cell constraints CheckConstraintSanity(cConstraints, sConstraints, m_cViewConstraints, m_sViewConstraints); if (m_config.IsVerboseTracing) { // Trace View constraints Trace.WriteLine(String.Empty); Trace.WriteLine("C-Level View Constraints"); Trace.WriteLine(m_cViewConstraints); Trace.WriteLine("S-Level View Constraints"); Trace.WriteLine(m_sViewConstraints); } // Check for implication if (m_config.IsValidationEnabled) { CheckImplication(m_cViewConstraints, m_sViewConstraints); } return m_errorLog; }
// effects: Propagates baseConstraints derived from the cellrelations // to the corresponding viewCellRelations and returns the list of // propagated constraints private static ViewSchemaConstraints PropagateConstraints(BasicSchemaConstraints baseConstraints) { ViewSchemaConstraints propagatedConstraints = new ViewSchemaConstraints(); // Key constraint propagation foreach (BasicKeyConstraint keyConstraint in baseConstraints.KeyConstraints) { ViewKeyConstraint viewConstraint = keyConstraint.Propagate(); if (viewConstraint != null) { propagatedConstraints.Add(viewConstraint); } } return propagatedConstraints; }