/// <summary>
        /// Loads Association Type Mapping
        /// </summary>
        /// <param name="objectMapping"></param>
        /// <param name="edmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection"></param>
        /// <param name="typeMappings"></param>
        private static void LoadAssociationTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType,
                                                       DefaultObjectMappingItemCollection ocItemCollection, Dictionary <string, ObjectTypeMapping> 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));
            }
        }
        /// <summary>
        /// Load the entity type or complex type mapping
        /// </summary>
        /// <param name="objectMapping"></param>
        /// <param name="edmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection">
        /// <param name="typeMappings"></param></param>
        private static void LoadEntityTypeOrComplexTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType,
                                                               DefaultObjectMappingItemCollection ocItemCollection, Dictionary <string, ObjectTypeMapping> 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));
                }
            }
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="containingEdmMember"></param>
        /// <param name="containingClrMember"></param>
        /// <param name="ocItemCollection"></param>
        /// <param name="typeMappings"></param>
        /// <returns></returns>
        private static ObjectComplexPropertyMapping LoadComplexMemberMapping(EdmProperty containingEdmMember, EdmProperty containingClrMember,
                                                                             DefaultObjectMappingItemCollection ocItemCollection, Dictionary <string, ObjectTypeMapping> 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 <string, ObjectTypeMapping> 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 static ObjectTypeMapping LoadObjectMapping(EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection,
                                                           Dictionary <string, ObjectTypeMapping> 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);
        }
        private static ObjectTypeMapping LoadTypeMapping(EdmType edmType, EdmType objectType, 
            DefaultObjectMappingItemCollection ocItemCollection, Dictionary<string, ObjectTypeMapping> 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);
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="cdmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection"></param>
        internal static ObjectTypeMapping LoadObjectMapping(EdmType cdmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection)
        {
            Dictionary <string, ObjectTypeMapping> typeMappings = new Dictionary <string, ObjectTypeMapping>(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);
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="containingEdmMember"></param>
        /// <param name="containingClrMember"></param>
        /// <param name="ocItemCollection"></param>
        /// <param name="typeMappings"></param>
        /// <returns></returns>
        private static ObjectComplexPropertyMapping LoadComplexMemberMapping(EdmProperty containingEdmMember, EdmProperty containingClrMember,
            DefaultObjectMappingItemCollection ocItemCollection, Dictionary<string, ObjectTypeMapping> 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);
        }
        /// <summary>
        /// Loads Association Type Mapping
        /// </summary>
        /// <param name="objectMapping"></param>
        /// <param name="edmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection"></param>
        /// <param name="typeMappings"></param>
        private static void LoadAssociationTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType,
            DefaultObjectMappingItemCollection ocItemCollection, Dictionary<string, ObjectTypeMapping> 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));
            }
        }
        /// <summary>
        /// Load the entity type or complex type mapping
        /// </summary>
        /// <param name="objectMapping"></param>
        /// <param name="edmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection">
        /// <param name="typeMappings"></param></param>
        private static void LoadEntityTypeOrComplexTypeMapping(ObjectTypeMapping objectMapping, EdmType edmType, EdmType objectType,
            DefaultObjectMappingItemCollection ocItemCollection, Dictionary<string, ObjectTypeMapping> 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 ObjectTypeMapping LoadObjectMapping(EdmType edmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection,
            Dictionary<string, ObjectTypeMapping> 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;
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="cdmType"></param>
        /// <param name="objectType"></param>
        /// <param name="ocItemCollection"></param>
        internal static ObjectTypeMapping LoadObjectMapping(EdmType cdmType, EdmType objectType, DefaultObjectMappingItemCollection ocItemCollection)
        {
            Dictionary<string, ObjectTypeMapping> typeMappings = new Dictionary<string, ObjectTypeMapping>(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;
        }