Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / ViewGeneration / QueryRewriting / FragmentQueryKB.cs
blobae6ec4120095d5334a6eb4cf6a078b38b8226d81
1 //---------------------------------------------------------------------
2 // <copyright file="FragmentQueryKB.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System;
11 using System.Diagnostics;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.Data.Common.Utils;
15 using System.Data.Common.Utils.Boolean;
16 using System.Data.Mapping.ViewGeneration.Structures;
17 using System.Data.Metadata.Edm;
18 using System.Linq;
20 namespace System.Data.Mapping.ViewGeneration.QueryRewriting
22 internal class FragmentQueryKB : KnowledgeBase<DomainConstraint<BoolLiteral, Constant>>
24 private BoolExpr<DomainConstraint<BoolLiteral, Constant>> _kbExpression = TrueExpr<DomainConstraint<BoolLiteral, Constant>>.Value;
26 internal override void AddFact(BoolExpr<DomainConstraint<BoolLiteral, Constant>> fact)
28 base.AddFact(fact);
29 _kbExpression = new AndExpr<DomainConstraint<BoolLiteral, Constant>>(_kbExpression, fact);
31 internal BoolExpr<DomainConstraint<BoolLiteral, Constant>> KbExpression
33 get { return _kbExpression; }
36 internal void CreateVariableConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
38 CreateVariableConstraintsRecursion(extent.ElementType, new MemberPath(extent), domainMap, edmItemCollection);
41 internal void CreateAssociationConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
43 AssociationSet assocSet = extent as AssociationSet;
44 if (assocSet != null)
46 BoolExpression assocSetExpr = BoolExpression.CreateLiteral(new RoleBoolean(assocSet), domainMap);
48 //Set of Keys for this Association Set
49 //need to key on EdmMember and EdmType because A, B subtype of C, can have the same id (EdmMember) that is defined in C.
50 HashSet<Pair<EdmMember, EntityType>> associationkeys = new HashSet<Pair<EdmMember, EntityType>>();
53 //foreach end, add each Key
54 foreach (var endMember in assocSet.ElementType.AssociationEndMembers)
56 EntityType type = (EntityType)((RefType)endMember.TypeUsage.EdmType).ElementType;
57 type.KeyMembers.All(member => associationkeys.Add(new Pair<EdmMember, EntityType>(member, type)) || true /* prevent early termination */);
60 foreach (AssociationSetEnd end in assocSet.AssociationSetEnds)
62 // construct type condition
63 HashSet<EdmType> derivedTypes = new HashSet<EdmType>();
64 derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(end.CorrespondingAssociationEndMember.TypeUsage.EdmType, edmItemCollection, false));
66 BoolExpression typeCondition = CreateIsOfTypeCondition(new MemberPath(end.EntitySet),
67 derivedTypes, domainMap);
69 BoolExpression inRoleExpression = BoolExpression.CreateLiteral(new RoleBoolean(end), domainMap);
70 BoolExpression inSetExpression = BoolExpression.CreateAnd(
71 BoolExpression.CreateLiteral(new RoleBoolean(end.EntitySet), domainMap),
72 typeCondition);
74 // InRole -> (InSet AND type(Set)=T)
75 AddImplication(inRoleExpression.Tree, inSetExpression.Tree);
77 if (MetadataHelper.IsEveryOtherEndAtLeastOne(assocSet, end.CorrespondingAssociationEndMember))
79 AddImplication(inSetExpression.Tree, inRoleExpression.Tree);
82 // Add equivalence between association set an End/Role if necessary.
83 // Equivalence is added when a given association end's keys subsumes keys for
84 // all the other association end.
86 // For example: We have Entity Sets A[id1], B[id2, id3] and an association A_B between them.
87 // Ref Constraint A.id1 = B.id2
88 // In this case, the Association Set has Key <id1, id2, id3>
89 // id1 alone can not identify a unique tuple in the Association Set, but <id2, id3> can.
90 // Therefore we add a constraint: InSet(B) <=> InEnd(A_B.B)
92 if (MetadataHelper.DoesEndKeySubsumeAssociationSetKey(assocSet,
93 end.CorrespondingAssociationEndMember,
94 associationkeys))
96 AddEquivalence(inRoleExpression.Tree, assocSetExpr.Tree);
101 // add rules for referential constraints (borrowed from LeftCellWrapper.cs)
102 AssociationType assocType = assocSet.ElementType;
104 foreach (ReferentialConstraint constraint in assocType.ReferentialConstraints)
106 AssociationEndMember toEndMember = (AssociationEndMember)constraint.ToRole;
107 EntitySet toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
108 // Check if the keys of the entitySet's are equal to what is specified in the constraint
109 // How annoying that KeyMembers returns EdmMember and not EdmProperty
110 IEnumerable<EdmMember> toProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.ToProperties);
111 if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer<EdmMember>.Default))
113 // Now check that the FromEnd is 1..1 (only then will all the Addresses be present in the assoc set)
114 if (constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One))
116 // Make sure that the ToEnd is not 0..* because then the schema is broken
117 Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many) == false);
118 // Equate the ends
119 BoolExpression inRoleExpression1 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[0]), domainMap);
120 BoolExpression inRoleExpression2 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[1]), domainMap);
121 AddEquivalence(inRoleExpression1.Tree, inRoleExpression2.Tree);
128 internal void CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(AssociationSet assocSet, MemberDomainMap domainMap,
129 EdmItemCollection edmItemCollection)
131 AssociationType assocType = assocSet.ElementType;
132 foreach (ReferentialConstraint constraint in assocType.ReferentialConstraints)
134 AssociationEndMember toEndMember = (AssociationEndMember)constraint.ToRole;
135 AssociationEndMember fromEndMember = (AssociationEndMember)constraint.FromRole;
136 EntitySet toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
137 EntitySet fromEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, fromEndMember);
139 // Check if the keys of the entitySet's are equal to what is specified in the constraint
140 IEnumerable<EdmMember> toProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.ToProperties);
141 if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer<EdmMember>.Default))
143 //make sure that the method called with a 1:1 association
144 Debug.Assert(constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
145 Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
146 // Create an Equivalence between the two Sets participating in this AssociationSet
147 BoolExpression fromSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(fromEntitySet), domainMap);
148 BoolExpression toSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(toEntitySet), domainMap);
149 AddEquivalence(fromSetExpression.Tree, toSetExpression.Tree);
154 private void CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
156 // Add the types can member have, i.e., its type and its subtypes
157 HashSet<EdmType> possibleTypes = new HashSet<EdmType>();
158 possibleTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(edmType, edmItemCollection, true));
160 foreach (EdmType possibleType in possibleTypes)
162 // determine type domain
164 HashSet<EdmType> derivedTypes = new HashSet<EdmType>();
165 derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(possibleType, edmItemCollection, false));
166 if (derivedTypes.Count != 0)
168 BoolExpression typeCondition = CreateIsOfTypeCondition(currentPath, derivedTypes, domainMap);
169 BoolExpression typeConditionComplement = BoolExpression.CreateNot(typeCondition);
170 if (false == typeConditionComplement.IsSatisfiable())
172 continue;
175 StructuralType structuralType = (StructuralType)possibleType;
176 foreach (EdmProperty childProperty in structuralType.GetDeclaredOnlyMembers<EdmProperty>())
178 MemberPath childPath = new MemberPath(currentPath, childProperty);
179 bool isScalar = MetadataHelper.IsNonRefSimpleMember(childProperty);
181 if (domainMap.IsConditionMember(childPath) || domainMap.IsProjectedConditionMember(childPath))
183 BoolExpression nullCondition;
184 List<Constant> childDomain = new List<Constant>(domainMap.GetDomain(childPath));
185 if (isScalar)
187 nullCondition = BoolExpression.CreateLiteral(new ScalarRestriction(new MemberProjectedSlot(childPath),
188 new Domain(ScalarConstant.Undefined, childDomain)), domainMap);
190 else
192 nullCondition = BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(childPath),
193 new Domain(TypeConstant.Undefined, childDomain)), domainMap);
195 // Properties not occuring in type are UNDEFINED
196 AddEquivalence(typeConditionComplement.Tree, nullCondition.Tree);
199 // recurse into complex types
200 if (false == isScalar)
202 CreateVariableConstraintsRecursion(childPath.EdmType, childPath, domainMap, edmItemCollection);
209 private static BoolExpression CreateIsOfTypeCondition(MemberPath currentPath, IEnumerable<EdmType> derivedTypes, MemberDomainMap domainMap)
211 Domain typeDomain = new Domain(derivedTypes.Select(derivedType => (Constant)new TypeConstant(derivedType)), domainMap.GetDomain(currentPath));
212 BoolExpression typeCondition = BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(currentPath), typeDomain), domainMap);
213 return typeCondition;