//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Mapping { using System; using System.Collections; using System.Collections.Generic; using System.Data.Entity; using System.Data.Metadata.Edm; using System.Diagnostics; using System.Globalization; using System.Linq; /// /// The class creates a default OCMapping between a TypeMetadata in O space /// and an TypeMetadata in Edm space. The loader expects that for each member in /// C space type there exists a member in O space type that has the same name. The member maps will be stored in /// C space member order. /// internal class DefaultObjectMappingItemCollection : MappingItemCollection { #region Constructors /// /// Constrcutor to create an instance of DefaultObjectMappingItemCollection. /// To start with we will create a Schema under which maps will be created. /// /// /// public DefaultObjectMappingItemCollection(EdmItemCollection edmCollection, ObjectItemCollection objectCollection) : base(DataSpace.OCSpace) { EntityUtil.CheckArgumentNull(edmCollection, "edmCollection"); EntityUtil.CheckArgumentNull(objectCollection, "objectCollection"); this.m_edmCollection = edmCollection; this.m_objectCollection = objectCollection; LoadPrimitiveMaps(); } #endregion #region Fields private ObjectItemCollection m_objectCollection; private EdmItemCollection m_edmCollection; private Dictionary clrTypeIndexes = new Dictionary(StringComparer.Ordinal); //Indexes into the type mappings collection based on clr type name private Dictionary cdmTypeIndexes = new Dictionary(StringComparer.Ordinal); //Indexes into the type mappings collection based on clr type name #endregion #region Methods /// /// Search for a Mapping metadata with the specified type key. /// /// identity of the type /// The dataspace that the type for which map needs to be returned belongs to /// true for case-insensitive lookup /// Thrown if mapping space is not valid internal override Map GetMap(string identity, DataSpace typeSpace, bool ignoreCase) { Map map; if (!this.TryGetMap(identity, typeSpace, ignoreCase, out map)) { throw new InvalidOperationException(System.Data.Entity.Strings.Mapping_Object_InvalidType(identity)); } return map; } /// /// Search for a Mapping metadata with the specified type key. /// /// identity of the type /// The dataspace that the type for which map needs to be returned belongs to /// true for case-insensitive lookup /// /// Returns false if no match found. internal override bool TryGetMap(string identity, DataSpace typeSpace, bool ignoreCase, out Map map) { EdmType cdmType = null; EdmType clrType = null; if (typeSpace == DataSpace.CSpace) { if (ignoreCase) { // Get the correct casing of the identity first if we are asked to do ignore case if (!m_edmCollection.TryGetItem(identity, true, out cdmType)) { map = null; return false; } identity = cdmType.Identity; } int index; if (cdmTypeIndexes.TryGetValue(identity, out index)) { map = (Map)this[index]; return true; } if (cdmType != null || m_edmCollection.TryGetItem(identity, ignoreCase, out cdmType)) { // If the mapping is not already loaded, then get the mapping ospace type m_objectCollection.TryGetOSpaceType(cdmType, out clrType); } } else if (typeSpace == DataSpace.OSpace) { if (ignoreCase) { // Get the correct casing of the identity first if we are asked to do ignore case if (!m_objectCollection.TryGetItem(identity, true, out clrType)) { map = null; return false; } identity = clrType.Identity; } int index; if (clrTypeIndexes.TryGetValue(identity, out index)) { map = (Map)this[index]; return true; } if (clrType != null || m_objectCollection.TryGetItem(identity, ignoreCase, out clrType)) { // If the mapping is not already loaded, get the mapping cspace type string cspaceTypeName = ObjectItemCollection.TryGetMappingCSpaceTypeIdentity(clrType); m_edmCollection.TryGetItem(cspaceTypeName, out cdmType); } } if ((clrType == null) || (cdmType == null)) { map = null; return false; } else { map = this.GetDefaultMapping(cdmType, clrType); return true; } } /// /// Search for a Mapping metadata with the specified type key. /// /// identity of the type /// The dataspace that the type for which map needs to be returned belongs to /// Thrown if mapping space is not valid internal override Map GetMap(string identity, DataSpace typeSpace) { return this.GetMap(identity, typeSpace, false /*ignoreCase*/); } /// /// Search for a Mapping metadata with the specified type key. /// /// identity of the type /// The dataspace that the type for which map needs to be returned belongs to /// /// Returns false if no match found. internal override bool TryGetMap(string identity, DataSpace typeSpace, out Map map) { return this.TryGetMap(identity, typeSpace, false /*ignoreCase*/, out map); } /// /// Search for a Mapping metadata with the specified type key. /// /// internal override Map GetMap(GlobalItem item) { EntityUtil.CheckArgumentNull(item, "item"); Map map; if (!this.TryGetMap(item, out map)) { throw new InvalidOperationException(System.Data.Entity.Strings.Mapping_Object_InvalidType(item.Identity)); } return map; } /// /// Search for a Mapping metadata with the specified type key. /// /// /// /// Returns false if no match found. internal override bool TryGetMap(GlobalItem item, out Map map) { if (item == null) { map = null; return false; } DataSpace typeSpace = item.DataSpace; //For transient types just create a map on fly and return EdmType edmType = item as EdmType; if (edmType != null) { if (Helper.IsTransientType(edmType)) { map = GetOCMapForTransientType(edmType, typeSpace); if (map != null) { return true; } else { return false; } } } return this.TryGetMap(item.Identity, typeSpace, out map); } /// /// The method creates a default mapping between two TypeMetadatas - one in /// C space and one in O space. The precondition for calling this method is that /// the type in Object space contains the members with the same name as those of defined in /// C space. It is not required the otherway. /// /// /// private Map GetDefaultMapping(EdmType cdmType, EdmType clrType) { Debug.Assert((cdmType != null) && (clrType != null)); return LoadObjectMapping(cdmType, clrType, this); } private Map GetOCMapForTransientType(EdmType edmType, DataSpace typeSpace) { Debug.Assert(typeSpace == DataSpace.CSpace || typeSpace == DataSpace.OSpace || Helper.IsRowType(edmType) || Helper.IsCollectionType(edmType)); EdmType clrType = null; EdmType cdmType = null; int index = -1; if (typeSpace != DataSpace.OSpace) { if (cdmTypeIndexes.TryGetValue(edmType.Identity, out index)) { return (Map)this[index]; } else { cdmType = edmType; clrType = ConvertCSpaceToOSpaceType(edmType); } } else if (typeSpace == DataSpace.OSpace) { if (clrTypeIndexes.TryGetValue(edmType.Identity, out index)) { return (Map)this[index]; } else { clrType = edmType; cdmType = ConvertOSpaceToCSpaceType(clrType); } } ObjectTypeMapping typeMapping = new ObjectTypeMapping(clrType, cdmType); if (BuiltInTypeKind.RowType == edmType.BuiltInTypeKind) { RowType clrRowType = (RowType)clrType; RowType edmRowType = (RowType)cdmType; Debug.Assert(clrRowType.Properties.Count == edmRowType.Properties.Count, "Property count mismatch"); for (int idx = 0; idx < clrRowType.Properties.Count; idx++) { typeMapping.AddMemberMap(new ObjectPropertyMapping(edmRowType.Properties[idx], clrRowType.Properties[idx])); } } if ( (!cdmTypeIndexes.ContainsKey(cdmType.Identity)) && (!clrTypeIndexes.ContainsKey(clrType.Identity)) ) { AddInternalMapping(typeMapping); } return typeMapping; } /// Convert CSpace TypeMetadata into OSpace TypeMetadata /// /// OSpace type metadata private EdmType ConvertCSpaceToOSpaceType(EdmType cdmType) { EdmType clrType = null; if (Helper.IsCollectionType(cdmType)) { EdmType elemType = ConvertCSpaceToOSpaceType(((CollectionType)cdmType).TypeUsage.EdmType); clrType = new CollectionType(elemType); } else if (Helper.IsRowType(cdmType)) { List clrProperties = new List(); foreach (EdmProperty column in ((RowType)cdmType).Properties) { EdmType clrPropertyType = ConvertCSpaceToOSpaceType(column.TypeUsage.EdmType); EdmProperty clrProperty = new EdmProperty(column.Name, TypeUsage.Create(clrPropertyType)); clrProperties.Add(clrProperty); } clrType = new RowType(clrProperties, ((RowType)cdmType).InitializerMetadata); } else if (Helper.IsRefType(cdmType)) { clrType = new RefType((EntityType)ConvertCSpaceToOSpaceType(((RefType)cdmType).ElementType)); } else if (Helper.IsPrimitiveType(cdmType)) { clrType = m_objectCollection.GetMappedPrimitiveType(((PrimitiveType)cdmType).PrimitiveTypeKind); } else { clrType = ((ObjectTypeMapping)GetMap(cdmType)).ClrType; } Debug.Assert((null != clrType), "null converted clr type"); return clrType; } /// Convert CSpace TypeMetadata into OSpace TypeMetadata /// /// OSpace type metadata private EdmType ConvertOSpaceToCSpaceType(EdmType clrType) { EdmType cdmType = null; if (Helper.IsCollectionType(clrType)) { EdmType elemType = ConvertOSpaceToCSpaceType(((CollectionType)clrType).TypeUsage.EdmType); cdmType = new CollectionType(elemType); } else if (Helper.IsRowType(clrType)) { List cdmProperties = new List(); foreach (EdmProperty column in ((RowType)clrType).Properties) { EdmType cdmPropertyType = ConvertOSpaceToCSpaceType(column.TypeUsage.EdmType); EdmProperty cdmPorperty = new EdmProperty(column.Name, TypeUsage.Create(cdmPropertyType)); cdmProperties.Add(cdmPorperty); } cdmType = new RowType(cdmProperties, ((RowType)clrType).InitializerMetadata); } else if (Helper.IsRefType(clrType)) { cdmType = new RefType((EntityType)(ConvertOSpaceToCSpaceType(((RefType)clrType).ElementType))); } else { cdmType = ((ObjectTypeMapping)GetMap(clrType)).EdmType; } Debug.Assert((null != cdmType), "null converted clr type"); return cdmType; } /// /// checks if the schemaKey refers to the primitive OC mapping schema and if true, /// loads the maps between primitive types /// /// returns the loaded schema if the schema key refers to a primitive schema private void LoadPrimitiveMaps() { // Get all the primitive types from the CSpace and create OCMaps for it IEnumerable cspaceTypes = m_edmCollection.GetPrimitiveTypes(); foreach (PrimitiveType type in cspaceTypes) { PrimitiveType ospaceType = m_objectCollection.GetMappedPrimitiveType(type.PrimitiveTypeKind); Debug.Assert(ospaceType != null, "all primitive type must have been loaded"); this.AddInternalMapping(new ObjectTypeMapping(ospaceType, type)); } } // Add to the cache. If it is already present, then throw an exception private void AddInternalMapping(ObjectTypeMapping objectMap) { string clrName = objectMap.ClrType.Identity; string cdmName = objectMap.EdmType.Identity; int currIndex = this.Count; //Always assume that the first Map for an associated map being added is //the default map for primitive type. Similarly, row and collection types can collide //because their components are primitive types. For other types, //there should be only one map if (clrTypeIndexes.ContainsKey(clrName)) { if (BuiltInTypeKind.PrimitiveType != objectMap.ClrType.BuiltInTypeKind && BuiltInTypeKind.RowType != objectMap.ClrType.BuiltInTypeKind && BuiltInTypeKind.CollectionType != objectMap.ClrType.BuiltInTypeKind) { throw new MappingException(System.Data.Entity.Strings.Mapping_Duplicate_Type(clrName)); } } else { clrTypeIndexes.Add(clrName, currIndex); } if (cdmTypeIndexes.ContainsKey(cdmName)) { if (BuiltInTypeKind.PrimitiveType != objectMap.EdmType.BuiltInTypeKind && BuiltInTypeKind.RowType != objectMap.EdmType.BuiltInTypeKind && BuiltInTypeKind.CollectionType != objectMap.EdmType.BuiltInTypeKind) { throw new MappingException(System.Data.Entity.Strings.Mapping_Duplicate_Type(clrName)); } } else { cdmTypeIndexes.Add(cdmName, currIndex); } objectMap.DataSpace = DataSpace.OCSpace; base.AddInternal (objectMap); } /// /// The method fills up the children of ObjectMapping. It goes through the /// members in CDM type and finds the member in Object space with the same name /// and creates a member map between them. These member maps are added /// as children of the object mapping. /// /// /// /// internal static ObjectTypeMapping LoadObjectMapping(EdmType cdmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection) { Dictionary typeMappings = new Dictionary(StringComparer.Ordinal); ObjectTypeMapping typeMapping = LoadObjectMapping(cdmType, objectType, ocItemCollection, typeMappings); // If DefaultOCMappingItemCollection is not null, add all the type mappings to the item collection if (ocItemCollection != null) { foreach (ObjectTypeMapping map in typeMappings.Values) { ocItemCollection.AddInternalMapping(map); } } return typeMapping; } private static ObjectTypeMapping LoadObjectMapping(EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection, Dictionary typeMappings) { Debug.Assert((edmType != null) && (objectType != null)); Debug.Assert((edmType.BuiltInTypeKind == objectType.BuiltInTypeKind), "The BuiltInTypeKind must be same in LoadObjectMapping"); if (Helper.IsEnumType(edmType) ^ Helper.IsEnumType(objectType)) { throw new MappingException(System.Data.Entity.Strings.Mapping_EnumTypeMappingToNonEnumType(edmType.FullName, objectType.FullName)); } // Check if both the types are abstract or both of them are not if (edmType.Abstract != objectType.Abstract) { throw new MappingException(System.Data.Entity.Strings.Mapping_AbstractTypeMappingToNonAbstractType(edmType.FullName, objectType.FullName)); } ObjectTypeMapping objectTypeMapping = new ObjectTypeMapping(objectType, edmType); typeMappings.Add(edmType.FullName, objectTypeMapping); if (Helper.IsEntityType(edmType) || Helper.IsComplexType(edmType)) { LoadEntityTypeOrComplexTypeMapping(objectTypeMapping, edmType, objectType, ocItemCollection, typeMappings); } else if (Helper.IsEnumType(edmType)) { ValidateEnumTypeMapping((EnumType)edmType, (EnumType)objectType); } else { Debug.Assert(Helper.IsAssociationType(edmType)); LoadAssociationTypeMapping(objectTypeMapping, edmType, objectType, ocItemCollection, typeMappings); } return objectTypeMapping; } /// /// Tries and get the mapping ospace member for the given edmMember and the ospace type /// /// /// /// /// Validates the scalar property on the cspace side and ospace side and creates a new /// ObjectPropertyMapping, if everything maps property /// /// /// /// private static ObjectPropertyMapping LoadScalarPropertyMapping(EdmProperty edmProperty, EdmProperty objectProperty) { Debug.Assert( Helper.IsScalarType(edmProperty.TypeUsage.EdmType), "Only edm scalar properties expected"); Debug.Assert( Helper.IsScalarType(objectProperty.TypeUsage.EdmType), "Only object scalar properties expected"); return new ObjectPropertyMapping(edmProperty, objectProperty); } /// /// Load the entity type or complex type mapping /// /// /// /// /// /// private static void LoadEntityTypeOrComplexTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection, Dictionary typeMappings) { Debug.Assert(edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType, "Expected Type Encountered in LoadEntityTypeOrComplexTypeMapping"); Debug.Assert((edmType.BuiltInTypeKind == objectType.BuiltInTypeKind), "The BuiltInTypeKind must be same in LoadEntityTypeOrComplexTypeMapping"); StructuralType cdmStructuralType = (StructuralType)edmType; StructuralType objectStructuralType = (StructuralType)objectType; ValidateAllMembersAreMapped(cdmStructuralType, objectStructuralType); //Go through the CDMMembers and find the corresponding member in Object space //and create a member map. foreach (EdmMember edmMember in cdmStructuralType.Members) { EdmMember objectMember = GetObjectMember(edmMember, objectStructuralType); ValidateMembersMatch(edmMember, objectMember); if (Helper.IsEdmProperty(edmMember)) { EdmProperty edmPropertyMember = (EdmProperty)edmMember; EdmProperty edmPropertyObject = (EdmProperty)objectMember; //Depending on the type of member load the member mapping i.e. For complex //members we have to go in and load the child members of the Complex type. if (Helper.IsComplexType(edmMember.TypeUsage.EdmType)) { objectMapping.AddMemberMap( LoadComplexMemberMapping(edmPropertyMember, edmPropertyObject, ocItemCollection, typeMappings)); } else { objectMapping.AddMemberMap( LoadScalarPropertyMapping(edmPropertyMember, edmPropertyObject)); } } else { Debug.Assert(edmMember.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty, "Unexpected Property type encountered"); // For navigation properties, we need to make sure the relationship type on the navigation property is mapped NavigationProperty navigationProperty = (NavigationProperty)edmMember; NavigationProperty objectNavigationProperty = (NavigationProperty)objectMember; LoadTypeMapping(navigationProperty.RelationshipType, objectNavigationProperty.RelationshipType, ocItemCollection, typeMappings); objectMapping.AddMemberMap(new ObjectNavigationPropertyMapping(navigationProperty, objectNavigationProperty)); } } } private static void ValidateAllMembersAreMapped(StructuralType cdmStructuralType, StructuralType objectStructuralType) { Debug.Assert(cdmStructuralType.BuiltInTypeKind == objectStructuralType.BuiltInTypeKind, "the types must be the same"); // error if they don't have the same required members, or if // some object concepts don't exist in cspace (it is ok if the ospace is missing some cspace concepts) if (cdmStructuralType.Members.Count != objectStructuralType.Members.Count) { throw new MappingException(System.Data.Entity.Strings.Mapping_Default_OCMapping_Member_Count_Mismatch( cdmStructuralType.FullName, objectStructuralType.FullName)); } foreach (EdmMember member in objectStructuralType.Members) { if(!cdmStructuralType.Members.Contains(member.Identity)) { throw new MappingException(System.Data.Entity.Strings.Mapping_Default_OCMapping_Clr_Member2( member.Name, objectStructuralType.FullName, cdmStructuralType.FullName)); } } } /// /// Validates whether CSpace enum type and OSpace enum type match. /// /// CSpace enum type. /// OSpace enum type. private static void ValidateEnumTypeMapping(EnumType edmEnumType, EnumType objectEnumType) { Debug.Assert(edmEnumType != null, "edmEnumType != null"); Debug.Assert(Helper.IsPrimitiveType(edmEnumType.UnderlyingType)); Debug.Assert(Helper.IsSupportedEnumUnderlyingType(edmEnumType.UnderlyingType.PrimitiveTypeKind)); Debug.Assert(objectEnumType != null, "objectEnumType != null"); Debug.Assert(Helper.IsPrimitiveType(objectEnumType.UnderlyingType)); Debug.Assert(Helper.IsSupportedEnumUnderlyingType(objectEnumType.UnderlyingType.PrimitiveTypeKind)); if (edmEnumType.UnderlyingType.PrimitiveTypeKind != objectEnumType.UnderlyingType.PrimitiveTypeKind) { throw new MappingException( System.Data.Entity.Strings.Mapping_Enum_OCMapping_UnderlyingTypesMismatch( edmEnumType.UnderlyingType.Name, edmEnumType.FullName, objectEnumType.UnderlyingType.Name, objectEnumType.FullName)); } // EnumMember.Value is just a number so sorting by value is faster than by the name. // The drawback is that there can be multiple members with the same value. To break // the tie we need to sort by name after sorting by value. var edmEnumTypeMembersSortedEnumerator = edmEnumType.Members.OrderBy(m => Convert.ToInt64(m.Value, CultureInfo.InvariantCulture)).ThenBy(m => m.Name).GetEnumerator(); var objectEnumTypeMembersSortedEnumerator = objectEnumType.Members.OrderBy(m => Convert.ToInt64(m.Value, CultureInfo.InvariantCulture)).ThenBy(m => m.Name).GetEnumerator(); if (edmEnumTypeMembersSortedEnumerator.MoveNext()) { while (objectEnumTypeMembersSortedEnumerator.MoveNext()) { if (edmEnumTypeMembersSortedEnumerator.Current.Name == objectEnumTypeMembersSortedEnumerator.Current.Name && edmEnumTypeMembersSortedEnumerator.Current.Value.Equals(objectEnumTypeMembersSortedEnumerator.Current.Value)) { if (!edmEnumTypeMembersSortedEnumerator.MoveNext()) { return; } } } throw new MappingException( System.Data.Entity.Strings.Mapping_Enum_OCMapping_MemberMismatch( objectEnumType.FullName, edmEnumTypeMembersSortedEnumerator.Current.Name, edmEnumTypeMembersSortedEnumerator.Current.Value, edmEnumType.FullName)); } } /// /// Loads Association Type Mapping /// /// /// /// /// /// private static void LoadAssociationTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection, Dictionary typeMappings) { Debug.Assert(edmType.BuiltInTypeKind == BuiltInTypeKind.AssociationType, "Expected Type Encountered in LoadAssociationTypeMapping"); Debug.Assert((edmType.BuiltInTypeKind == objectType.BuiltInTypeKind), "The BuiltInTypeKind must be same in LoadAssociationTypeMapping"); AssociationType association = (AssociationType)edmType; AssociationType objectAssociation = (AssociationType)objectType; foreach (AssociationEndMember edmEnd in association.AssociationEndMembers) { AssociationEndMember objectEnd = (AssociationEndMember)GetObjectMember(edmEnd, objectAssociation); ValidateMembersMatch(edmEnd, objectEnd); if (edmEnd.RelationshipMultiplicity != objectEnd.RelationshipMultiplicity) { throw new MappingException(System.Data.Entity.Strings.Mapping_Default_OCMapping_MultiplicityMismatch( edmEnd.RelationshipMultiplicity, edmEnd.Name, association.FullName, objectEnd.RelationshipMultiplicity, objectEnd.Name, objectAssociation.FullName)); } Debug.Assert(edmEnd.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "Ends must be of Ref type"); // GetMap for the entity types for the ends of the relationship type to make sure // the entity type mentioned are valid LoadTypeMapping(((RefType)edmEnd.TypeUsage.EdmType).ElementType, ((RefType)objectEnd.TypeUsage.EdmType).ElementType, ocItemCollection, typeMappings); objectMapping.AddMemberMap(new ObjectAssociationEndMapping(edmEnd, objectEnd)); } } /// /// The method loads the EdmMember mapping for complex members. /// It goes through the CDM members of the Complex Cdm type and /// tries to find the corresponding members in Complex Clr type. /// /// /// /// /// /// private static ObjectComplexPropertyMapping LoadComplexMemberMapping(EdmProperty containingEdmMember, EdmProperty containingClrMember, DefaultObjectMappingItemCollection ocItemCollection, Dictionary typeMappings) { Debug.Assert(containingEdmMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType, "edm member declaringType must be of complexType"); Debug.Assert(containingClrMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType, "clr member declaringType must be of complexType"); ComplexType edmComplexType = (ComplexType)containingEdmMember.TypeUsage.EdmType; ComplexType objectComplexType = (ComplexType)containingClrMember.TypeUsage.EdmType; // Get the type mapping for the complex type ObjectTypeMapping complexTypeMapping = LoadTypeMapping(edmComplexType, objectComplexType, ocItemCollection, typeMappings); //Go through the CDMMembers and find the corresponding member in Object space //and create a member map. return new ObjectComplexPropertyMapping(containingEdmMember, containingClrMember, complexTypeMapping); } private static ObjectTypeMapping LoadTypeMapping(EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection, Dictionary typeMappings) { ObjectTypeMapping objectTypeMapping; //First, check in the type mappings to find out if the mapping is already present if (typeMappings.TryGetValue(edmType.FullName, out objectTypeMapping)) { return objectTypeMapping; } if (ocItemCollection != null) { ObjectTypeMapping typeMapping; if (ocItemCollection.ContainsMap(edmType, out typeMapping)) { return (ObjectTypeMapping)typeMapping; } } // If the type mapping is not already loaded, then load it return LoadObjectMapping(edmType, objectType, ocItemCollection, typeMappings); } private bool ContainsMap(GlobalItem cspaceItem, out ObjectTypeMapping map) { Debug.Assert(cspaceItem.DataSpace == DataSpace.CSpace, "ContainsMap: It must be a CSpace item"); int index; if (cdmTypeIndexes.TryGetValue(cspaceItem.Identity, out index)) { map = (ObjectTypeMapping)this[index]; return true; } map = null; return false; } #endregion } }