// effects: Returns the key for entityType prefixed with prefix (for // its memberPath) internal static ExtentKey GetPrimaryKeyForEntityType(MemberPath prefix, EntityType entityType) { var keyFields = new List<MemberPath>(); foreach (var keyMember in entityType.KeyMembers) { Debug.Assert(keyMember != null, "Bogus key member in metadata"); keyFields.Add(new MemberPath(prefix, keyMember)); } // Just have one key for now var key = new ExtentKey(keyFields); return key; }
// effects: Returns a key correspnding to all the fields in different // ends of relationtype prefixed with "prefix" internal static ExtentKey GetKeyForRelationType(MemberPath prefix, AssociationType relationType) { var keyFields = new List<MemberPath>(); foreach (var endMember in relationType.AssociationEndMembers) { var endPrefix = new MemberPath(prefix, endMember); var entityType = MetadataHelper.GetEntityTypeForEnd(endMember); var primaryKey = GetPrimaryKeyForEntityType(endPrefix, entityType); keyFields.AddRange(primaryKey.KeyFields); } var key = new ExtentKey(keyFields); return key; }
// 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: Returns an error record if the keys of the extent/associationSet being mapped are // present in the projected slots of this query. Returns null // otherwise. ownerCell indicates the cell that owns this and // resourceString is a resource used for error messages internal ErrorLog.Record VerifyKeysPresent(Cell ownerCell, Func <object, object, string> formatEntitySetMessage, Func <object, object, object, string> formatAssociationSetMessage, ViewGenErrorCode errorCode) { List <MemberPath> prefixes = new List <MemberPath>(1); // Keep track of the key corresponding to each prefix List <ExtentKey> keys = new List <ExtentKey>(1); if (Extent is EntitySet) { // For entity set just get the full path of the key properties MemberPath prefix = new MemberPath(Extent); prefixes.Add(prefix); EntityType entityType = (EntityType)Extent.ElementType; List <ExtentKey> entitySetKeys = ExtentKey.GetKeysForEntityType(prefix, entityType); Debug.Assert(entitySetKeys.Count == 1, "Currently, we only support primary keys"); keys.Add(entitySetKeys[0]); } else { AssociationSet relationshipSet = (AssociationSet)Extent; // For association set, get the full path of the key // properties of each end foreach (AssociationSetEnd relationEnd in relationshipSet.AssociationSetEnds) { AssociationEndMember assocEndMember = relationEnd.CorrespondingAssociationEndMember; MemberPath prefix = new MemberPath(relationshipSet, assocEndMember); prefixes.Add(prefix); List <ExtentKey> endKeys = ExtentKey.GetKeysForEntityType(prefix, MetadataHelper.GetEntityTypeForEnd(assocEndMember)); Debug.Assert(endKeys.Count == 1, "Currently, we only support primary keys"); keys.Add(endKeys[0]); } } for (int i = 0; i < prefixes.Count; i++) { MemberPath prefix = prefixes[i]; // Get all or none key slots that are being projected in this cell query List <MemberProjectedSlot> keySlots = MemberProjectedSlot.GetKeySlots(GetMemberProjectedSlots(), prefix); if (keySlots == null) { ExtentKey key = keys[i]; string message; if (Extent is EntitySet) { string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, true); message = formatEntitySetMessage(keyPropertiesString, Extent.Name); } else { string endName = prefix.RootEdmMember.Name; string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, false); message = formatAssociationSetMessage(keyPropertiesString, endName, Extent.Name); } ErrorLog.Record error = new ErrorLog.Record(true, errorCode, message, ownerCell, String.Empty); return(error); } } return(null); }