// <summary> // Finds interesting members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods // for the given <paramref name="entitySet" /> and <paramref name="entityType" />. // </summary> // <param name="entitySet"> An EntitySet belonging to the C-Space. Must not be null. </param> // <param name="entityType"> An EntityType that participates in the given EntitySet. Must not be null. </param> // <param name="interestingMembersKind"> Scenario the members should be returned for. </param> // <returns> // ReadOnlyCollection of interesting members for the requested scenario ( // <paramref // name="interestingMembersKind" /> // ). // </returns> private ReadOnlyCollection<EdmMember> FindInterestingMembers( EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind) { DebugCheck.NotNull(entitySet); DebugCheck.NotNull(entityType); var interestingMembers = new List<EdmMember>(); foreach ( var storageTypeMapping in MappingMetadataHelper.GetMappingsForEntitySetAndSuperTypes(this, entitySet.EntityContainer, entitySet, entityType)) { var associationTypeMapping = storageTypeMapping as AssociationTypeMapping; if (associationTypeMapping != null) { FindInterestingAssociationMappingMembers(associationTypeMapping, interestingMembers); } else { Debug.Assert(storageTypeMapping is EntityTypeMapping, "EntityTypeMapping expected."); FindInterestingEntityMappingMembers( (EntityTypeMapping)storageTypeMapping, interestingMembersKind, interestingMembers); } } // For backwards compatibility we don't return foreign keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method if (interestingMembersKind != InterestingMembersKind.RequiredOriginalValueMembers) { FindForeignKeyProperties(entitySet, entityType, interestingMembers); } foreach (var functionMappings in MappingMetadataHelper .GetModificationFunctionMappingsForEntitySetAndType(this, entitySet.EntityContainer, entitySet, entityType) .Where(functionMappings => functionMappings.UpdateFunctionMapping != null)) { FindInterestingFunctionMappingMembers(functionMappings, interestingMembersKind, ref interestingMembers); } Debug.Assert(interestingMembers != null, "interestingMembers must never be null."); return new ReadOnlyCollection<EdmMember>(interestingMembers.Distinct().ToList()); }
// <summary> // Finds interesting entity properties - primary keys (if requested), properties (including complex properties and nested properties) // with concurrency mode set to fixed and C-Side condition members and adds them to the // <paramref // name="interestingMembers" /> // . // </summary> // <param name="entityTypeMapping"> Entity type mapping. Must not be null. </param> // <param name="interestingMembersKind"> Scenario the members should be returned for. </param> // <param name="interestingMembers"> The list the interesting members (if any) will be added to. Must not be null. </param> private static void FindInterestingEntityMappingMembers( EntityTypeMapping entityTypeMapping, InterestingMembersKind interestingMembersKind, List<EdmMember> interestingMembers) { DebugCheck.NotNull(entityTypeMapping); DebugCheck.NotNull(interestingMembers); foreach (var propertyMapping in entityTypeMapping.MappingFragments.SelectMany(mf => mf.AllProperties)) { var scalarPropMapping = propertyMapping as ScalarPropertyMapping; var complexPropMapping = propertyMapping as ComplexPropertyMapping; var conditionMapping = propertyMapping as ConditionPropertyMapping; Debug.Assert(!(propertyMapping is EndPropertyMapping), "association mapping properties should be handled elsewhere."); Debug.Assert( scalarPropMapping != null || complexPropMapping != null || conditionMapping != null, "Unimplemented property mapping"); //scalar property if (scalarPropMapping != null && scalarPropMapping.Property != null) { // (0) if a member is part of the key it is interesting if (MetadataHelper.IsPartOfEntityTypeKey(scalarPropMapping.Property)) { // For backwards compatibility we do return primary keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method if (interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers) { interestingMembers.Add(scalarPropMapping.Property); } } //(3) if a scalar property has Fixed concurrency mode then it is "interesting" else if (MetadataHelper.GetConcurrencyMode(scalarPropMapping.Property) == ConcurrencyMode.Fixed) { interestingMembers.Add(scalarPropMapping.Property); } } else if (complexPropMapping != null) { // (7) All complex members - partial update scenarios only // (3.1) The complex property or its one of its children has fixed concurrency mode if (interestingMembersKind == InterestingMembersKind.PartialUpdate || MetadataHelper.GetConcurrencyMode(complexPropMapping.Property) == ConcurrencyMode.Fixed || HasFixedConcurrencyModeInAnyChildProperty(complexPropMapping)) { interestingMembers.Add(complexPropMapping.Property); } } else if (conditionMapping != null) { //(1) C-Side condition members are 'interesting' if (conditionMapping.Property != null) { interestingMembers.Add(conditionMapping.Property); } } } }
// <summary> // Finds interesting members for modification functions mapped to stored procedures and adds them to the // <paramref // name="interestingMembers" /> // . // </summary> // <param name="functionMappings"> Modification function mapping. Must not be null. </param> // <param name="interestingMembersKind"> Update scenario the members will be used in (in general - partial update vs. full update). </param> private static void FindInterestingFunctionMappingMembers( EntityTypeModificationFunctionMapping functionMappings, InterestingMembersKind interestingMembersKind, ref List<EdmMember> interestingMembers) { DebugCheck.NotNull(functionMappings); DebugCheck.NotNull(functionMappings.UpdateFunctionMapping); DebugCheck.NotNull(interestingMembers); // for partial update scenarios (e.g. EntityDataSourceControl) all members are interesting otherwise the data may be corrupt. // See bugs #272992 and #124460 in DevDiv database for more details. For full update scenarios and the obsolete // MetadataWorkspace.GetRequiredOriginalValueMembers() metod we return only members with Version set to "Original". if (interestingMembersKind == InterestingMembersKind.PartialUpdate) { // (5) Members included in Update ModificationFunction interestingMembers.AddRange( functionMappings.UpdateFunctionMapping.ParameterBindings.Select(p => p.MemberPath.Members.Last())); } else { //(4) Members in update ModificationFunction with Version="Original" are "interesting" // This also works when you have complex-types (4.1) Debug.Assert( interestingMembersKind == InterestingMembersKind.FullUpdate || interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers, "Unexpected kind of interesting members - if you changed the InterestingMembersKind enum type update this code accordingly"); foreach (var parameterBinding in functionMappings.UpdateFunctionMapping.ParameterBindings.Where(p => !p.IsCurrent)) { //Last is the root element (with respect to the Entity) //For example, Entity1={ // S1, // C1{S2, // C2{ S3, S4 } // }, // S5} // if S4 matches (i.e. C1.C2.S4), then it returns C1 //because internally the list is [S4][C2][C1] interestingMembers.Add(parameterBinding.MemberPath.Members.Last()); } } }
// <summary> // Return members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods. // </summary> // <param name="entitySet"> An EntitySet belonging to the C-Space. Must not be null. </param> // <param name="entityType"> An EntityType that participates in the given EntitySet. Must not be null. </param> // <param name="interestingMembersKind"> Scenario the members should be returned for. </param> // <returns> // ReadOnlyCollection of interesting members for the requested scenario ( // <paramref // name="interestingMembersKind" /> // ). // </returns> internal ReadOnlyCollection<EdmMember> GetInterestingMembers( EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind) { DebugCheck.NotNull(entitySet); DebugCheck.NotNull(entityType); var key = new Tuple<EntitySetBase, EntityTypeBase, InterestingMembersKind>(entitySet, entityType, interestingMembersKind); return _cachedInterestingMembers.GetOrAdd(key, FindInterestingMembers(entitySet, entityType, interestingMembersKind)); }
/// <summary> /// Return members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods. /// </summary> /// <param name="entitySet"> An EntitySet belonging to the C-Space. Must not be null. </param> /// <param name="entityType"> An EntityType that participates in the given EntitySet. Must not be null. </param> /// <param name="interestingMembersKind"> Scenario the members should be returned for. </param> /// <returns> ReadOnlyCollection of interesting members for the requested scenario ( <paramref /// name="interestingMembersKind" /> ). </returns> internal ReadOnlyCollection<EdmMember> GetInterestingMembers( EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind) { Debug.Assert(entitySet != null, "entitySet != null"); Debug.Assert(entityType != null, "entityType != null"); var key = new Tuple<EntitySetBase, EntityTypeBase, InterestingMembersKind>(entitySet, entityType, interestingMembersKind); return _cachedInterestingMembers.GetOrAdd(key, FindInterestingMembers(entitySet, entityType, interestingMembersKind)); }
/// <summary> /// Finds interesting members for modification functions mapped to stored procedures and adds them to the <paramref name="interestingMembers"/>. /// </summary> /// <param name="functionMappings">Modification function mapping. Must not be null.</param> /// <param name="interestingMembersKind">Update scenario the members will be used in (in general - partial update vs. full update).</param> /// <param name="interestingMembers"></param> private static void FindInterestingFunctionMappingMembers(StorageEntityTypeModificationFunctionMapping functionMappings, InterestingMembersKind interestingMembersKind, ref List <EdmMember> interestingMembers) { Debug.Assert(functionMappings != null && functionMappings.UpdateFunctionMapping != null, "Expected function mapping fragment with non-null update function mapping"); Debug.Assert(interestingMembers != null, "interestingMembers != null"); // for partial update scenarios (e.g. EntityDataSourceControl) all members are interesting otherwise the data may be corrupt. // See bugs #272992 and #124460 in DevDiv database for more details. For full update scenarios and the obsolete // MetadataWorkspace.GetRequiredOriginalValueMembers() metod we return only members with Version set to "Original". if (interestingMembersKind == InterestingMembersKind.PartialUpdate) { // (5) Members included in Update ModificationFunction interestingMembers.AddRange(functionMappings.UpdateFunctionMapping.ParameterBindings.Select(p => p.MemberPath.Members.Last())); } else { //(4) Members in update ModificationFunction with Version="Original" are "interesting" // This also works when you have complex-types (4.1) Debug.Assert( interestingMembersKind == InterestingMembersKind.FullUpdate || interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers, "Unexpected kind of interesting members - if you changed the InterestingMembersKind enum type update this code accordingly"); foreach (var parameterBinding in functionMappings.UpdateFunctionMapping.ParameterBindings.Where(p => !p.IsCurrent)) { //Last is the root element (with respect to the Entity) //For example, Entity1={ // S1, // C1{S2, // C2{ S3, S4 } // }, // S5} // if S4 matches (i.e. C1.C2.S4), then it returns C1 //because internally the list is [S4][C2][C1] interestingMembers.Add(parameterBinding.MemberPath.Members.Last()); } } }
/// <summary> /// Finds interesting entity properties - primary keys (if requested), properties (including complex properties and nested properties) /// with concurrency mode set to fixed and C-Side condition members and adds them to the <paramref name="interestingMembers"/>. /// </summary> /// <param name="entityTypeMapping">Entity type mapping. Must not be null.</param> /// <param name="interestingMembersKind">Scenario the members should be returned for.</param> /// <param name="interestingMembers">The list the interesting members (if any) will be added to. Must not be null.</param> private static void FindInterestingEntityMappingMembers(StorageEntityTypeMapping entityTypeMapping, InterestingMembersKind interestingMembersKind, List <EdmMember> interestingMembers) { Debug.Assert(entityTypeMapping != null, "entityTypeMapping != null"); Debug.Assert(interestingMembers != null, "interestingMembers != null"); foreach (var propertyMapping in entityTypeMapping.MappingFragments.SelectMany(mf => mf.AllProperties)) { StorageScalarPropertyMapping scalarPropMapping = propertyMapping as StorageScalarPropertyMapping; StorageComplexPropertyMapping complexPropMapping = propertyMapping as StorageComplexPropertyMapping; StorageConditionPropertyMapping conditionMapping = propertyMapping as StorageConditionPropertyMapping; Debug.Assert(!(propertyMapping is StorageEndPropertyMapping), "association mapping properties should be handled elsewhere."); Debug.Assert(scalarPropMapping != null || complexPropMapping != null || conditionMapping != null, "Unimplemented property mapping"); //scalar property if (scalarPropMapping != null && scalarPropMapping.EdmProperty != null) { // (0) if a member is part of the key it is interesting if (MetadataHelper.IsPartOfEntityTypeKey(scalarPropMapping.EdmProperty)) { // For backwards compatibility we do return primary keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method if (interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers) { interestingMembers.Add(scalarPropMapping.EdmProperty); } } //(3) if a scalar property has Fixed concurrency mode then it is "interesting" else if (MetadataHelper.GetConcurrencyMode(scalarPropMapping.EdmProperty) == ConcurrencyMode.Fixed) { interestingMembers.Add(scalarPropMapping.EdmProperty); } } else if (complexPropMapping != null) { // (7) All complex members - partial update scenarios only // (3.1) The complex property or its one of its children has fixed concurrency mode if (interestingMembersKind == InterestingMembersKind.PartialUpdate || MetadataHelper.GetConcurrencyMode(complexPropMapping.EdmProperty) == ConcurrencyMode.Fixed || HasFixedConcurrencyModeInAnyChildProperty(complexPropMapping)) { interestingMembers.Add(complexPropMapping.EdmProperty); } } else if (conditionMapping != null) { //(1) C-Side condition members are 'interesting' if (conditionMapping.EdmProperty != null) { interestingMembers.Add(conditionMapping.EdmProperty); } } } }
/// <summary> /// Finds interesting members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods /// for the given <paramref name="entitySet"/> and <paramref name="entityType"/>. /// </summary> /// <param name="entitySet">An EntitySet belonging to the C-Space. Must not be null.</param> /// <param name="entityType">An EntityType that participates in the given EntitySet. Must not be null.</param> /// <param name="interestingMembersKind">Scenario the members should be returned for.</param> /// <returns>ReadOnlyCollection of interesting members for the requested scenario (<paramref name="interestingMembersKind"/>).</returns> private ReadOnlyCollection <EdmMember> FindInterestingMembers(EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind) { Debug.Assert(entitySet != null, "entitySet != null"); Debug.Assert(entityType != null, "entityType != null"); var interestingMembers = new List <EdmMember>(); foreach (var storageTypeMapping in MappingMetadataHelper.GetMappingsForEntitySetAndSuperTypes(this, entitySet.EntityContainer, entitySet, entityType)) { StorageAssociationTypeMapping associationTypeMapping = storageTypeMapping as StorageAssociationTypeMapping; if (associationTypeMapping != null) { FindInterestingAssociationMappingMembers(associationTypeMapping, interestingMembers); } else { Debug.Assert(storageTypeMapping is StorageEntityTypeMapping, "StorageEntityTypeMapping expected."); FindInterestingEntityMappingMembers((StorageEntityTypeMapping)storageTypeMapping, interestingMembersKind, interestingMembers); } } // For backwards compatibility we don't return foreign keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method if (interestingMembersKind != InterestingMembersKind.RequiredOriginalValueMembers) { FindForeignKeyProperties(entitySet, entityType, interestingMembers); } foreach (var functionMappings in MappingMetadataHelper .GetModificationFunctionMappingsForEntitySetAndType(this, entitySet.EntityContainer, entitySet, entityType) .Where(functionMappings => functionMappings.UpdateFunctionMapping != null)) { FindInterestingFunctionMappingMembers(functionMappings, interestingMembersKind, ref interestingMembers); } Debug.Assert(interestingMembers != null, "interestingMembers must never be null."); return(new ReadOnlyCollection <EdmMember>(interestingMembers.Distinct().ToList())); }
/// <summary> /// Return members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods. /// </summary> /// <param name="entitySet">An EntitySet belonging to the C-Space. Must not be null.</param> /// <param name="entityType">An EntityType that participates in the given EntitySet. Must not be null.</param> /// <param name="interestingMembersKind">Scenario the members should be returned for.</param> /// <returns>ReadOnlyCollection of interesting members for the requested scenario (<paramref name="interestingMembersKind"/>).</returns> internal ReadOnlyCollection <EdmMember> GetInterestingMembers(EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind) { Debug.Assert(entitySet != null, "entitySet != null"); Debug.Assert(entityType != null, "entityType != null"); var key = new Tuple <EntitySetBase, EntityTypeBase, InterestingMembersKind>(entitySet, entityType, interestingMembersKind); return(_cachedInterestingMembers.GetOrAdd(key, FindInterestingMembers(entitySet, entityType, interestingMembersKind))); }