1 //---------------------------------------------------------------------
2 // <copyright file="MetadataHelper.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 using System.Data.Mapping;
13 using System.Data.Metadata.Edm;
14 using System.Data.Objects.ELinq;
15 using System.Diagnostics;
17 using System.Security.Cryptography;
19 namespace System.Data.Common.Utils
21 // Helper functions to get metadata information
22 internal static class MetadataHelper
25 /// Returns an element type of the collection returned by the function import.
26 /// Returns false, if element type cannot be determined.
28 internal static bool TryGetFunctionImportReturnType<T>(EdmFunction functionImport, int resultSetIndex, out T returnType) where T : EdmType
31 if (TryGetWrappedReturnEdmTypeFromFunctionImport<T>(functionImport, resultSetIndex, out resultType))
33 if (typeof(EntityType).Equals(typeof(T)) && resultType is EntityType
34 || typeof(ComplexType).Equals(typeof(T)) && resultType is ComplexType
35 || typeof(StructuralType).Equals(typeof(T)) && resultType is StructuralType
36 || typeof(EdmType).Equals(typeof(T)) && resultType is EdmType)
38 returnType = resultType;
46 private static bool TryGetWrappedReturnEdmTypeFromFunctionImport<T>(EdmFunction functionImport, int resultSetIndex, out T resultType) where T : EdmType
50 CollectionType collectionType;
51 if (TryGetFunctionImportReturnCollectionType(functionImport, resultSetIndex, out collectionType))
53 resultType = collectionType.TypeUsage.EdmType as T;
60 /// effects: determines if the given function import returns collection type, and if so returns the type
62 internal static bool TryGetFunctionImportReturnCollectionType(EdmFunction functionImport, int resultSetIndex, out CollectionType collectionType)
64 FunctionParameter returnParameter = GetReturnParameter(functionImport, resultSetIndex);
65 if (returnParameter != null
66 && returnParameter.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
68 collectionType = (CollectionType)returnParameter.TypeUsage.EdmType;
71 collectionType = null;
77 /// Gets the resultSetIndexth return parameter for functionImport, or null if resultSetIndex is out of range
79 internal static FunctionParameter GetReturnParameter(EdmFunction functionImport, int resultSetIndex)
81 return functionImport.ReturnParameters.Count > resultSetIndex
82 ? functionImport.ReturnParameters[resultSetIndex]
86 internal static EdmFunction GetFunctionImport(
87 string functionName, string defaultContainerName, MetadataWorkspace workspace,
88 out string containerName, out string functionImportName)
90 // find FunctionImport
92 CommandHelper.ParseFunctionImportCommandText(functionName, defaultContainerName,
93 out containerName, out functionImportName);
94 return CommandHelper.FindFunctionImport(workspace, containerName, functionImportName);
98 /// Gets the resultSetIndexth result edm type, and ensure that it is consistent with EntityType.
100 internal static EdmType GetAndCheckFunctionImportReturnType<TElement>(EdmFunction functionImport, int resultSetIndex, MetadataWorkspace workspace)
102 EdmType expectedEdmType;
103 if (!MetadataHelper.TryGetFunctionImportReturnType<EdmType>(functionImport, resultSetIndex, out expectedEdmType))
105 throw EntityUtil.ExecuteFunctionCalledWithNonReaderFunction(functionImport);
107 CheckFunctionImportReturnType<TElement>(expectedEdmType, workspace);
109 return expectedEdmType;
113 /// check that the type TElement and function metadata are consistent
115 internal static void CheckFunctionImportReturnType<TElement>(EdmType expectedEdmType, MetadataWorkspace workspace)
117 // currently there are only two possible spatial O-space types, but 16 C-space types.
118 // Normalize the C-space type to the base type before we check to see if it matches the O-space type.
120 EdmType spatialNormalizedEdmType = expectedEdmType;
121 if (Helper.IsSpatialType(expectedEdmType, out isGeographic))
123 spatialNormalizedEdmType = PrimitiveType.GetEdmPrimitiveType(isGeographic ? PrimitiveTypeKind.Geography : PrimitiveTypeKind.Geometry);
126 EdmType modelEdmType;
127 if (!MetadataHelper.TryDetermineCSpaceModelType<TElement>(workspace, out modelEdmType)||
128 !modelEdmType.EdmEquals(spatialNormalizedEdmType))
130 throw EntityUtil.ExecuteFunctionTypeMismatch(typeof(TElement), expectedEdmType);
134 // Returns ParameterDirection corresponding to given ParameterMode
135 internal static ParameterDirection ParameterModeToParameterDirection(ParameterMode mode)
139 case ParameterMode.In:
140 return ParameterDirection.Input;
142 case ParameterMode.InOut:
143 return ParameterDirection.InputOutput;
145 case ParameterMode.Out:
146 return ParameterDirection.Output;
148 case ParameterMode.ReturnValue:
149 return ParameterDirection.ReturnValue;
152 Debug.Fail("unrecognized mode " + mode.ToString());
153 return default(ParameterDirection);
157 // requires: workspace
158 // Determines CSpace EntityType associated with the type argument T
159 internal static bool TryDetermineCSpaceModelType<T>(MetadataWorkspace workspace, out EdmType modelEdmType)
161 return TryDetermineCSpaceModelType(typeof(T), workspace, out modelEdmType);
164 internal static bool TryDetermineCSpaceModelType(Type type, MetadataWorkspace workspace, out EdmType modelEdmType)
166 Debug.Assert(null != workspace);
167 Type nonNullabelType = TypeSystem.GetNonNullableType(type);
168 // make sure the workspace knows about T
169 workspace.ImplicitLoadAssemblyForType(nonNullabelType, System.Reflection.Assembly.GetCallingAssembly());
170 ObjectItemCollection objectItemCollection = (ObjectItemCollection)workspace.GetItemCollection(DataSpace.OSpace);
171 EdmType objectEdmType;
172 if (objectItemCollection.TryGetItem<EdmType>(nonNullabelType.FullName, out objectEdmType))
175 if (workspace.TryGetMap(objectEdmType, DataSpace.OCSpace, out map))
177 ObjectTypeMapping objectMapping = (ObjectTypeMapping)map;
178 modelEdmType = objectMapping.EdmType;
186 // effects: Returns true iff member is present in type.Members
187 internal static bool DoesMemberExist(StructuralType type, EdmMember member)
189 foreach (EdmMember child in type.Members)
191 if (child.Equals(member))
200 /// Returns true iff member's is a simple non-structures scalar such as primitive or enum.
202 internal static bool IsNonRefSimpleMember(EdmMember member)
204 return member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType ||
205 member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.EnumType;
208 // effects: Returns true if member's type has a discrete domain (i.e. is bolean type)
209 // Note: enums don't have discrete domains as we allow domain of the underlying type.
210 internal static bool HasDiscreteDomain(EdmType edmType)
212 var primitiveType = edmType as PrimitiveType;
214 return primitiveType != null && primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Boolean;
217 // requires: end is given
218 // effects: determine the entity type for an association end member
219 internal static EntityType GetEntityTypeForEnd(AssociationEndMember end)
221 Debug.Assert(null != end);
222 Debug.Assert(end.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType,
223 "type of association end member must be ref");
224 RefType refType = (RefType)end.TypeUsage.EdmType;
225 EntityTypeBase endType = refType.ElementType;
226 Debug.Assert(endType.BuiltInTypeKind == BuiltInTypeKind.EntityType,
227 "type of association end reference element must be entity type");
228 return (EntityType)endType;
232 // effects: Returns the entity set at the end corresponding to endMember
233 internal static EntitySet GetEntitySetAtEnd(AssociationSet associationSet,
234 AssociationEndMember endMember)
236 return associationSet.AssociationSetEnds[endMember.Name].EntitySet;
239 // effects: Returns the AssociationEndMember at the other end of the parent association (first found)
240 internal static AssociationEndMember GetOtherAssociationEnd(AssociationEndMember endMember)
242 ReadOnlyMetadataCollection<EdmMember> members = endMember.DeclaringType.Members;
243 Debug.Assert(members.Count == 2, "only expecting two end members");
245 EdmMember otherMember = members[0];
246 if (!Object.ReferenceEquals(endMember, otherMember))
248 Debug.Assert(Object.ReferenceEquals(endMember, members[1]), "didn't match other member");
249 return (AssociationEndMember)otherMember;
251 return (AssociationEndMember)members[1];
254 // effects: Returns true iff every end other than "endPropery" has a lower
255 // multiplicity of at least one
256 internal static bool IsEveryOtherEndAtLeastOne(AssociationSet associationSet,
257 AssociationEndMember member)
259 foreach (AssociationSetEnd end in associationSet.AssociationSetEnds)
261 AssociationEndMember endMember = end.CorrespondingAssociationEndMember;
262 if (endMember.Equals(member) == false &&
263 GetLowerBoundOfMultiplicity(endMember.RelationshipMultiplicity) == 0)
271 // requires: toEnd and type are given
272 // effects: determines whether the given association end can be referenced by an entity of the given type
273 internal static bool IsAssociationValidForEntityType(AssociationSetEnd toEnd, EntityType type)
275 Debug.Assert(null != toEnd);
276 Debug.Assert(null != type);
278 // get the opposite end which includes the relevant type information
279 AssociationSetEnd fromEnd = GetOppositeEnd(toEnd);
280 EntityType fromType = GetEntityTypeForEnd(fromEnd.CorrespondingAssociationEndMember);
281 return (fromType.IsAssignableFrom(type));
284 // requires: end is given
285 // effects: returns the opposite end in the association
286 internal static AssociationSetEnd GetOppositeEnd(AssociationSetEnd end)
288 Debug.Assert(null != end);
289 // there must be exactly one ("Single") other end that isn't ("Filter") this end
290 AssociationSetEnd otherEnd = end.ParentAssociationSet.AssociationSetEnds.Where(
291 e => !e.EdmEquals(end)).Single();
295 // requires: function is not null
296 // effects: Returns true if the given function is composable.
297 internal static bool IsComposable(EdmFunction function)
299 Debug.Assert(function != null);
300 MetadataProperty isComposableProperty;
301 if (function.MetadataProperties.TryGetValue("IsComposableAttribute", false, out isComposableProperty))
303 return (bool)isComposableProperty.Value;
306 return !function.IsFunctionImport;
310 // requires: member is EdmProperty or AssociationEndMember
311 // effects: Returns true if member is nullable
312 internal static bool IsMemberNullable(EdmMember member)
314 Debug.Assert(member != null);
315 Debug.Assert(Helper.IsEdmProperty(member) || Helper.IsAssociationEndMember(member));
316 if (Helper.IsEdmProperty(member))
318 return ((EdmProperty)member).Nullable;
324 /// Given a table EntitySet this function finds out all C-side EntitySets that are mapped to the table.
326 internal static IEnumerable<EntitySet> GetInfluencingEntitySetsForTable(EntitySet table, MetadataWorkspace workspace)
328 Debug.Assert(table.EntityContainer.GetDataSpace() == DataSpace.SSpace);
330 ItemCollection itemCollection = null;
331 workspace.TryGetItemCollection(DataSpace.CSSpace, out itemCollection);
332 StorageEntityContainerMapping containerMapping = MappingMetadataHelper.GetEntityContainerMap((StorageMappingItemCollection)itemCollection, table.EntityContainer);
334 //find EntitySetMappings where one of the mapping fragment maps some type to the given table
335 return containerMapping.EntitySetMaps
337 map => map.TypeMappings.Any(
338 typeMap => typeMap.MappingFragments.Any(
339 mappingFrag => mappingFrag.TableSet.EdmEquals(table)
348 // effects: Returns this type and its sub types - for refs, gets the
349 // type and subtypes of the entity type
350 internal static IEnumerable<EdmType> GetTypeAndSubtypesOf(EdmType type, MetadataWorkspace workspace, bool includeAbstractTypes)
352 return GetTypeAndSubtypesOf(type, workspace.GetItemCollection(DataSpace.CSpace), includeAbstractTypes);
355 internal static IEnumerable<EdmType> GetTypeAndSubtypesOf(EdmType type, ItemCollection itemCollection, bool includeAbstractTypes)
357 // We have to collect subtypes in ref to support conditional association mappings
358 if (Helper.IsRefType(type))
360 type = ((RefType)type).ElementType;
363 if (includeAbstractTypes || !type.Abstract)
368 // Get entity sub-types
369 foreach (EdmType subType in GetTypeAndSubtypesOf<EntityType>(type, itemCollection, includeAbstractTypes))
371 yield return subType;
374 // Get complex sub-types
375 foreach (EdmType subType in GetTypeAndSubtypesOf<ComplexType>(type, itemCollection, includeAbstractTypes))
377 yield return subType;
381 private static IEnumerable<EdmType> GetTypeAndSubtypesOf<T_EdmType>(EdmType type, ItemCollection itemCollection, bool includeAbstractTypes)
382 where T_EdmType : EdmType
384 // Get the subtypes of the type from the WorkSpace
385 T_EdmType specificType = type as T_EdmType;
386 if (specificType != null)
389 IEnumerable<T_EdmType> typesInWorkSpace = itemCollection.GetItems<T_EdmType>();
390 foreach (T_EdmType typeInWorkSpace in typesInWorkSpace)
392 if (specificType.Equals(typeInWorkSpace) == false && Helper.IsSubtypeOf(typeInWorkSpace, specificType))
394 if (includeAbstractTypes || !typeInWorkSpace.Abstract)
396 yield return typeInWorkSpace;
406 internal static IEnumerable<EdmType> GetTypeAndParentTypesOf(EdmType type, ItemCollection itemCollection, bool includeAbstractTypes)
408 // We have to collect subtypes in ref to support conditional association mappings
409 if (Helper.IsRefType(type))
411 type = ((RefType)type).ElementType;
414 EdmType specificType = type;
415 while (specificType != null)
417 if (includeAbstractTypes || !specificType.Abstract)
419 yield return specificType;
422 specificType = specificType.BaseType as EntityType; //The cast is guaranteed to work. See use of GetItems<T_EdmType> in GetTypesAndSubTypesOf()
428 /// Builds an undirected graph (represented as a directional graph with reciprocal navigation edges) of the all the types in the workspace.
429 /// This is used to traverse inheritance hierarchy up and down.
430 /// O(n), where n=number of types
432 /// <returns>A dictionary of type t -> set of types {s}, such that there is an edge between t and elem(s) iff t and s are related DIRECTLY via inheritance (child or parent type) </returns>
433 internal static Dictionary<EntityType, Set<EntityType>> BuildUndirectedGraphOfTypes(EdmItemCollection edmItemCollection)
435 Dictionary<EntityType, Set<EntityType>> graph = new Dictionary<EntityType, Set<EntityType>>();
437 IEnumerable<EntityType> typesInWorkSpace = edmItemCollection.GetItems<EntityType>();
438 foreach (EntityType childType in typesInWorkSpace)
440 if (childType.BaseType == null) //root type
445 EntityType parentType = childType.BaseType as EntityType;
446 Debug.Assert(parentType != null, "Parent type not Entity Type ??");
448 AddDirectedEdgeBetweenEntityTypes(graph, childType, parentType);
449 AddDirectedEdgeBetweenEntityTypes(graph, parentType, childType);
456 /// is A parent of b?
458 internal static bool IsParentOf(EntityType a, EntityType b)
460 EntityType parent = b.BaseType as EntityType;
462 while (parent != null)
464 if (parent.EdmEquals(a))
470 parent = parent.BaseType as EntityType;
477 /// Add and Edge a --> b
478 /// Assumes edge does not exist
481 private static void AddDirectedEdgeBetweenEntityTypes(Dictionary<EntityType, Set<EntityType>> graph, EntityType a, EntityType b)
483 Set<EntityType> references;
484 if (graph.ContainsKey(a))
486 references = graph[a];
490 references = new Set<EntityType>();
491 graph.Add(a, references);
494 Debug.Assert(!references.Contains(b), "Dictionary already has a --> b reference");
501 /// Checks wither the given AssociationEnd's keys are sufficient for identifying a unique tuple in the AssociationSet.
502 /// This is possible because refconstraints make certain Keys redundant. We subtract such redundant key sof "other" ends
503 /// and see if what is left is contributed only from the given end's keys.
505 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]
506 internal static bool DoesEndKeySubsumeAssociationSetKey(AssociationSet assocSet, AssociationEndMember thisEnd, HashSet<Pair<EdmMember, EntityType>> associationkeys)
508 AssociationType assocType = assocSet.ElementType;
509 EntityType thisEndsEntityType = (EntityType)((RefType)thisEnd.TypeUsage.EdmType).ElementType;
511 HashSet<Pair<EdmMember, EntityType>> thisEndKeys = new HashSet<Pair<EdmMember, EntityType>>(
512 thisEndsEntityType.KeyMembers.Select(edmMember => new Pair<EdmMember, EntityType>(edmMember, thisEndsEntityType)));
514 foreach (ReferentialConstraint constraint in assocType.ReferentialConstraints)
516 IEnumerable<EdmMember> otherEndProperties;
517 EntityType otherEndType;
519 if (thisEnd.Equals((AssociationEndMember)constraint.ToRole))
521 otherEndProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.FromProperties);
522 otherEndType = (EntityType)((RefType)((AssociationEndMember)constraint.FromRole).TypeUsage.EdmType).ElementType;
524 else if (thisEnd.Equals((AssociationEndMember)constraint.FromRole))
526 otherEndProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.ToProperties);
527 otherEndType = (EntityType)((RefType)((AssociationEndMember)constraint.ToRole).TypeUsage.EdmType).ElementType;
531 //this end not part of the referential constraint
535 //Essentially ref constraints is an equality condition, so remove redundant members from entity set key
536 foreach (EdmMember member in otherEndProperties)
538 associationkeys.Remove(new Pair<EdmMember, EntityType>(member, otherEndType));
542 //Now that all redundant members have been removed, is thisEnd the key of the entity set?
543 return associationkeys.IsSubsetOf(thisEndKeys);
547 // effects: Returns true if end forms a key in relationshipSet
548 internal static bool DoesEndFormKey(AssociationSet associationSet, AssociationEndMember end)
550 // Look at all other ends. if their multiplicities are at most 1, return true
551 foreach (AssociationEndMember endMember in associationSet.ElementType.Members)
553 if (endMember.Equals(end) == false &&
554 endMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) // some other end has multiplicity 0..*
562 // effects: Returns true if extent is at one of the ends of relationshipSet
563 internal static bool IsExtentAtSomeRelationshipEnd(AssociationSet relationshipSet, EntitySetBase extent)
565 if (Helper.IsEntitySet(extent))
567 return GetSomeEndForEntitySet(relationshipSet, (EntitySet)extent) != null;
572 // effects: Returns some end corresponding to entity set in
573 // association set. If no such end exists, return null
574 internal static AssociationEndMember GetSomeEndForEntitySet(AssociationSet associationSet, EntitySetBase entitySet)
576 foreach (AssociationSetEnd associationEnd in associationSet.AssociationSetEnds)
578 if (associationEnd.EntitySet.Equals(entitySet))
580 return associationEnd.CorrespondingAssociationEndMember;
588 // requires: entitySet1 and entitySet2 belong to the same container
589 // effects: Returns the associations that occur between entitySet1
590 // and entitySet2. If none is found, returns an empty set
591 internal static List<AssociationSet> GetAssociationsForEntitySets(EntitySet entitySet1, EntitySet entitySet2)
593 Debug.Assert(entitySet1 != null);
594 Debug.Assert(entitySet2 != null);
595 Debug.Assert(entitySet1.EntityContainer == entitySet2.EntityContainer, "EntityContainer must be the same for both the entity sets");
597 List<AssociationSet> result = new List<AssociationSet>();
599 foreach (EntitySetBase extent in entitySet1.EntityContainer.BaseEntitySets)
601 if (Helper.IsRelationshipSet(extent))
603 AssociationSet assocSet = (AssociationSet)extent;
604 if (IsExtentAtSomeRelationshipEnd(assocSet, entitySet1) &&
605 IsExtentAtSomeRelationshipEnd(assocSet, entitySet2))
607 result.Add(assocSet);
614 // requires: entitySet and associationType
615 // effects: Returns the associations that refer to associationType and refer to entitySet in one of its end.
616 // If none is found, returns an empty set
617 internal static AssociationSet GetAssociationsForEntitySetAndAssociationType(EntityContainer entityContainer, string entitySetName,
618 AssociationType associationType, string endName, out EntitySet entitySet)
620 Debug.Assert(associationType.Members.Contains(endName), "EndName should be a valid name");
622 AssociationSet retValue = null;
623 ReadOnlyMetadataCollection<EntitySetBase> baseEntitySets = entityContainer.BaseEntitySets;
624 int count = baseEntitySets.Count;
625 for (int i = 0; i < count; ++i)
627 EntitySetBase extent = baseEntitySets[i];
628 if (Object.ReferenceEquals(extent.ElementType, associationType))
630 AssociationSet assocSet = (AssociationSet)extent;
631 EntitySet es = assocSet.AssociationSetEnds[endName].EntitySet;
632 if (es.Name == entitySetName)
634 Debug.Assert(retValue == null, "There should be only one AssociationSet, given an assocationtype, end name and entity set");
646 // requires: entitySet
647 // effects: Returns the associations that occur between entitySet
648 // and other entitySets. If none is found, returns an empty set
649 internal static List<AssociationSet> GetAssociationsForEntitySet(EntitySetBase entitySet)
651 Debug.Assert(entitySet != null);
653 List<AssociationSet> result = new List<AssociationSet>();
655 foreach (EntitySetBase extent in entitySet.EntityContainer.BaseEntitySets)
657 if (Helper.IsRelationshipSet(extent))
659 AssociationSet assocSet = (AssociationSet)extent;
660 if (IsExtentAtSomeRelationshipEnd(assocSet, entitySet))
662 result.Add(assocSet);
669 // effects: Returns true iff superType is an ancestor of subType in
670 // the type hierarchy or superType and subType are the same
671 internal static bool IsSuperTypeOf(EdmType superType, EdmType subType)
673 EdmType currentType = subType;
674 while (currentType != null)
676 if (currentType.Equals(superType))
680 currentType = currentType.BaseType;
685 // requires: typeUsage wraps a primitive type
686 internal static PrimitiveTypeKind GetPrimitiveTypeKind(TypeUsage typeUsage)
688 Debug.Assert(null != typeUsage && null != typeUsage.EdmType && typeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
690 PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType;
692 return primitiveType.PrimitiveTypeKind;
695 // determines whether the given member is a key of an entity set
696 internal static bool IsPartOfEntityTypeKey(EdmMember member)
698 if (Helper.IsEntityType(member.DeclaringType) &&
699 Helper.IsEdmProperty(member))
701 return ((EntityType)member.DeclaringType).KeyMembers.Contains(member);
707 // Given a type usage, returns the element type (unwraps collections)
708 internal static TypeUsage GetElementType(TypeUsage typeUsage)
710 if (BuiltInTypeKind.CollectionType == typeUsage.EdmType.BuiltInTypeKind)
712 TypeUsage elementType = ((CollectionType)typeUsage.EdmType).TypeUsage;
713 // recursively unwrap
714 return GetElementType(elementType);
719 internal static int GetLowerBoundOfMultiplicity(RelationshipMultiplicity multiplicity)
721 if (multiplicity == RelationshipMultiplicity.Many ||
722 multiplicity == RelationshipMultiplicity.ZeroOrOne)
732 internal static int? GetUpperBoundOfMultiplicity(RelationshipMultiplicity multiplicity)
734 if (multiplicity == RelationshipMultiplicity.One ||
735 multiplicity == RelationshipMultiplicity.ZeroOrOne)
745 // effects: Returns all the concurrency token members in superType and its subtypes
746 internal static Set<EdmMember> GetConcurrencyMembersForTypeHierarchy(EntityTypeBase superType, EdmItemCollection edmItemCollection)
748 Set<EdmMember> result = new Set<EdmMember>();
749 foreach (StructuralType type in GetTypeAndSubtypesOf(superType, edmItemCollection, true /*includeAbstractTypes */ ))
752 // Go through all the members -- Can call Members instead of AllMembers since we are
753 // running through the whole hierarchy
754 foreach (EdmMember member in type.Members)
756 // check for the concurrency facet
757 ConcurrencyMode concurrencyMode = GetConcurrencyMode(member);
758 if (concurrencyMode == ConcurrencyMode.Fixed)
767 // Determines whether the given member is declared as a concurrency property
768 internal static ConcurrencyMode GetConcurrencyMode(EdmMember member)
770 return GetConcurrencyMode(member.TypeUsage);
773 // Determines whether the given member is declared as a concurrency property
774 internal static ConcurrencyMode GetConcurrencyMode(TypeUsage typeUsage)
776 Facet concurrencyFacet;
777 if (typeUsage.Facets.TryGetValue(EdmProviderManifest.ConcurrencyModeFacetName, false, out concurrencyFacet) &&
778 concurrencyFacet.Value != null)
780 ConcurrencyMode concurrencyMode = (ConcurrencyMode)concurrencyFacet.Value;
781 return concurrencyMode;
783 return ConcurrencyMode.None;
786 // Determines the store generated pattern for this member
787 internal static StoreGeneratedPattern GetStoreGeneratedPattern(EdmMember member)
789 Facet storeGeneratedFacet;
790 if (member.TypeUsage.Facets.TryGetValue(EdmProviderManifest.StoreGeneratedPatternFacetName, false, out storeGeneratedFacet) &&
791 storeGeneratedFacet.Value != null)
793 StoreGeneratedPattern pattern = (StoreGeneratedPattern)storeGeneratedFacet.Value;
796 return StoreGeneratedPattern.None;
800 /// Check if all the SchemaErrors have the serverity of SchemaErrorSeverity.Warning
802 /// <param name="schemaErrors"></param>
803 /// <returns></returns>
804 internal static bool CheckIfAllErrorsAreWarnings(IList<EdmSchemaError> schemaErrors)
806 int length = schemaErrors.Count;
807 for (int i = 0; i < length; ++i)
809 EdmSchemaError error = schemaErrors[i];
810 if (error.Severity != EdmSchemaErrorSeverity.Warning)
821 /// <param name="dictionaryExtentViews"></param>
822 /// <returns></returns>
823 internal static string GenerateHashForAllExtentViewsContent(double schemaVersion, IEnumerable<KeyValuePair<string, string>> extentViews)
825 CompressingHashBuilder builder = new CompressingHashBuilder(CreateMetadataHashAlgorithm(schemaVersion));
826 foreach (var view in extentViews)
828 builder.AppendLine(view.Key);
829 builder.AppendLine(view.Value);
831 return builder.ComputeHash();
834 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:Microsoft.Cryptographic.Standard",
835 Justification = "MD5CryptoServiceProvider is not used for cryptography/security purposes and we do it only for v1 and v1.1 for compatibility reasons.")]
836 internal static HashAlgorithm CreateMetadataHashAlgorithm(double schemaVersion)
838 HashAlgorithm hashAlgorithm;
839 if (schemaVersion < XmlConstants.EdmVersionForV2)
841 // v1 and v1.1 use old hash to remain compatible
842 hashAlgorithm = new MD5CryptoServiceProvider();
846 // v2 and above use a FIPS approved provider
847 // so that when FIPS only is enforced by the OS
849 hashAlgorithm = CreateSHA256HashAlgorithm();
851 return hashAlgorithm;
854 internal static SHA256 CreateSHA256HashAlgorithm()
856 SHA256 sha256HashAlgorith;
859 // use the FIPS compliant SHA256 implementation
860 sha256HashAlgorith = new SHA256CryptoServiceProvider();
862 catch (PlatformNotSupportedException)
864 // the FIPS compliant (and faster) algorith was not available, create the managed version
865 // this will throw if FIPS only is enforced
866 sha256HashAlgorith = new SHA256Managed();
869 return sha256HashAlgorith;
872 internal static TypeUsage ConvertStoreTypeUsageToEdmTypeUsage(TypeUsage storeTypeUsage)
874 TypeUsage edmTypeUsage = storeTypeUsage.GetModelTypeUsage().ShallowCopy(FacetValues.NullFacetValues);
876 // we don't reason the facets during the function resolution any more
882 internal static byte GetPrecision(this TypeUsage type)
884 return type.GetFacetValue<byte>("Precision");
887 internal static byte GetScale(this TypeUsage type)
889 return type.GetFacetValue<byte>("Scale");
892 internal static int GetMaxLength(this TypeUsage type)
894 return type.GetFacetValue<int>("MaxLength");
897 internal static T GetFacetValue<T>(this TypeUsage type, string facetName)
899 return (T)type.Facets[facetName].Value;
901 #region NavigationPropertyAccessor Helpers
903 internal static NavigationPropertyAccessor GetNavigationPropertyAccessor(EntityType sourceEntityType, AssociationEndMember sourceMember, AssociationEndMember targetMember)
905 Debug.Assert(sourceEntityType.DataSpace == DataSpace.OSpace && sourceEntityType.ClrType != null, "sourceEntityType must contain an ospace type");
906 return GetNavigationPropertyAccessor(sourceEntityType, sourceMember.DeclaringType.FullName, sourceMember.Name, targetMember.Name);
909 internal static NavigationPropertyAccessor GetNavigationPropertyAccessor(EntityType entityType, string relationshipType, string fromName, string toName)
911 NavigationProperty navigationProperty;
912 if (entityType.TryGetNavigationProperty(relationshipType, fromName, toName, out navigationProperty))
914 return navigationProperty.Accessor;
918 return NavigationPropertyAccessor.NoNavigationProperty;