internal void CreateVariableConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection) { CreateVariableConstraintsRecursion(extent.ElementType, new MemberPath(extent), domainMap, edmItemCollection); }
internal void CreateAssociationConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection) { var assocSet = extent as AssociationSet; if (assocSet != null) { var assocSetExpr = BoolExpression.CreateLiteral(new RoleBoolean(assocSet), domainMap); //Set of Keys for this Association Set //need to key on EdmMember and EdmType because A, B subtype of C, can have the same id (EdmMember) that is defined in C. var associationkeys = new HashSet <Pair <EdmMember, EntityType> >(); //foreach end, add each Key foreach (var endMember in assocSet.ElementType.AssociationEndMembers) { var type = (EntityType)((RefType)endMember.TypeUsage.EdmType).ElementType; type.KeyMembers.All( member => associationkeys.Add(new Pair <EdmMember, EntityType>(member, type)) || true /* prevent early termination */); } foreach (var end in assocSet.AssociationSetEnds) { // construct type condition var derivedTypes = new HashSet <EdmType>(); derivedTypes.UnionWith( MetadataHelper.GetTypeAndSubtypesOf( end.CorrespondingAssociationEndMember.TypeUsage.EdmType, edmItemCollection, false)); var typeCondition = CreateIsOfTypeCondition( new MemberPath(end.EntitySet), derivedTypes, domainMap); var inRoleExpression = BoolExpression.CreateLiteral(new RoleBoolean(end), domainMap); var inSetExpression = BoolExpression.CreateAnd( BoolExpression.CreateLiteral(new RoleBoolean(end.EntitySet), domainMap), typeCondition); // InRole -> (InSet AND type(Set)=T) AddImplication(inRoleExpression.Tree, inSetExpression.Tree); if (MetadataHelper.IsEveryOtherEndAtLeastOne(assocSet, end.CorrespondingAssociationEndMember)) { AddImplication(inSetExpression.Tree, inRoleExpression.Tree); } // Add equivalence between association set an End/Role if necessary. // Equivalence is added when a given association end's keys subsumes keys for // all the other association end. // For example: We have Entity Sets A[id1], B[id2, id3] and an association A_B between them. // Ref Constraint A.id1 = B.id2 // In this case, the Association Set has Key <id1, id2, id3> // id1 alone can not identify a unique tuple in the Association Set, but <id2, id3> can. // Therefore we add a constraint: InSet(B) <=> InEnd(A_B.B) if (MetadataHelper.DoesEndKeySubsumeAssociationSetKey( assocSet, end.CorrespondingAssociationEndMember, associationkeys)) { AddEquivalence(inRoleExpression.Tree, assocSetExpr.Tree); } } // add rules for referential constraints (borrowed from LeftCellWrapper.cs) var assocType = assocSet.ElementType; foreach (var constraint in assocType.ReferentialConstraints) { var toEndMember = (AssociationEndMember)constraint.ToRole; var toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember); // Check if the keys of the entitySet's are equal to what is specified in the constraint // How annoying that KeyMembers returns EdmMember and not EdmProperty var toProperties = Helpers.AsSuperTypeList <EdmProperty, EdmMember>(constraint.ToProperties); if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer <EdmMember> .Default)) { // Now check that the FromEnd is 1..1 (only then will all the Addresses be present in the assoc set) if (constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One)) { // Make sure that the ToEnd is not 0..* because then the schema is broken Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many) == false); // Equate the ends var inRoleExpression1 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[0]), domainMap); var inRoleExpression2 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[1]), domainMap); AddEquivalence(inRoleExpression1.Tree, inRoleExpression2.Tree); } } } } }
private void CreateVariableConstraintsRecursion( EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection) { // Add the types can member have, i.e., its type and its subtypes var possibleTypes = new HashSet <EdmType>(); possibleTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(edmType, edmItemCollection, true)); foreach (var possibleType in possibleTypes) { // determine type domain var derivedTypes = new HashSet <EdmType>(); derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(possibleType, edmItemCollection, false)); if (derivedTypes.Count != 0) { var typeCondition = CreateIsOfTypeCondition(currentPath, derivedTypes, domainMap); var typeConditionComplement = BoolExpression.CreateNot(typeCondition); if (false == typeConditionComplement.IsSatisfiable()) { continue; } var structuralType = (StructuralType)possibleType; foreach (var childProperty in structuralType.GetDeclaredOnlyMembers <EdmProperty>()) { var childPath = new MemberPath(currentPath, childProperty); var isScalar = MetadataHelper.IsNonRefSimpleMember(childProperty); if (domainMap.IsConditionMember(childPath) || domainMap.IsProjectedConditionMember(childPath)) { BoolExpression nullCondition; var childDomain = new List <Constant>(domainMap.GetDomain(childPath)); if (isScalar) { nullCondition = BoolExpression.CreateLiteral( new ScalarRestriction( new MemberProjectedSlot(childPath), new Domain(Constant.Undefined, childDomain)), domainMap); } else { nullCondition = BoolExpression.CreateLiteral( new TypeRestriction( new MemberProjectedSlot(childPath), new Domain(Constant.Undefined, childDomain)), domainMap); } // Properties not occuring in type are UNDEFINED AddEquivalence(typeConditionComplement.Tree, nullCondition.Tree); } // recurse into complex types if (false == isScalar) { CreateVariableConstraintsRecursion(childPath.EdmType, childPath, domainMap, edmItemCollection); } } } } }
internal void CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(AssociationSet assocSet, MemberDomainMap domainMap) { var assocType = assocSet.ElementType; foreach (var constraint in assocType.ReferentialConstraints) { var toEndMember = (AssociationEndMember)constraint.ToRole; var fromEndMember = (AssociationEndMember)constraint.FromRole; var toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember); var fromEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, fromEndMember); // Check if the keys of the entitySet's are equal to what is specified in the constraint var toProperties = Helpers.AsSuperTypeList <EdmProperty, EdmMember>(constraint.ToProperties); if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer <EdmMember> .Default)) { //make sure that the method called with a 1:1 association Debug.Assert(constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One)); Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One)); // Create an Equivalence between the two Sets participating in this AssociationSet var fromSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(fromEntitySet), domainMap); var toSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(toEntitySet), domainMap); AddEquivalence(fromSetExpression.Tree, toSetExpression.Tree); } } }
internal ViewgenContext(ViewTarget viewTarget, EntitySetBase extent, IEnumerable <Cell> extentCells, CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap, StorageEntityContainerMapping entityContainerMapping) { foreach (Cell cell in extentCells) { Debug.Assert(extent.Equals(cell.GetLeftQuery(viewTarget).Extent)); Debug.Assert(cell.CQuery.NumProjectedSlots == cell.SQuery.NumProjectedSlots); } m_extent = extent; m_viewTarget = viewTarget; m_config = config; m_edmItemCollection = entityContainerMapping.StorageMappingItemCollection.EdmItemCollection; m_entityContainerMapping = entityContainerMapping; m_identifiers = identifiers; // create a copy of updateDomainMap so generation of query views later on is not affected // it is modified in QueryRewriter.AdjustMemberDomainsForUpdateViews updateDomainMap = updateDomainMap.MakeCopy(); // Create a signature generator that handles all the // multiconstant work and generating the signatures MemberDomainMap domainMap = viewTarget == ViewTarget.QueryView ? queryDomainMap : updateDomainMap; m_memberMaps = new MemberMaps(viewTarget, MemberProjectionIndex.Create(extent, m_edmItemCollection), queryDomainMap, updateDomainMap); // Create left fragment KB: includes constraints for the extent to be constructed FragmentQueryKB leftKB = new FragmentQueryKB(); leftKB.CreateVariableConstraints(extent, domainMap, m_edmItemCollection); m_leftFragmentQP = new FragmentQueryProcessor(leftKB); m_rewritingCache = new Dictionary <FragmentQuery, Tile <FragmentQuery> >( FragmentQuery.GetEqualityComparer(m_leftFragmentQP)); // Now using the signatures, create new cells such that // "extent's" query (C or S) is described in terms of multiconstants if (!CreateLeftCellWrappers(extentCells, viewTarget)) { return; } // Create right fragment KB: includes constraints for all extents and association roles of right queries FragmentQueryKB rightKB = new FragmentQueryKB(); MemberDomainMap rightDomainMap = viewTarget == ViewTarget.QueryView ? updateDomainMap : queryDomainMap; foreach (LeftCellWrapper leftCellWrapper in m_cellWrappers) { EntitySetBase rightExtent = leftCellWrapper.RightExtent; rightKB.CreateVariableConstraints(rightExtent, rightDomainMap, m_edmItemCollection); rightKB.CreateAssociationConstraints(rightExtent, rightDomainMap, m_edmItemCollection); } if (m_viewTarget == ViewTarget.UpdateView) { CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper(rightKB, rightDomainMap); } m_rightFragmentQP = new FragmentQueryProcessor(rightKB); // Check for concurrency control tokens if (m_viewTarget == ViewTarget.QueryView) { CheckConcurrencyControlTokens(); } // For backward compatibility - // order wrappers by increasing domain size, decreasing number of attributes m_cellWrappers.Sort(LeftCellWrapper.Comparer); }
/// <summary> /// Find the Foreign Key Associations that relate EntitySets used in these left cell wrappers and /// add any equivalence facts between sets implied by 1:1 associations. /// We can collect other implication facts but we don't have a scenario that needs them( yet ). /// </summary> /// <param name="rightKB"></param> /// <param name="rightDomainMap"></param> private void CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper(FragmentQueryKB rightKB, MemberDomainMap rightDomainMap) { //First find the entity types of the sets in these cell wrappers. var entityTypes = m_cellWrappers.Select(it => it.RightExtent).OfType <EntitySet>().Select(it => it.ElementType); //Get all the foreign key association sets in these entity sets var allForeignKeyAssociationSets = this.m_entityContainerMapping.EdmEntityContainer.BaseEntitySets.OfType <AssociationSet>().Where(it => it.ElementType.IsForeignKey); //Find all the foreign key associations that have corresponding sets var oneToOneForeignKeyAssociationsForThisWrapper = allForeignKeyAssociationSets.Select(it => it.ElementType); //Find all the 1:1 associations from the above list oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where(it => (it.AssociationEndMembers.All(endMember => endMember.RelationshipMultiplicity == RelationshipMultiplicity.One))); //Filter the 1:1 foreign key associations to the ones relating the sets used in these cell wrappers. oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where(it => (it.AssociationEndMembers.All(endMember => entityTypes.Contains(endMember.GetEntityType())))); //filter foreign key association sets to the sets that are 1:1 and affecting this wrapper. var oneToOneForeignKeyAssociationSetsForThisWrapper = allForeignKeyAssociationSets.Where(it => oneToOneForeignKeyAssociationsForThisWrapper.Contains(it.ElementType)); //Collect the facts for the foreign key association sets that are 1:1 and affecting this wrapper foreach (var assocSet in oneToOneForeignKeyAssociationSetsForThisWrapper) { rightKB.CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(assocSet, rightDomainMap, m_edmItemCollection); } }
// creates a condition member=value internal static BoolExpression CreateMemberCondition(MemberPath path, Constant domainValue, MemberDomainMap domainMap) { if (domainValue is TypeConstant) { return(BoolExpression.CreateLiteral( new TypeRestriction( new MemberProjectedSlot(path), new Domain(domainValue, domainMap.GetDomain(path))), domainMap)); } else { return(BoolExpression.CreateLiteral( new ScalarRestriction( new MemberProjectedSlot(path), new Domain(domainValue, domainMap.GetDomain(path))), domainMap)); } }