Converter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Metadata / Converter.cs / 1305376 / Converter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Data.Common; 
using System.Diagnostics;
using System.Data.Objects.DataClasses;
using System.Collections.Generic;
using System.Globalization; 
using System.Text;
using System.Linq; 
 
namespace System.Data.Metadata.Edm
{ 
    /// 
    /// Helper Class for converting SOM objects to metadata objects
    /// This class should go away once we have completely integrated SOM and metadata
    ///  
    internal static class Converter
    { 
        #region Constructor 
        /// 
        /// Static constructor for creating FacetDescription objects that we use 
        /// 
        static Converter()
        {
            // Create the enum types that we will need 
            EnumType concurrencyModeType = new EnumType(EdmProviderManifest.ConcurrencyModeFacetName,
                                                        EdmConstants.EdmNamespace, 
                                                        DataSpace.CSpace); 
            foreach (string name in Enum.GetNames(typeof(ConcurrencyMode)))
            { 
                concurrencyModeType.AddMember(new EnumMember(name));
            }
            EnumType storeGeneratedPatternType = new EnumType(EdmProviderManifest.StoreGeneratedPatternFacetName,
                                                              EdmConstants.EdmNamespace, 
                                                              DataSpace.CSpace);
            foreach (string name in Enum.GetNames(typeof(StoreGeneratedPattern))) 
            { 
                storeGeneratedPatternType.AddMember(new EnumMember(name));
            } 


            // Now create the facet description objects
            ConcurrencyModeFacet = new FacetDescription(EdmProviderManifest.ConcurrencyModeFacetName, 
                                                        concurrencyModeType,
                                                        null, 
                                                        null, 
                                                        ConcurrencyMode.None);
            StoreGeneratedPatternFacet = new FacetDescription(EdmProviderManifest.StoreGeneratedPatternFacetName, 
                                                              storeGeneratedPatternType,
                                                              null,
                                                              null,
                                                              StoreGeneratedPattern.None); 
            CollationFacet = new FacetDescription(EdmProviderManifest.CollationFacetName,
                                                  MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String), 
                                                  null, 
                                                  null,
                                                  string.Empty); 
        }
        #endregion

        #region Fields 
        internal static readonly FacetDescription ConcurrencyModeFacet;
        internal static readonly FacetDescription StoreGeneratedPatternFacet; 
        internal static readonly FacetDescription CollationFacet; 

        #endregion 

        #region Methods
        /// 
        /// Converts a schema from SOM into Metadata 
        /// 
        /// The SOM schema to convert 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        internal static IEnumerable ConvertSchema(Som.Schema somSchema, 
                                                              DbProviderManifest providerManifest,
                                                              ItemCollection itemCollection)
        {
            Dictionary newGlobalItems = new Dictionary(); 
            ConvertSchema(somSchema, providerManifest, new ConversionCache(itemCollection), newGlobalItems);
            return newGlobalItems.Values; 
        } 

        internal static IEnumerable ConvertSchema(IList somSchemas, 
                                                              DbProviderManifest providerManifest,
                                                              ItemCollection itemCollection)
        {
            Dictionary newGlobalItems = new Dictionary(); 
            ConversionCache conversionCache = new ConversionCache(itemCollection);
 
            foreach (Som.Schema somSchema in somSchemas) 
            {
                ConvertSchema(somSchema, providerManifest, conversionCache, newGlobalItems); 
            }

            return newGlobalItems.Values;
        } 

        private static void ConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, 
            ConversionCache convertedItemCache, Dictionary newGlobalItems) 
        {
            List funcsWithUnresolvedTypes = new List(); 
            foreach (Som.SchemaType element in somSchema.SchemaTypes)
            {
                if (null == LoadSchemaElement(element, providerManifest, convertedItemCache, newGlobalItems))
                { 
                    if (element is Som.Function)
                    { 
                        funcsWithUnresolvedTypes.Add(element as Som.Function); 
                    }
                } 
            }

            foreach (Som.SchemaEntityType element in somSchema.SchemaTypes.OfType())
            { 
                LoadEntityTypePhase2(element, providerManifest, convertedItemCache, newGlobalItems);
            } 
 
            foreach (var function in funcsWithUnresolvedTypes)
            { 
                if (null == LoadSchemaElement(function, providerManifest, convertedItemCache, newGlobalItems))
                {
                    Debug.Fail("Could not load model function definition"); //this should never happen.
                } 
            }
 
            if (convertedItemCache.ItemCollection.DataSpace == DataSpace.CSpace) 
            {
                EdmItemCollection edmCollection = (EdmItemCollection)convertedItemCache.ItemCollection; 
                //Get the version of the SomSchema and update the EdmVersion to be the Maximum of all the
                //versions of the schemas that are being loaded in this item collection.
                edmCollection.EdmVersion = Math.Max(somSchema.SchemaVersion, edmCollection.EdmVersion);
            } 
            else
            { 
                Debug.Assert(convertedItemCache.ItemCollection.DataSpace == DataSpace.SSpace, "Did you add a new space?"); 
                // when converting the ProviderManifest, the DataSpace is SSpace, but the ItemCollection is EmptyItemCollection,
                // not StoreItemCollection 
                StoreItemCollection storeCollection = convertedItemCache.ItemCollection as StoreItemCollection;
                if (storeCollection != null)
                {
                    storeCollection.SchemaVersion = Math.Max(somSchema.SchemaVersion, storeCollection.SchemaVersion); 
                }
            } 
        } 

        ///  
        /// Loads a schema element
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The item resulting from the load 
        internal static MetadataItem LoadSchemaElement(Som.SchemaType element,
                                              DbProviderManifest providerManifest, 
                                              ConversionCache convertedItemCache,
                                              Dictionary newGlobalItems)
        {
            Debug.Assert(providerManifest != null, "This will make the dataspace to be default SSpace"); 
            // Try to fetch from the collection first
            GlobalItem item; 
 
            Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(element.FQName, false, out item), "Som should have checked for duplicate items");
 
            // Try to fetch in our collection of new GlobalItems
            if (newGlobalItems.TryGetValue(element, out item))
            {
                return item; 
            }
 
            Som.EntityContainer entityContainer = element as Som.EntityContainer; 
            // Perform different conversion depending on the type of the SOM object
            if (entityContainer!=null) 
            {
                item = ConvertToEntityContainer(entityContainer,
                                                providerManifest,
                                                convertedItemCache, 
                                                newGlobalItems);
            } 
            else if (element is Som.SchemaEntityType) 
            {
                item = ConvertToEntityType((Som.SchemaEntityType)element, 
                                           providerManifest,
                                           convertedItemCache,
                                           newGlobalItems);
            } 
            else if (element is Som.Relationship)
            { 
                item = ConvertToAssociationType((Som.Relationship)element, 
                                                providerManifest,
                                                convertedItemCache, 
                                                newGlobalItems);
            }
            else if (element is Som.SchemaComplexType)
            { 
                item = ConvertToComplexType((Som.SchemaComplexType)element,
                                            providerManifest, 
                                            convertedItemCache, 
                                            newGlobalItems);
            } 
            else if (element is Som.Function)
            {
                item = ConvertToFunction((Som.Function)element, providerManifest,
                    convertedItemCache, null, newGlobalItems); 
            }
            else 
            { 
                // the only type we don't handle is the ProviderManifest TypeElement
                // if it is anything else, it is probably a mistake 
                Debug.Assert(element is Som.TypeElement &&
                    element.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel,
                    "Unknown Type in somschema");
                return null; 
            }
 
            return item; 
        }
 
        /// 
        /// Converts an entity container from SOM to metadata
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The entity container object resulting from the convert
        private static EntityContainer ConvertToEntityContainer(Som.EntityContainer element, 
                                                                DbProviderManifest providerManifest,
                                                                ConversionCache convertedItemCache,
                                                                Dictionary newGlobalItems)
        { 
            // Creating a new entity container object and populate with converted entity set objects
            EntityContainer entityContainer = new EntityContainer(element.Name, GetDataSpace(providerManifest)); 
            newGlobalItems.Add(element, entityContainer); 

            foreach (Som.EntityContainerEntitySet entitySet in element.EntitySets) 
            {
                entityContainer.AddEntitySetBase(ConvertToEntitySet(entitySet,
                                                                      entityContainer.Name,
                                                                      providerManifest, 
                                                                      convertedItemCache,
                                                                      newGlobalItems)); 
            } 

            // Populate with converted relationship set objects 
            foreach (Som.EntityContainerRelationshipSet relationshipSet in element.RelationshipSets)
            {
                Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association,
                             "We do not support containment set"); 

                entityContainer.AddEntitySetBase(ConvertToAssociationSet(relationshipSet, 
                                                                           providerManifest, 
                                                                           convertedItemCache,
                                                                           entityContainer, 
                                                                           newGlobalItems));
            }

            // Populate with converted function imports 
            foreach (Som.Function functionImport in element.FunctionImports)
            { 
                entityContainer.AddFunctionImport(ConvertToFunction(functionImport, 
                    providerManifest, convertedItemCache, entityContainer, newGlobalItems));
            } 

            // Extract the optional Documentation
            if (element.Documentation != null)
            { 
                entityContainer.Documentation = ConvertToDocumentation(element.Documentation);
            } 
 
            AddOtherContent(element, entityContainer);
 
            return entityContainer;
        }

        ///  
        /// Converts an entity type from SOM to metadata
        /// 
        /// This method should only build the internally contained and vertical part of the EntityType (keys, properties, and base types) but not 
        /// sideways parts (NavigationProperties) that go between types or we risk trying to access and EntityTypes keys, from the referenctial constraint,
        /// before the base type, which has the keys, is setup yet. 
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The entity type object resulting from the convert 
        private static EntityType ConvertToEntityType(Som.SchemaEntityType element, 
                                                      DbProviderManifest providerManifest,
                                                      ConversionCache convertedItemCache, 
                                                      Dictionary newGlobalItems)
        {
            string[] keyMembers = null;
            // Check if this type has keys 
            if (element.DeclaredKeyProperties.Count != 0)
            { 
                keyMembers = new string[element.DeclaredKeyProperties.Count]; 
                for (int i = 0; i < keyMembers.Length; i++)
                { 
                    //Add the name of the key property to the list of
                    //key properties
                    keyMembers[i] = (element.DeclaredKeyProperties[i].Property.Name);
                } 
            }
 
            EdmProperty[] properties = new EdmProperty[element.Properties.Count]; 
            int index = 0;
 
            foreach (Som.StructuredProperty somProperty in element.Properties)
            {
                properties[index++] = ConvertToProperty(somProperty,
                                                        providerManifest, 
                                                        convertedItemCache,
                                                        newGlobalItems); 
            } 

            EntityType entityType = new EntityType(element.Name, 
                                                   element.Namespace,
                                                   GetDataSpace(providerManifest),
                                                   keyMembers,
                                                   properties); 

            if (element.BaseType != null) 
            { 
                entityType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
                                                                  providerManifest, 
                                                                  convertedItemCache,
                                                                  newGlobalItems));
            }
 
            // set the abstract and sealed type values for the entity type
            entityType.Abstract = element.IsAbstract; 
            // Extract the optional Documentation 
            if (element.Documentation != null)
            { 
                entityType.Documentation = ConvertToDocumentation(element.Documentation);
            }
            AddOtherContent(element, entityType);
            newGlobalItems.Add(element, entityType); 
            return entityType;
        } 
 
        private static void LoadEntityTypePhase2(Som.SchemaEntityType element,
                                                      DbProviderManifest providerManifest, 
                                                      ConversionCache convertedItemCache,
                                                      Dictionary newGlobalItems)
        {
            EntityType entityType = (EntityType)newGlobalItems[element]; 

            // Since Navigation properties are internal and not part of member collection, we 
            // need to initialize the base class first before we start adding the navigation property 
            // this will ensure that all the base navigation properties are initialized
            foreach (Som.NavigationProperty somNavigationProperty in element.NavigationProperties) 
            {
                entityType.AddMember(ConvertToNavigationProperty(entityType,
                                                                 somNavigationProperty,
                                                                 providerManifest, 
                                                                 convertedItemCache,
                                                                 newGlobalItems)); 
            } 
        }
 
        /// 
        /// Converts an complex type from SOM to metadata
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The complex type object resulting from the convert
        private static ComplexType ConvertToComplexType(Som.SchemaComplexType element, 
                                                        DbProviderManifest providerManifest,
                                                        ConversionCache convertedItemCache,
                                                        Dictionary newGlobalItems)
        { 
            ComplexType complexType = new ComplexType(element.Name,
                                                      element.Namespace, 
                                                      GetDataSpace(providerManifest)); 
            newGlobalItems.Add(element, complexType);
 
            foreach (Som.StructuredProperty somProperty in element.Properties)
            {
                complexType.AddMember(ConvertToProperty(somProperty,
                                                          providerManifest, 
                                                          convertedItemCache,
                                                          newGlobalItems)); 
            } 

            // set the abstract and sealed type values for the entity type 
            complexType.Abstract = element.IsAbstract;

            if (element.BaseType != null)
            { 
                complexType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
                                                                  providerManifest, 
                                                                  convertedItemCache, 
                                                                  newGlobalItems));
            } 

            // Extract the optional Documentation
            if (element.Documentation != null)
            { 
                complexType.Documentation = ConvertToDocumentation(element.Documentation);
            } 
            AddOtherContent(element, complexType); 

            return complexType; 
        }

        /// 
        /// Converts an association type from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The association type object resulting from the convert
        private static AssociationType ConvertToAssociationType(Som.Relationship element,
                                                                DbProviderManifest providerManifest,
                                                                ConversionCache convertedItemCache, 
                                                                Dictionary newGlobalItems)
        { 
            Debug.Assert(element.RelationshipKind == RelationshipKind.Association); 

            AssociationType associationType = new AssociationType(element.Name, 
                                                                  element.Namespace,
                                                                  element.IsForeignKey,
                                                                  GetDataSpace(providerManifest));
            newGlobalItems.Add(element, associationType); 

            foreach (Som.RelationshipEnd end in element.Ends) 
            { 
                Som.SchemaType entityTypeElement = end.Type;
                EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement, 
                                                                providerManifest,
                                                                convertedItemCache,
                                                                newGlobalItems);
 
                AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType);
                AddOtherContent(end, endMember); 
                // Loop through and convert the operations 
                foreach (Som.OnOperation operation in end.Operations)
                { 
                    // Process only the ones that we recognize
                    if (operation.Operation != Som.Operation.Delete)
                    {
                        continue; 
                    }
 
                    // Determine the action for this operation 
                    OperationAction action = OperationAction.None;
                    switch (operation.Action) 
                    {
                        case Som.Action.Cascade:
                            action = OperationAction.Cascade;
                            break; 
                        case Som.Action.None:
                            action = OperationAction.None; 
                            break; 
                        default:
                            Debug.Fail("Operation action not supported."); 
                            break;
                    }
                    endMember.DeleteBehavior = action;
                } 

                // Extract optional Documentation hanging off the end element 
                if (end.Documentation != null) 
                {
                    endMember.Documentation = ConvertToDocumentation(end.Documentation); 
                }
            }

            Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized"); 

            for (int i = 0; i < element.Constraints.Count; i++) 
            { 
                Som.ReferentialConstraint constraint = element.Constraints[i];
                AssociationEndMember fromMember = (AssociationEndMember) associationType.Members[constraint.PrincipalRole.Name]; 
                AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name];
                EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType;
                EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType;
 
                ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember,
                                                                                        GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties), 
                                                                                        GetProperties(toEntityType, constraint.DependentRole.RoleProperties)); 

                // Attach the optional Documentation 
                if (constraint.Documentation != null)
                    referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation);
                if (constraint.PrincipalRole.Documentation != null)
                    referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation); 
                if (constraint.DependentRole.Documentation != null)
                    referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation); 
 

                associationType.AddReferentialConstraint(referentialConstraint); 
                AddOtherContent(element.Constraints[i], referentialConstraint);

            }
 
            // Extract the optional Documentation
            if (element.Documentation != null) 
            { 
                associationType.Documentation = ConvertToDocumentation(element.Documentation);
            } 
            AddOtherContent(element, associationType);

            return associationType;
        } 

        ///  
        /// Initialize the end member if its not initialized already 
        /// 
        ///  
        /// 
        /// 
        private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end,
            EntityType endMemberType) 
        {
            AssociationEndMember associationEnd; 
 
            EdmMember member;
            // make sure that the end is not initialized as of yet 
            if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member))
            {
                // Create the end member and add the operations
                associationEnd = new AssociationEndMember(end.Name, 
                                                          endMemberType.GetReferenceType(),
                                                          end.Multiplicity.Value); 
                associationType.AddKeyMember(associationEnd); 
            }
            else 
            {
                associationEnd = (AssociationEndMember)member;
            }
 
            //Extract the optional Documentation
            Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd; 
 
            if (relationshipEnd != null && (relationshipEnd.Documentation != null))
            { 
                associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation);
            }

            return associationEnd; 
        }
 
        private static EdmProperty[] GetProperties(EntityTypeBase entityType, IList properties) 
        {
            Debug.Assert(properties.Count != 0); 
            EdmProperty[] result = new EdmProperty[properties.Count];

            for (int i = 0; i < properties.Count; i++)
            { 
                result[i] = (EdmProperty) entityType.Members[properties[i].Name];
            } 
 
            return result;
        } 


        private static void AddOtherContent(Som.SchemaElement element, MetadataItem item)
        { 
            if (element.OtherContent.Count > 0)
            { 
                item.AddMetadataProperties(element.OtherContent); 
            }
        } 

        /// 
        /// Converts an entity set from SOM to metadata
        ///  
        /// The SOM element to process
        /// the name of the container this will be added to 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The entity set object resulting from the convert
        private static EntitySet ConvertToEntitySet(Som.EntityContainerEntitySet set,
                                                    string containerName,
                                                    DbProviderManifest providerManifest, 
                                                    ConversionCache convertedItemCache,
                                                    Dictionary newGlobalItems) 
        { 
            EntitySet entitySet = new EntitySet(set.Name,set.DbSchema,set.Table, set.DefiningQuery,
                                                 (EntityType)LoadSchemaElement(set.EntityType, 
                                                                               providerManifest,
                                                                               convertedItemCache,
                                                                               newGlobalItems));
 
            // Extract the optional Documentation
            if (set.Documentation != null) 
            { 
                entitySet.Documentation = ConvertToDocumentation(set.Documentation);
            } 
            AddOtherContent(set, entitySet);

            return entitySet;
        } 

        ///  
        /// Converts an entity set from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// 
        /// The entity set object resulting from the convert
        private static EntitySet GetEntitySet(Som.EntityContainerEntitySet set, EntityContainer container)
        { 
            return container.GetEntitySetByName(set.Name, false);
        } 
 
        /// 
        /// Converts an association set from SOM to metadata 
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        ///  
        /// The association set object resulting from the convert 
        private static AssociationSet ConvertToAssociationSet(Som.EntityContainerRelationshipSet relationshipSet,
                                                              DbProviderManifest providerManifest, 
                                                              ConversionCache convertedItemCache,
                                                              EntityContainer container,
                                                              Dictionary newGlobalItems)
        { 
            Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association);
 
            AssociationType associationType = (AssociationType)LoadSchemaElement((Som.SchemaType)relationshipSet.Relationship, 
                                                                                  providerManifest,
                                                                                  convertedItemCache, 
                                                                                  newGlobalItems);

            AssociationSet associationSet = new AssociationSet(relationshipSet.Name, associationType);
 
            foreach (Som.EntityContainerRelationshipSetEnd end in relationshipSet.Ends)
            { 
                //-- need the EntityType for the end 
                EntityType endEntityType = (EntityType)LoadSchemaElement(end.EntitySet.EntityType,
                                                                         providerManifest, 
                                                                         convertedItemCache,
                                                                         newGlobalItems);
                //-- need to get the end member
                AssociationEndMember endMember = (AssociationEndMember) associationType.Members[end.Name]; 
                //-- create the end
                AssociationSetEnd associationSetEnd = new AssociationSetEnd(GetEntitySet(end.EntitySet, container), 
                                                                            associationSet, 
                                                                            endMember);
 
                AddOtherContent(end, associationSetEnd);
                associationSet.AddAssociationSetEnd(associationSetEnd);

                // Extract optional Documentation hanging off the end element 
                if (end.Documentation != null)
                { 
                    associationSetEnd.Documentation = ConvertToDocumentation(end.Documentation); 
                }
            } 

            // Extract the optional Documentation
            if (relationshipSet.Documentation != null)
            { 
                associationSet.Documentation = ConvertToDocumentation(relationshipSet.Documentation);
            } 
            AddOtherContent(relationshipSet, associationSet); 

            return associationSet; 
        }

        /// 
        /// Converts a property from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The property object resulting from the convert
        private static EdmProperty ConvertToProperty(Som.StructuredProperty somProperty,
                                                  DbProviderManifest providerManifest,
                                                  ConversionCache convertedItemCache, 
                                                  Dictionary newGlobalItems)
        { 
            EdmProperty property; 

            // Get the appropriate type object for this type, for primitive types, get the facet values for the primitive type 
            // property as a type usage object as well
            TypeUsage typeUsage = null;

            Som.ScalarType scalarType = somProperty.Type as Som.ScalarType; 
            if (scalarType != null)
            { 
                if (somProperty.Schema.DataModel == Som.SchemaDataModelOption.EntityDataModel) 
                {
                    // csdl 
                    typeUsage = GetCsdlPrimitiveTypeUsageWithFacets(somProperty, convertedItemCache);
                }
                else
                { 
                    // parsing ssdl
                    typeUsage = somProperty.TypeUsage; 
                    UpdateSentinelValuesInFacets(ref typeUsage); 
                }
            } 
            else
            {
                EdmType propertyType = (EdmType)LoadSchemaElement(somProperty.Type, providerManifest, convertedItemCache, newGlobalItems);
                if (somProperty.CollectionKind != CollectionKind.None) 
                {
                    propertyType = new CollectionType(propertyType); 
                } 
                typeUsage = TypeUsage.Create(propertyType);
            } 

            PopulateGeneralFacets(somProperty, providerManifest, ref typeUsage);
            property = new EdmProperty(somProperty.Name, typeUsage);
 
            // Extract the optional Documentation
            if (somProperty.Documentation != null) 
            { 
                property.Documentation = ConvertToDocumentation(somProperty.Documentation);
            } 
            AddOtherContent(somProperty, property);

            return property;
        } 

        ///  
        /// Converts a navigation property from SOM to metadata 
        /// 
        /// entity type on which this navigation property was declared 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The property object resulting from the convert
        private static NavigationProperty ConvertToNavigationProperty(EntityType declaringEntityType, 
                                                                      Som.NavigationProperty somNavigationProperty, 
                                                                      DbProviderManifest providerManifest,
                                                                      ConversionCache convertedItemCache, 
                                                                      Dictionary newGlobalItems)
        {
            // Navigation properties cannot be primitive types, so we can ignore the possibility of having primitive type
            // facets 
            EntityType toEndEntityType = (EntityType)LoadSchemaElement(somNavigationProperty.Type,
                                                      providerManifest, 
                                                      convertedItemCache, 
                                                      newGlobalItems);
 
            EdmType edmType = toEndEntityType;

            // Also load the relationship Type that this navigation property represents
            AssociationType relationshipType = (AssociationType)LoadSchemaElement((Som.Relationship)somNavigationProperty.Relationship, 
                    providerManifest, convertedItemCache, newGlobalItems);
 
            Som.IRelationshipEnd somRelationshipEnd = null; 
            somNavigationProperty.Relationship.TryGetEnd(somNavigationProperty.ToEnd.Name, out somRelationshipEnd);
            if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.Many) 
            {
                edmType = toEndEntityType.GetCollectionType();
            }
            else 
            {
                Debug.Assert(somRelationshipEnd.Multiplicity != RelationshipMultiplicity.Many); 
                edmType = toEndEntityType; 
            }
 
            TypeUsage typeUsage;
            if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.One)
            {
                typeUsage = TypeUsage.Create(edmType, 
                    new FacetValues{Nullable = false});
            } 
            else 
            {
                typeUsage = TypeUsage.Create(edmType); 

            }

            // We need to make sure that both the ends of the relationtype are initialized. If there are not, then we should 
            // initialize them here
            InitializeAssociationEndMember(relationshipType, somNavigationProperty.ToEnd, toEndEntityType); 
            InitializeAssociationEndMember(relationshipType, somNavigationProperty.FromEnd, declaringEntityType); 

            // The type of the navigation property must be a ref or collection depending on which end they belong to 
            NavigationProperty navigationProperty = new NavigationProperty(somNavigationProperty.Name, typeUsage);
            navigationProperty.RelationshipType = relationshipType;
            navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.ToEnd.Name];
            navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.FromEnd.Name]; 

            // Extract the optional Documentation 
            if (somNavigationProperty.Documentation != null) 
            {
                navigationProperty.Documentation = ConvertToDocumentation(somNavigationProperty.Documentation); 
            }
            AddOtherContent(somNavigationProperty, navigationProperty);

            return navigationProperty; 
        }
 
        ///  
        /// Converts a function from SOM to metadata
        ///  
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects
        /// For function imports, the entity container including the function declaration 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The function object resulting from the convert 
        private static EdmFunction ConvertToFunction(Som.Function somFunction, 
                                                  DbProviderManifest providerManifest,
                                                  ConversionCache convertedItemCache, 
                                                  EntityContainer entityContainer,
                                                  Dictionary newGlobalItems)
        {
            // If we already have it, don't bother converting 
            GlobalItem globalItem = null;
 
            // if we are converted the function import, we need not check the global items collection, 
            // since the function imports are local to the entity container
            if (!somFunction.IsFunctionImport && newGlobalItems.TryGetValue(somFunction, out globalItem)) 
            {
                return (EdmFunction)globalItem;
            }
 

            FunctionParameter returnParameter = null; 
            bool areConvertingForProviderManifest = somFunction.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel; 
            TypeUsage returnType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
                                                        somFunction, 
                                                        somFunction.ReturnType,
                                                        providerManifest,
                                                        areConvertingForProviderManifest,
                                                        somFunction.Type, 
                                                        somFunction.CollectionKind,
                                                        (somFunction != null && somFunction.IsReturnAttributeReftype) /*isReftype*/, 
                                                        somFunction, 
                                                        convertedItemCache,
                                                        newGlobalItems); 
            if (null != returnType)
            {
                // Create the return parameter object, need to set the declaring type explicitly on the return parameter
                // because we aren't adding it to the members collection 
                returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue);
 
            } 
            else if(somFunction.Type != null)
            { //Return type was specified but we could not find a type usage 
                return null;
            }

            if (somFunction.ReturnType != null) 
            {
                AddOtherContent(somFunction.ReturnType, returnParameter); 
            } 

            EntitySet entitySet = null; 
            if (null != somFunction.EntitySet)
            {
                Debug.Assert(null != entityContainer, "only function imports may declare a entity set " +
                    "and function imports are always scoped to an entity container"); 
                entitySet = GetEntitySet(somFunction.EntitySet, entityContainer);
            } 
 
            List parameters = new List();
            foreach (Som.Parameter somParameter in somFunction.Parameters) 
            {
                TypeUsage parameterType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
                                                               somFunction,
                                                               somParameter, 
                                                               providerManifest,
                                                               areConvertingForProviderManifest, 
                                                               somParameter.Type, 
                                                               somParameter.CollectionKind,
                                                               somParameter.IsRefType, 
                                                               somParameter,
                                                               convertedItemCache,
                                                               newGlobalItems);
                if (parameterType == null) 
                {
                    return null; 
                } 

                FunctionParameter parameter = new FunctionParameter(somParameter.Name, 
                                                                    parameterType,
                                                                    GetParameterMode(somParameter.ParameterDirection));
                AddOtherContent(somParameter, parameter);
 
                if (somParameter.Documentation != null)
                { 
                    parameter.Documentation = ConvertToDocumentation(somParameter.Documentation); 
                }
                parameters.Add(parameter); 
            }

            EdmFunction function = new EdmFunction(somFunction.Name,
                somFunction.Schema.Namespace, 
                GetDataSpace(providerManifest),
                new EdmFunctionPayload 
                { 
                    Schema = somFunction.DbSchema,
                    StoreFunctionName = somFunction.StoreFunctionName, 
                    CommandText = somFunction.CommandText,
                    EntitySet = entitySet,
                    IsAggregate = somFunction.IsAggregate,
                    IsBuiltIn = somFunction.IsBuiltIn, 
                    IsNiladic = somFunction.IsNiladicFunction,
                    IsComposable = somFunction.IsComposable, 
                    IsFromProviderManifest = areConvertingForProviderManifest, 
                    ReturnParameter = returnParameter,
                    Parameters = parameters.ToArray(), 
                    ParameterTypeSemantics = somFunction.ParameterTypeSemantics,
                });

            // Add this function to new global items, only if it is not a function import 
            if (!somFunction.IsFunctionImport)
            { 
                newGlobalItems.Add(somFunction, function); 
            }
 



            //Check if we already converted functions since we are loading it from 
            //ssdl we could see functions many times.
            GlobalItem returnFunction = null; 
            Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(function.Identity, false, out returnFunction), 
                "Function duplicates must be checked by som");
 
            // Extract the optional Documentation
            if (somFunction.Documentation != null)
            {
                function.Documentation = ConvertToDocumentation(somFunction.Documentation); 
            }
            AddOtherContent(somFunction, function); 
 
            return function;
        } 

        /// 
        /// Converts an SOM Documentation node to a metadata Documentation construct
        ///  
        /// The SOM element to process
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The Documentation object resulting from the convert operation 
        private static Documentation ConvertToDocumentation(Som.DocumentationElement element)
        {
            Debug.Assert(null != element, "ConvertToDocumentation cannot be invoked with a null Som.Documentation element");
            return element.MetadataDocumentation; 
        }
 
        private static TypeUsage GetFunctionTypeUsage(bool isModelFunction, 
                                                      Som.Function somFunction,
                                                      Som.FacetEnabledSchemaElement somParameter, 
                                                      DbProviderManifest providerManifest,
                                                      bool areConvertingForProviderManifest,
                                                      Som.SchemaType type,
                                                      CollectionKind collectionKind, 
                                                      bool isRefType,
                                                      Som.SchemaElement schemaElement, 
                                                      ConversionCache convertedItemCache, 
                                                      Dictionary newGlobalItems)
        { 
            if (null != somParameter && areConvertingForProviderManifest
                && somParameter.HasUserDefinedFacets)
            {
                return somParameter.TypeUsage; 
            }
 
            if (null == type) 
            {
                if (isModelFunction && somParameter != null && somParameter is Som.Parameter) 
                {
                    (somParameter as Som.Parameter).ResolveNestedTypeNames(convertedItemCache, newGlobalItems);
                    return somParameter.TypeUsage;
                } 
                else if (isModelFunction && somFunction.ReturnType != null)
                { 
                    somFunction.ReturnType.ResolveNestedTypeNames(convertedItemCache, newGlobalItems); 
                    return somFunction.ReturnType.TypeUsage;
                } 
                else
                {
                    return null;
                } 
            }
 
            EdmType edmType; 
            if (!areConvertingForProviderManifest)
            { 
                // SOM verifies the type is either scalar, row, or entity
                Som.ScalarType scalarType = type as Som.ScalarType;
                if (null != scalarType)
                { 
                    if (isModelFunction && somParameter != null)
                    { 
                        if (somParameter.TypeUsage == null) 
                        {
                            somParameter.ValidateAndSetTypeUsage(scalarType); 
                        }
                        return somParameter.TypeUsage;
                    }
                    else if (isModelFunction) 
                    {
                        Som.ModelFunction modelFunction = somFunction as Som.ModelFunction; 
                        if(modelFunction.TypeUsage==null) 
                        {
                            modelFunction.ValidateAndSetTypeUsage(scalarType); 
                        }
                        return modelFunction.TypeUsage;
                    }
                    else if(somParameter!=null && somParameter.HasUserDefinedFacets && somFunction.Schema.DataModel == System.Data.EntityModel.SchemaObjectModel.SchemaDataModelOption.ProviderDataModel) 
                    {
                        somParameter.ValidateAndSetTypeUsage(scalarType); 
                        return somParameter.TypeUsage; 
                        //edmType = GetSsdlPrimitiveType(scalarType, providerManifest);
                    } 
                    else
                    {
                        edmType = GetSsdlPrimitiveType(scalarType, providerManifest);
                    } 
                }
                else 
                { 
                    edmType = (EdmType)LoadSchemaElement(type,
                        providerManifest, 
                        convertedItemCache,
                        newGlobalItems);
                }
            } 
            else if (type is Som.TypeElement)
            { 
                Som.TypeElement typeElement = type as Som.TypeElement; 
                edmType = typeElement.PrimitiveType;
            } 
            else
            {
                Som.ScalarType typeElement = type as Som.ScalarType;
                edmType = typeElement.Type; 
            }
 
            //Construct type usage 
            TypeUsage usage;
            if (collectionKind != CollectionKind.None) 
            {
                usage = convertedItemCache.GetCollectionTypeUsageWithNullFacets(edmType);
            }
            else 
            {
                if (edmType is EntityType && isRefType) 
                { 
                    usage = TypeUsage.Create(new RefType(edmType as EntityType));
                } 
                else
                {
                    usage = convertedItemCache.GetTypeUsageWithNullFacets(edmType);
                } 
            }
 
            return usage; 

        } 

        /// 
        /// Converts the ParameterDirection into a ParameterMode
        ///  
        /// The ParameterDirection to convert
        /// ParameterMode 
        private static ParameterMode GetParameterMode(ParameterDirection parameterDirection) 
        {
            Debug.Assert( 
                parameterDirection == ParameterDirection.Input
                || parameterDirection == ParameterDirection.InputOutput
                || parameterDirection == ParameterDirection.Output,
                "Inconsistent metadata error"); 

            switch (parameterDirection) 
            { 
                case ParameterDirection.Input:
                    return ParameterMode.In; 

                case ParameterDirection.Output:
                    return ParameterMode.Out;
 
                case ParameterDirection.InputOutput:
                default: 
                    return ParameterMode.InOut; 
            }
        } 

        /// 
        /// Apply the facet values from the property which are specific to primitive types to the given list of facets
        ///  
        /// The source TypeUsage
        /// The PrimativeType of the target 
        private static void ApplyPrimitiveTypePropertyFacets(TypeUsage sourceType, ref TypeUsage targetType) 
        {
            Dictionary newFacets = targetType.Facets.ToDictionary(f => f.Name); 
            bool madeChange = false;
            foreach (Facet sourceFacet in sourceType.Facets)
            {
 
                Facet targetFacet;
                if(newFacets.TryGetValue(sourceFacet.Name, out targetFacet)) 
                { 
                    if (!targetFacet.Description.IsConstant)
                    { 
                        madeChange = true;
                        newFacets[targetFacet.Name] = Facet.Create(targetFacet.Description, sourceFacet.Value);
                    }
                } 
                else
                { 
                    madeChange = true; 
                    newFacets.Add(sourceFacet.Name, sourceFacet);
                } 
            }

            if (madeChange)
            { 
                targetType = TypeUsage.Create(targetType.EdmType, newFacets.Values);
            } 
        } 

        ///  
        /// Populate the facets on the TypeUsage object fora property
        /// 
        /// The property containing the information
        /// The type usage object where to populate facet 
        /// The provider manifest to be used for conversion
        private static void PopulateGeneralFacets(Som.StructuredProperty somProperty, 
                                                  DbProviderManifest providerManifest, 
                                                  ref TypeUsage propertyTypeUsage)
        { 
            bool madeChanges = false;
            Dictionary facets = propertyTypeUsage.Facets.ToDictionary(f => f.Name);
            if (!somProperty.Nullable)
            { 
                facets[DbProviderManifest.NullableFacetName] = Facet.Create(MetadataItem.NullableFacetDescription, false);
                madeChanges = true; 
            } 

            if (somProperty.Default != null) 
            {
                facets[DbProviderManifest.DefaultValueFacetName] = Facet.Create(MetadataItem.DefaultValueFacetDescription, somProperty.DefaultAsObject);
                madeChanges = true;
            } 

            //This is not really a general facet 
            //If we are dealing with a 1.1 Schema, Add a facet for CollectionKind 
            if (somProperty.Schema.SchemaVersion == XmlConstants.EdmVersionForV1_1)
            { 
                Facet newFacet = Facet.Create(MetadataItem.CollectionKindFacetDescription, somProperty.CollectionKind);
                facets.Add(newFacet.Name, newFacet);
                madeChanges = true;
            } 

            if (madeChanges) 
            { 
                propertyTypeUsage = TypeUsage.Create(propertyTypeUsage.EdmType, facets.Values);
            } 
        }

        private static DataSpace GetDataSpace(DbProviderManifest providerManifest)
        { 
            Debug.Assert(providerManifest != null, "null provider manifest will be consider as SSpace");
            // Target attributes is for types and sets in target space. 
            if (providerManifest is EdmProviderManifest) 
            {
                return DataSpace.CSpace; 
            }
            else
            {
                return DataSpace.SSpace; 
            }
        } 
 
        /// 
        /// Get a primitive type when converting a CSDL schema 
        /// 
        /// The schema type representing the primitive type
        /// The provider manifest for retrieving the store types
        private static PrimitiveType GetSsdlPrimitiveType(Som.ScalarType scalarType, 
                                                          DbProviderManifest providerManifest)
        { 
            PrimitiveType returnValue = null; 
            string scalarTypeName = scalarType.Name;
 
            foreach (PrimitiveType primitiveType in providerManifest.GetStoreTypes())
            {
                if (primitiveType.Name == scalarTypeName)
                { 
                    returnValue = primitiveType;
                    break; 
                } 
            }
 
            Debug.Assert(scalarType != null, "Som scalar type should always resolve to a primitive type");
            return returnValue;
        }
 
        // This will update the sentinel values in the facets if required
        private static void UpdateSentinelValuesInFacets(ref TypeUsage typeUsage) 
        { 
            // For string and decimal types, replace the sentinel by the max possible value
            PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType; 
            if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String ||
                primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary)
            {
                Facet maxLengthFacet = typeUsage.Facets[EdmProviderManifest.MaxLengthFacetName]; 
                if (Helper.IsUnboundedFacetValue(maxLengthFacet))
                { 
                    typeUsage = typeUsage.ShallowCopy( 
                            new FacetValues{ MaxLength = Helper.GetFacet(primitiveType.FacetDescriptions,
                                                                EdmProviderManifest.MaxLengthFacetName).MaxValue }); 
                }
            }

        } 

        ///  
        /// Get the type usage for a structured primitive property when converting a CSDL schema 
        /// 
        /// Som Property that contains the type for which we need to get the mapping provider type 
        /// The item collection for currently existing metadata objects
        private static TypeUsage GetCsdlPrimitiveTypeUsageWithFacets(Som.StructuredProperty somProperty,
                                                      ConversionCache convertedItemCache)
        { 
            Debug.Assert(somProperty.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
            // try to get the instance of the primitive type from the item collection so that it back pointer is set. 
            EdmType propertyType = convertedItemCache.ItemCollection.GetItem(somProperty.TypeUsage.EdmType.FullName); 
            TypeUsage typeUsage = null;
            if (somProperty.CollectionKind != CollectionKind.None) 
            {
                propertyType = new CollectionType(propertyType);
                typeUsage = TypeUsage.Create(propertyType);
            } 
            else
            { 
                typeUsage = TypeUsage.Create(propertyType); 
                ApplyPrimitiveTypePropertyFacets(somProperty.TypeUsage, ref typeUsage);
            } 
            return typeUsage;
        }
        #endregion
 
        #region Nested types
        ///  
        /// Cache containing item collection and type usages to support looking up and generating 
        /// metadata types.
        ///  
        internal class ConversionCache
        {
            #region Fields
            internal readonly ItemCollection ItemCollection; 
            private readonly Dictionary _nullFacetsTypeUsage;
            private readonly Dictionary _nullFacetsCollectionTypeUsage; 
            #endregion 

            #region Constructors 
            internal ConversionCache(ItemCollection itemCollection)
            {
                this.ItemCollection = itemCollection;
                this._nullFacetsTypeUsage = new Dictionary(); 
                this._nullFacetsCollectionTypeUsage = new Dictionary();
            } 
            #endregion 

            #region Methods 
            /// 
            /// Gets type usage for the given type with null facet values. Caches usage to avoid creating
            /// redundant type usages.
            ///  
            internal TypeUsage GetTypeUsageWithNullFacets(EdmType edmType)
            { 
                // check for cached result 
                TypeUsage result;
                if (_nullFacetsTypeUsage.TryGetValue(edmType, out result)) 
                {
                    return result;
                }
 
                // construct result
                result = TypeUsage.Create(edmType, FacetValues.NullFacetValues); 
 
                // cache result
                _nullFacetsTypeUsage.Add(edmType, result); 

                return result;
            }
 
            /// 
            /// Gets collection type usage for the given type with null facet values. Caches usage to avoid creating 
            /// redundant type usages. 
            /// 
            internal TypeUsage GetCollectionTypeUsageWithNullFacets(EdmType edmType) 
            {
                // check for cached result
                TypeUsage result;
                if (_nullFacetsCollectionTypeUsage.TryGetValue(edmType, out result)) 
                {
                    return result; 
                } 

                // construct collection type from cached element type 
                TypeUsage elementTypeUsage = GetTypeUsageWithNullFacets(edmType);
                result = TypeUsage.Create(new CollectionType(elementTypeUsage), FacetValues.NullFacetValues);

                // cache result 
                _nullFacetsCollectionTypeUsage.Add(edmType, result);
 
                return result; 
            }
            #endregion 
        }
        #endregion
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Data.Common; 
using System.Diagnostics;
using System.Data.Objects.DataClasses;
using System.Collections.Generic;
using System.Globalization; 
using System.Text;
using System.Linq; 
 
namespace System.Data.Metadata.Edm
{ 
    /// 
    /// Helper Class for converting SOM objects to metadata objects
    /// This class should go away once we have completely integrated SOM and metadata
    ///  
    internal static class Converter
    { 
        #region Constructor 
        /// 
        /// Static constructor for creating FacetDescription objects that we use 
        /// 
        static Converter()
        {
            // Create the enum types that we will need 
            EnumType concurrencyModeType = new EnumType(EdmProviderManifest.ConcurrencyModeFacetName,
                                                        EdmConstants.EdmNamespace, 
                                                        DataSpace.CSpace); 
            foreach (string name in Enum.GetNames(typeof(ConcurrencyMode)))
            { 
                concurrencyModeType.AddMember(new EnumMember(name));
            }
            EnumType storeGeneratedPatternType = new EnumType(EdmProviderManifest.StoreGeneratedPatternFacetName,
                                                              EdmConstants.EdmNamespace, 
                                                              DataSpace.CSpace);
            foreach (string name in Enum.GetNames(typeof(StoreGeneratedPattern))) 
            { 
                storeGeneratedPatternType.AddMember(new EnumMember(name));
            } 


            // Now create the facet description objects
            ConcurrencyModeFacet = new FacetDescription(EdmProviderManifest.ConcurrencyModeFacetName, 
                                                        concurrencyModeType,
                                                        null, 
                                                        null, 
                                                        ConcurrencyMode.None);
            StoreGeneratedPatternFacet = new FacetDescription(EdmProviderManifest.StoreGeneratedPatternFacetName, 
                                                              storeGeneratedPatternType,
                                                              null,
                                                              null,
                                                              StoreGeneratedPattern.None); 
            CollationFacet = new FacetDescription(EdmProviderManifest.CollationFacetName,
                                                  MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String), 
                                                  null, 
                                                  null,
                                                  string.Empty); 
        }
        #endregion

        #region Fields 
        internal static readonly FacetDescription ConcurrencyModeFacet;
        internal static readonly FacetDescription StoreGeneratedPatternFacet; 
        internal static readonly FacetDescription CollationFacet; 

        #endregion 

        #region Methods
        /// 
        /// Converts a schema from SOM into Metadata 
        /// 
        /// The SOM schema to convert 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        internal static IEnumerable ConvertSchema(Som.Schema somSchema, 
                                                              DbProviderManifest providerManifest,
                                                              ItemCollection itemCollection)
        {
            Dictionary newGlobalItems = new Dictionary(); 
            ConvertSchema(somSchema, providerManifest, new ConversionCache(itemCollection), newGlobalItems);
            return newGlobalItems.Values; 
        } 

        internal static IEnumerable ConvertSchema(IList somSchemas, 
                                                              DbProviderManifest providerManifest,
                                                              ItemCollection itemCollection)
        {
            Dictionary newGlobalItems = new Dictionary(); 
            ConversionCache conversionCache = new ConversionCache(itemCollection);
 
            foreach (Som.Schema somSchema in somSchemas) 
            {
                ConvertSchema(somSchema, providerManifest, conversionCache, newGlobalItems); 
            }

            return newGlobalItems.Values;
        } 

        private static void ConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, 
            ConversionCache convertedItemCache, Dictionary newGlobalItems) 
        {
            List funcsWithUnresolvedTypes = new List(); 
            foreach (Som.SchemaType element in somSchema.SchemaTypes)
            {
                if (null == LoadSchemaElement(element, providerManifest, convertedItemCache, newGlobalItems))
                { 
                    if (element is Som.Function)
                    { 
                        funcsWithUnresolvedTypes.Add(element as Som.Function); 
                    }
                } 
            }

            foreach (Som.SchemaEntityType element in somSchema.SchemaTypes.OfType())
            { 
                LoadEntityTypePhase2(element, providerManifest, convertedItemCache, newGlobalItems);
            } 
 
            foreach (var function in funcsWithUnresolvedTypes)
            { 
                if (null == LoadSchemaElement(function, providerManifest, convertedItemCache, newGlobalItems))
                {
                    Debug.Fail("Could not load model function definition"); //this should never happen.
                } 
            }
 
            if (convertedItemCache.ItemCollection.DataSpace == DataSpace.CSpace) 
            {
                EdmItemCollection edmCollection = (EdmItemCollection)convertedItemCache.ItemCollection; 
                //Get the version of the SomSchema and update the EdmVersion to be the Maximum of all the
                //versions of the schemas that are being loaded in this item collection.
                edmCollection.EdmVersion = Math.Max(somSchema.SchemaVersion, edmCollection.EdmVersion);
            } 
            else
            { 
                Debug.Assert(convertedItemCache.ItemCollection.DataSpace == DataSpace.SSpace, "Did you add a new space?"); 
                // when converting the ProviderManifest, the DataSpace is SSpace, but the ItemCollection is EmptyItemCollection,
                // not StoreItemCollection 
                StoreItemCollection storeCollection = convertedItemCache.ItemCollection as StoreItemCollection;
                if (storeCollection != null)
                {
                    storeCollection.SchemaVersion = Math.Max(somSchema.SchemaVersion, storeCollection.SchemaVersion); 
                }
            } 
        } 

        ///  
        /// Loads a schema element
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The item resulting from the load 
        internal static MetadataItem LoadSchemaElement(Som.SchemaType element,
                                              DbProviderManifest providerManifest, 
                                              ConversionCache convertedItemCache,
                                              Dictionary newGlobalItems)
        {
            Debug.Assert(providerManifest != null, "This will make the dataspace to be default SSpace"); 
            // Try to fetch from the collection first
            GlobalItem item; 
 
            Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(element.FQName, false, out item), "Som should have checked for duplicate items");
 
            // Try to fetch in our collection of new GlobalItems
            if (newGlobalItems.TryGetValue(element, out item))
            {
                return item; 
            }
 
            Som.EntityContainer entityContainer = element as Som.EntityContainer; 
            // Perform different conversion depending on the type of the SOM object
            if (entityContainer!=null) 
            {
                item = ConvertToEntityContainer(entityContainer,
                                                providerManifest,
                                                convertedItemCache, 
                                                newGlobalItems);
            } 
            else if (element is Som.SchemaEntityType) 
            {
                item = ConvertToEntityType((Som.SchemaEntityType)element, 
                                           providerManifest,
                                           convertedItemCache,
                                           newGlobalItems);
            } 
            else if (element is Som.Relationship)
            { 
                item = ConvertToAssociationType((Som.Relationship)element, 
                                                providerManifest,
                                                convertedItemCache, 
                                                newGlobalItems);
            }
            else if (element is Som.SchemaComplexType)
            { 
                item = ConvertToComplexType((Som.SchemaComplexType)element,
                                            providerManifest, 
                                            convertedItemCache, 
                                            newGlobalItems);
            } 
            else if (element is Som.Function)
            {
                item = ConvertToFunction((Som.Function)element, providerManifest,
                    convertedItemCache, null, newGlobalItems); 
            }
            else 
            { 
                // the only type we don't handle is the ProviderManifest TypeElement
                // if it is anything else, it is probably a mistake 
                Debug.Assert(element is Som.TypeElement &&
                    element.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel,
                    "Unknown Type in somschema");
                return null; 
            }
 
            return item; 
        }
 
        /// 
        /// Converts an entity container from SOM to metadata
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The entity container object resulting from the convert
        private static EntityContainer ConvertToEntityContainer(Som.EntityContainer element, 
                                                                DbProviderManifest providerManifest,
                                                                ConversionCache convertedItemCache,
                                                                Dictionary newGlobalItems)
        { 
            // Creating a new entity container object and populate with converted entity set objects
            EntityContainer entityContainer = new EntityContainer(element.Name, GetDataSpace(providerManifest)); 
            newGlobalItems.Add(element, entityContainer); 

            foreach (Som.EntityContainerEntitySet entitySet in element.EntitySets) 
            {
                entityContainer.AddEntitySetBase(ConvertToEntitySet(entitySet,
                                                                      entityContainer.Name,
                                                                      providerManifest, 
                                                                      convertedItemCache,
                                                                      newGlobalItems)); 
            } 

            // Populate with converted relationship set objects 
            foreach (Som.EntityContainerRelationshipSet relationshipSet in element.RelationshipSets)
            {
                Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association,
                             "We do not support containment set"); 

                entityContainer.AddEntitySetBase(ConvertToAssociationSet(relationshipSet, 
                                                                           providerManifest, 
                                                                           convertedItemCache,
                                                                           entityContainer, 
                                                                           newGlobalItems));
            }

            // Populate with converted function imports 
            foreach (Som.Function functionImport in element.FunctionImports)
            { 
                entityContainer.AddFunctionImport(ConvertToFunction(functionImport, 
                    providerManifest, convertedItemCache, entityContainer, newGlobalItems));
            } 

            // Extract the optional Documentation
            if (element.Documentation != null)
            { 
                entityContainer.Documentation = ConvertToDocumentation(element.Documentation);
            } 
 
            AddOtherContent(element, entityContainer);
 
            return entityContainer;
        }

        ///  
        /// Converts an entity type from SOM to metadata
        /// 
        /// This method should only build the internally contained and vertical part of the EntityType (keys, properties, and base types) but not 
        /// sideways parts (NavigationProperties) that go between types or we risk trying to access and EntityTypes keys, from the referenctial constraint,
        /// before the base type, which has the keys, is setup yet. 
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The entity type object resulting from the convert 
        private static EntityType ConvertToEntityType(Som.SchemaEntityType element, 
                                                      DbProviderManifest providerManifest,
                                                      ConversionCache convertedItemCache, 
                                                      Dictionary newGlobalItems)
        {
            string[] keyMembers = null;
            // Check if this type has keys 
            if (element.DeclaredKeyProperties.Count != 0)
            { 
                keyMembers = new string[element.DeclaredKeyProperties.Count]; 
                for (int i = 0; i < keyMembers.Length; i++)
                { 
                    //Add the name of the key property to the list of
                    //key properties
                    keyMembers[i] = (element.DeclaredKeyProperties[i].Property.Name);
                } 
            }
 
            EdmProperty[] properties = new EdmProperty[element.Properties.Count]; 
            int index = 0;
 
            foreach (Som.StructuredProperty somProperty in element.Properties)
            {
                properties[index++] = ConvertToProperty(somProperty,
                                                        providerManifest, 
                                                        convertedItemCache,
                                                        newGlobalItems); 
            } 

            EntityType entityType = new EntityType(element.Name, 
                                                   element.Namespace,
                                                   GetDataSpace(providerManifest),
                                                   keyMembers,
                                                   properties); 

            if (element.BaseType != null) 
            { 
                entityType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
                                                                  providerManifest, 
                                                                  convertedItemCache,
                                                                  newGlobalItems));
            }
 
            // set the abstract and sealed type values for the entity type
            entityType.Abstract = element.IsAbstract; 
            // Extract the optional Documentation 
            if (element.Documentation != null)
            { 
                entityType.Documentation = ConvertToDocumentation(element.Documentation);
            }
            AddOtherContent(element, entityType);
            newGlobalItems.Add(element, entityType); 
            return entityType;
        } 
 
        private static void LoadEntityTypePhase2(Som.SchemaEntityType element,
                                                      DbProviderManifest providerManifest, 
                                                      ConversionCache convertedItemCache,
                                                      Dictionary newGlobalItems)
        {
            EntityType entityType = (EntityType)newGlobalItems[element]; 

            // Since Navigation properties are internal and not part of member collection, we 
            // need to initialize the base class first before we start adding the navigation property 
            // this will ensure that all the base navigation properties are initialized
            foreach (Som.NavigationProperty somNavigationProperty in element.NavigationProperties) 
            {
                entityType.AddMember(ConvertToNavigationProperty(entityType,
                                                                 somNavigationProperty,
                                                                 providerManifest, 
                                                                 convertedItemCache,
                                                                 newGlobalItems)); 
            } 
        }
 
        /// 
        /// Converts an complex type from SOM to metadata
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The complex type object resulting from the convert
        private static ComplexType ConvertToComplexType(Som.SchemaComplexType element, 
                                                        DbProviderManifest providerManifest,
                                                        ConversionCache convertedItemCache,
                                                        Dictionary newGlobalItems)
        { 
            ComplexType complexType = new ComplexType(element.Name,
                                                      element.Namespace, 
                                                      GetDataSpace(providerManifest)); 
            newGlobalItems.Add(element, complexType);
 
            foreach (Som.StructuredProperty somProperty in element.Properties)
            {
                complexType.AddMember(ConvertToProperty(somProperty,
                                                          providerManifest, 
                                                          convertedItemCache,
                                                          newGlobalItems)); 
            } 

            // set the abstract and sealed type values for the entity type 
            complexType.Abstract = element.IsAbstract;

            if (element.BaseType != null)
            { 
                complexType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
                                                                  providerManifest, 
                                                                  convertedItemCache, 
                                                                  newGlobalItems));
            } 

            // Extract the optional Documentation
            if (element.Documentation != null)
            { 
                complexType.Documentation = ConvertToDocumentation(element.Documentation);
            } 
            AddOtherContent(element, complexType); 

            return complexType; 
        }

        /// 
        /// Converts an association type from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The association type object resulting from the convert
        private static AssociationType ConvertToAssociationType(Som.Relationship element,
                                                                DbProviderManifest providerManifest,
                                                                ConversionCache convertedItemCache, 
                                                                Dictionary newGlobalItems)
        { 
            Debug.Assert(element.RelationshipKind == RelationshipKind.Association); 

            AssociationType associationType = new AssociationType(element.Name, 
                                                                  element.Namespace,
                                                                  element.IsForeignKey,
                                                                  GetDataSpace(providerManifest));
            newGlobalItems.Add(element, associationType); 

            foreach (Som.RelationshipEnd end in element.Ends) 
            { 
                Som.SchemaType entityTypeElement = end.Type;
                EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement, 
                                                                providerManifest,
                                                                convertedItemCache,
                                                                newGlobalItems);
 
                AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType);
                AddOtherContent(end, endMember); 
                // Loop through and convert the operations 
                foreach (Som.OnOperation operation in end.Operations)
                { 
                    // Process only the ones that we recognize
                    if (operation.Operation != Som.Operation.Delete)
                    {
                        continue; 
                    }
 
                    // Determine the action for this operation 
                    OperationAction action = OperationAction.None;
                    switch (operation.Action) 
                    {
                        case Som.Action.Cascade:
                            action = OperationAction.Cascade;
                            break; 
                        case Som.Action.None:
                            action = OperationAction.None; 
                            break; 
                        default:
                            Debug.Fail("Operation action not supported."); 
                            break;
                    }
                    endMember.DeleteBehavior = action;
                } 

                // Extract optional Documentation hanging off the end element 
                if (end.Documentation != null) 
                {
                    endMember.Documentation = ConvertToDocumentation(end.Documentation); 
                }
            }

            Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized"); 

            for (int i = 0; i < element.Constraints.Count; i++) 
            { 
                Som.ReferentialConstraint constraint = element.Constraints[i];
                AssociationEndMember fromMember = (AssociationEndMember) associationType.Members[constraint.PrincipalRole.Name]; 
                AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name];
                EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType;
                EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType;
 
                ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember,
                                                                                        GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties), 
                                                                                        GetProperties(toEntityType, constraint.DependentRole.RoleProperties)); 

                // Attach the optional Documentation 
                if (constraint.Documentation != null)
                    referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation);
                if (constraint.PrincipalRole.Documentation != null)
                    referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation); 
                if (constraint.DependentRole.Documentation != null)
                    referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation); 
 

                associationType.AddReferentialConstraint(referentialConstraint); 
                AddOtherContent(element.Constraints[i], referentialConstraint);

            }
 
            // Extract the optional Documentation
            if (element.Documentation != null) 
            { 
                associationType.Documentation = ConvertToDocumentation(element.Documentation);
            } 
            AddOtherContent(element, associationType);

            return associationType;
        } 

        ///  
        /// Initialize the end member if its not initialized already 
        /// 
        ///  
        /// 
        /// 
        private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end,
            EntityType endMemberType) 
        {
            AssociationEndMember associationEnd; 
 
            EdmMember member;
            // make sure that the end is not initialized as of yet 
            if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member))
            {
                // Create the end member and add the operations
                associationEnd = new AssociationEndMember(end.Name, 
                                                          endMemberType.GetReferenceType(),
                                                          end.Multiplicity.Value); 
                associationType.AddKeyMember(associationEnd); 
            }
            else 
            {
                associationEnd = (AssociationEndMember)member;
            }
 
            //Extract the optional Documentation
            Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd; 
 
            if (relationshipEnd != null && (relationshipEnd.Documentation != null))
            { 
                associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation);
            }

            return associationEnd; 
        }
 
        private static EdmProperty[] GetProperties(EntityTypeBase entityType, IList properties) 
        {
            Debug.Assert(properties.Count != 0); 
            EdmProperty[] result = new EdmProperty[properties.Count];

            for (int i = 0; i < properties.Count; i++)
            { 
                result[i] = (EdmProperty) entityType.Members[properties[i].Name];
            } 
 
            return result;
        } 


        private static void AddOtherContent(Som.SchemaElement element, MetadataItem item)
        { 
            if (element.OtherContent.Count > 0)
            { 
                item.AddMetadataProperties(element.OtherContent); 
            }
        } 

        /// 
        /// Converts an entity set from SOM to metadata
        ///  
        /// The SOM element to process
        /// the name of the container this will be added to 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The entity set object resulting from the convert
        private static EntitySet ConvertToEntitySet(Som.EntityContainerEntitySet set,
                                                    string containerName,
                                                    DbProviderManifest providerManifest, 
                                                    ConversionCache convertedItemCache,
                                                    Dictionary newGlobalItems) 
        { 
            EntitySet entitySet = new EntitySet(set.Name,set.DbSchema,set.Table, set.DefiningQuery,
                                                 (EntityType)LoadSchemaElement(set.EntityType, 
                                                                               providerManifest,
                                                                               convertedItemCache,
                                                                               newGlobalItems));
 
            // Extract the optional Documentation
            if (set.Documentation != null) 
            { 
                entitySet.Documentation = ConvertToDocumentation(set.Documentation);
            } 
            AddOtherContent(set, entitySet);

            return entitySet;
        } 

        ///  
        /// Converts an entity set from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// 
        /// The entity set object resulting from the convert
        private static EntitySet GetEntitySet(Som.EntityContainerEntitySet set, EntityContainer container)
        { 
            return container.GetEntitySetByName(set.Name, false);
        } 
 
        /// 
        /// Converts an association set from SOM to metadata 
        /// 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        ///  
        /// The association set object resulting from the convert 
        private static AssociationSet ConvertToAssociationSet(Som.EntityContainerRelationshipSet relationshipSet,
                                                              DbProviderManifest providerManifest, 
                                                              ConversionCache convertedItemCache,
                                                              EntityContainer container,
                                                              Dictionary newGlobalItems)
        { 
            Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association);
 
            AssociationType associationType = (AssociationType)LoadSchemaElement((Som.SchemaType)relationshipSet.Relationship, 
                                                                                  providerManifest,
                                                                                  convertedItemCache, 
                                                                                  newGlobalItems);

            AssociationSet associationSet = new AssociationSet(relationshipSet.Name, associationType);
 
            foreach (Som.EntityContainerRelationshipSetEnd end in relationshipSet.Ends)
            { 
                //-- need the EntityType for the end 
                EntityType endEntityType = (EntityType)LoadSchemaElement(end.EntitySet.EntityType,
                                                                         providerManifest, 
                                                                         convertedItemCache,
                                                                         newGlobalItems);
                //-- need to get the end member
                AssociationEndMember endMember = (AssociationEndMember) associationType.Members[end.Name]; 
                //-- create the end
                AssociationSetEnd associationSetEnd = new AssociationSetEnd(GetEntitySet(end.EntitySet, container), 
                                                                            associationSet, 
                                                                            endMember);
 
                AddOtherContent(end, associationSetEnd);
                associationSet.AddAssociationSetEnd(associationSetEnd);

                // Extract optional Documentation hanging off the end element 
                if (end.Documentation != null)
                { 
                    associationSetEnd.Documentation = ConvertToDocumentation(end.Documentation); 
                }
            } 

            // Extract the optional Documentation
            if (relationshipSet.Documentation != null)
            { 
                associationSet.Documentation = ConvertToDocumentation(relationshipSet.Documentation);
            } 
            AddOtherContent(relationshipSet, associationSet); 

            return associationSet; 
        }

        /// 
        /// Converts a property from SOM to metadata 
        /// 
        /// The SOM element to process 
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The property object resulting from the convert
        private static EdmProperty ConvertToProperty(Som.StructuredProperty somProperty,
                                                  DbProviderManifest providerManifest,
                                                  ConversionCache convertedItemCache, 
                                                  Dictionary newGlobalItems)
        { 
            EdmProperty property; 

            // Get the appropriate type object for this type, for primitive types, get the facet values for the primitive type 
            // property as a type usage object as well
            TypeUsage typeUsage = null;

            Som.ScalarType scalarType = somProperty.Type as Som.ScalarType; 
            if (scalarType != null)
            { 
                if (somProperty.Schema.DataModel == Som.SchemaDataModelOption.EntityDataModel) 
                {
                    // csdl 
                    typeUsage = GetCsdlPrimitiveTypeUsageWithFacets(somProperty, convertedItemCache);
                }
                else
                { 
                    // parsing ssdl
                    typeUsage = somProperty.TypeUsage; 
                    UpdateSentinelValuesInFacets(ref typeUsage); 
                }
            } 
            else
            {
                EdmType propertyType = (EdmType)LoadSchemaElement(somProperty.Type, providerManifest, convertedItemCache, newGlobalItems);
                if (somProperty.CollectionKind != CollectionKind.None) 
                {
                    propertyType = new CollectionType(propertyType); 
                } 
                typeUsage = TypeUsage.Create(propertyType);
            } 

            PopulateGeneralFacets(somProperty, providerManifest, ref typeUsage);
            property = new EdmProperty(somProperty.Name, typeUsage);
 
            // Extract the optional Documentation
            if (somProperty.Documentation != null) 
            { 
                property.Documentation = ConvertToDocumentation(somProperty.Documentation);
            } 
            AddOtherContent(somProperty, property);

            return property;
        } 

        ///  
        /// Converts a navigation property from SOM to metadata 
        /// 
        /// entity type on which this navigation property was declared 
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects
        /// The new GlobalItem objects that are created as a result of this conversion 
        /// The property object resulting from the convert
        private static NavigationProperty ConvertToNavigationProperty(EntityType declaringEntityType, 
                                                                      Som.NavigationProperty somNavigationProperty, 
                                                                      DbProviderManifest providerManifest,
                                                                      ConversionCache convertedItemCache, 
                                                                      Dictionary newGlobalItems)
        {
            // Navigation properties cannot be primitive types, so we can ignore the possibility of having primitive type
            // facets 
            EntityType toEndEntityType = (EntityType)LoadSchemaElement(somNavigationProperty.Type,
                                                      providerManifest, 
                                                      convertedItemCache, 
                                                      newGlobalItems);
 
            EdmType edmType = toEndEntityType;

            // Also load the relationship Type that this navigation property represents
            AssociationType relationshipType = (AssociationType)LoadSchemaElement((Som.Relationship)somNavigationProperty.Relationship, 
                    providerManifest, convertedItemCache, newGlobalItems);
 
            Som.IRelationshipEnd somRelationshipEnd = null; 
            somNavigationProperty.Relationship.TryGetEnd(somNavigationProperty.ToEnd.Name, out somRelationshipEnd);
            if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.Many) 
            {
                edmType = toEndEntityType.GetCollectionType();
            }
            else 
            {
                Debug.Assert(somRelationshipEnd.Multiplicity != RelationshipMultiplicity.Many); 
                edmType = toEndEntityType; 
            }
 
            TypeUsage typeUsage;
            if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.One)
            {
                typeUsage = TypeUsage.Create(edmType, 
                    new FacetValues{Nullable = false});
            } 
            else 
            {
                typeUsage = TypeUsage.Create(edmType); 

            }

            // We need to make sure that both the ends of the relationtype are initialized. If there are not, then we should 
            // initialize them here
            InitializeAssociationEndMember(relationshipType, somNavigationProperty.ToEnd, toEndEntityType); 
            InitializeAssociationEndMember(relationshipType, somNavigationProperty.FromEnd, declaringEntityType); 

            // The type of the navigation property must be a ref or collection depending on which end they belong to 
            NavigationProperty navigationProperty = new NavigationProperty(somNavigationProperty.Name, typeUsage);
            navigationProperty.RelationshipType = relationshipType;
            navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.ToEnd.Name];
            navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.FromEnd.Name]; 

            // Extract the optional Documentation 
            if (somNavigationProperty.Documentation != null) 
            {
                navigationProperty.Documentation = ConvertToDocumentation(somNavigationProperty.Documentation); 
            }
            AddOtherContent(somNavigationProperty, navigationProperty);

            return navigationProperty; 
        }
 
        ///  
        /// Converts a function from SOM to metadata
        ///  
        /// The SOM element to process
        /// The provider manifest to be used for conversion
        /// The item collection for currently existing metadata objects
        /// For function imports, the entity container including the function declaration 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The function object resulting from the convert 
        private static EdmFunction ConvertToFunction(Som.Function somFunction, 
                                                  DbProviderManifest providerManifest,
                                                  ConversionCache convertedItemCache, 
                                                  EntityContainer entityContainer,
                                                  Dictionary newGlobalItems)
        {
            // If we already have it, don't bother converting 
            GlobalItem globalItem = null;
 
            // if we are converted the function import, we need not check the global items collection, 
            // since the function imports are local to the entity container
            if (!somFunction.IsFunctionImport && newGlobalItems.TryGetValue(somFunction, out globalItem)) 
            {
                return (EdmFunction)globalItem;
            }
 

            FunctionParameter returnParameter = null; 
            bool areConvertingForProviderManifest = somFunction.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel; 
            TypeUsage returnType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
                                                        somFunction, 
                                                        somFunction.ReturnType,
                                                        providerManifest,
                                                        areConvertingForProviderManifest,
                                                        somFunction.Type, 
                                                        somFunction.CollectionKind,
                                                        (somFunction != null && somFunction.IsReturnAttributeReftype) /*isReftype*/, 
                                                        somFunction, 
                                                        convertedItemCache,
                                                        newGlobalItems); 
            if (null != returnType)
            {
                // Create the return parameter object, need to set the declaring type explicitly on the return parameter
                // because we aren't adding it to the members collection 
                returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue);
 
            } 
            else if(somFunction.Type != null)
            { //Return type was specified but we could not find a type usage 
                return null;
            }

            if (somFunction.ReturnType != null) 
            {
                AddOtherContent(somFunction.ReturnType, returnParameter); 
            } 

            EntitySet entitySet = null; 
            if (null != somFunction.EntitySet)
            {
                Debug.Assert(null != entityContainer, "only function imports may declare a entity set " +
                    "and function imports are always scoped to an entity container"); 
                entitySet = GetEntitySet(somFunction.EntitySet, entityContainer);
            } 
 
            List parameters = new List();
            foreach (Som.Parameter somParameter in somFunction.Parameters) 
            {
                TypeUsage parameterType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
                                                               somFunction,
                                                               somParameter, 
                                                               providerManifest,
                                                               areConvertingForProviderManifest, 
                                                               somParameter.Type, 
                                                               somParameter.CollectionKind,
                                                               somParameter.IsRefType, 
                                                               somParameter,
                                                               convertedItemCache,
                                                               newGlobalItems);
                if (parameterType == null) 
                {
                    return null; 
                } 

                FunctionParameter parameter = new FunctionParameter(somParameter.Name, 
                                                                    parameterType,
                                                                    GetParameterMode(somParameter.ParameterDirection));
                AddOtherContent(somParameter, parameter);
 
                if (somParameter.Documentation != null)
                { 
                    parameter.Documentation = ConvertToDocumentation(somParameter.Documentation); 
                }
                parameters.Add(parameter); 
            }

            EdmFunction function = new EdmFunction(somFunction.Name,
                somFunction.Schema.Namespace, 
                GetDataSpace(providerManifest),
                new EdmFunctionPayload 
                { 
                    Schema = somFunction.DbSchema,
                    StoreFunctionName = somFunction.StoreFunctionName, 
                    CommandText = somFunction.CommandText,
                    EntitySet = entitySet,
                    IsAggregate = somFunction.IsAggregate,
                    IsBuiltIn = somFunction.IsBuiltIn, 
                    IsNiladic = somFunction.IsNiladicFunction,
                    IsComposable = somFunction.IsComposable, 
                    IsFromProviderManifest = areConvertingForProviderManifest, 
                    ReturnParameter = returnParameter,
                    Parameters = parameters.ToArray(), 
                    ParameterTypeSemantics = somFunction.ParameterTypeSemantics,
                });

            // Add this function to new global items, only if it is not a function import 
            if (!somFunction.IsFunctionImport)
            { 
                newGlobalItems.Add(somFunction, function); 
            }
 



            //Check if we already converted functions since we are loading it from 
            //ssdl we could see functions many times.
            GlobalItem returnFunction = null; 
            Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(function.Identity, false, out returnFunction), 
                "Function duplicates must be checked by som");
 
            // Extract the optional Documentation
            if (somFunction.Documentation != null)
            {
                function.Documentation = ConvertToDocumentation(somFunction.Documentation); 
            }
            AddOtherContent(somFunction, function); 
 
            return function;
        } 

        /// 
        /// Converts an SOM Documentation node to a metadata Documentation construct
        ///  
        /// The SOM element to process
        /// The provider manifest to be used for conversion 
        /// The item collection for currently existing metadata objects 
        /// The new GlobalItem objects that are created as a result of this conversion
        /// The Documentation object resulting from the convert operation 
        private static Documentation ConvertToDocumentation(Som.DocumentationElement element)
        {
            Debug.Assert(null != element, "ConvertToDocumentation cannot be invoked with a null Som.Documentation element");
            return element.MetadataDocumentation; 
        }
 
        private static TypeUsage GetFunctionTypeUsage(bool isModelFunction, 
                                                      Som.Function somFunction,
                                                      Som.FacetEnabledSchemaElement somParameter, 
                                                      DbProviderManifest providerManifest,
                                                      bool areConvertingForProviderManifest,
                                                      Som.SchemaType type,
                                                      CollectionKind collectionKind, 
                                                      bool isRefType,
                                                      Som.SchemaElement schemaElement, 
                                                      ConversionCache convertedItemCache, 
                                                      Dictionary newGlobalItems)
        { 
            if (null != somParameter && areConvertingForProviderManifest
                && somParameter.HasUserDefinedFacets)
            {
                return somParameter.TypeUsage; 
            }
 
            if (null == type) 
            {
                if (isModelFunction && somParameter != null && somParameter is Som.Parameter) 
                {
                    (somParameter as Som.Parameter).ResolveNestedTypeNames(convertedItemCache, newGlobalItems);
                    return somParameter.TypeUsage;
                } 
                else if (isModelFunction && somFunction.ReturnType != null)
                { 
                    somFunction.ReturnType.ResolveNestedTypeNames(convertedItemCache, newGlobalItems); 
                    return somFunction.ReturnType.TypeUsage;
                } 
                else
                {
                    return null;
                } 
            }
 
            EdmType edmType; 
            if (!areConvertingForProviderManifest)
            { 
                // SOM verifies the type is either scalar, row, or entity
                Som.ScalarType scalarType = type as Som.ScalarType;
                if (null != scalarType)
                { 
                    if (isModelFunction && somParameter != null)
                    { 
                        if (somParameter.TypeUsage == null) 
                        {
                            somParameter.ValidateAndSetTypeUsage(scalarType); 
                        }
                        return somParameter.TypeUsage;
                    }
                    else if (isModelFunction) 
                    {
                        Som.ModelFunction modelFunction = somFunction as Som.ModelFunction; 
                        if(modelFunction.TypeUsage==null) 
                        {
                            modelFunction.ValidateAndSetTypeUsage(scalarType); 
                        }
                        return modelFunction.TypeUsage;
                    }
                    else if(somParameter!=null && somParameter.HasUserDefinedFacets && somFunction.Schema.DataModel == System.Data.EntityModel.SchemaObjectModel.SchemaDataModelOption.ProviderDataModel) 
                    {
                        somParameter.ValidateAndSetTypeUsage(scalarType); 
                        return somParameter.TypeUsage; 
                        //edmType = GetSsdlPrimitiveType(scalarType, providerManifest);
                    } 
                    else
                    {
                        edmType = GetSsdlPrimitiveType(scalarType, providerManifest);
                    } 
                }
                else 
                { 
                    edmType = (EdmType)LoadSchemaElement(type,
                        providerManifest, 
                        convertedItemCache,
                        newGlobalItems);
                }
            } 
            else if (type is Som.TypeElement)
            { 
                Som.TypeElement typeElement = type as Som.TypeElement; 
                edmType = typeElement.PrimitiveType;
            } 
            else
            {
                Som.ScalarType typeElement = type as Som.ScalarType;
                edmType = typeElement.Type; 
            }
 
            //Construct type usage 
            TypeUsage usage;
            if (collectionKind != CollectionKind.None) 
            {
                usage = convertedItemCache.GetCollectionTypeUsageWithNullFacets(edmType);
            }
            else 
            {
                if (edmType is EntityType && isRefType) 
                { 
                    usage = TypeUsage.Create(new RefType(edmType as EntityType));
                } 
                else
                {
                    usage = convertedItemCache.GetTypeUsageWithNullFacets(edmType);
                } 
            }
 
            return usage; 

        } 

        /// 
        /// Converts the ParameterDirection into a ParameterMode
        ///  
        /// The ParameterDirection to convert
        /// ParameterMode 
        private static ParameterMode GetParameterMode(ParameterDirection parameterDirection) 
        {
            Debug.Assert( 
                parameterDirection == ParameterDirection.Input
                || parameterDirection == ParameterDirection.InputOutput
                || parameterDirection == ParameterDirection.Output,
                "Inconsistent metadata error"); 

            switch (parameterDirection) 
            { 
                case ParameterDirection.Input:
                    return ParameterMode.In; 

                case ParameterDirection.Output:
                    return ParameterMode.Out;
 
                case ParameterDirection.InputOutput:
                default: 
                    return ParameterMode.InOut; 
            }
        } 

        /// 
        /// Apply the facet values from the property which are specific to primitive types to the given list of facets
        ///  
        /// The source TypeUsage
        /// The PrimativeType of the target 
        private static void ApplyPrimitiveTypePropertyFacets(TypeUsage sourceType, ref TypeUsage targetType) 
        {
            Dictionary newFacets = targetType.Facets.ToDictionary(f => f.Name); 
            bool madeChange = false;
            foreach (Facet sourceFacet in sourceType.Facets)
            {
 
                Facet targetFacet;
                if(newFacets.TryGetValue(sourceFacet.Name, out targetFacet)) 
                { 
                    if (!targetFacet.Description.IsConstant)
                    { 
                        madeChange = true;
                        newFacets[targetFacet.Name] = Facet.Create(targetFacet.Description, sourceFacet.Value);
                    }
                } 
                else
                { 
                    madeChange = true; 
                    newFacets.Add(sourceFacet.Name, sourceFacet);
                } 
            }

            if (madeChange)
            { 
                targetType = TypeUsage.Create(targetType.EdmType, newFacets.Values);
            } 
        } 

        ///  
        /// Populate the facets on the TypeUsage object fora property
        /// 
        /// The property containing the information
        /// The type usage object where to populate facet 
        /// The provider manifest to be used for conversion
        private static void PopulateGeneralFacets(Som.StructuredProperty somProperty, 
                                                  DbProviderManifest providerManifest, 
                                                  ref TypeUsage propertyTypeUsage)
        { 
            bool madeChanges = false;
            Dictionary facets = propertyTypeUsage.Facets.ToDictionary(f => f.Name);
            if (!somProperty.Nullable)
            { 
                facets[DbProviderManifest.NullableFacetName] = Facet.Create(MetadataItem.NullableFacetDescription, false);
                madeChanges = true; 
            } 

            if (somProperty.Default != null) 
            {
                facets[DbProviderManifest.DefaultValueFacetName] = Facet.Create(MetadataItem.DefaultValueFacetDescription, somProperty.DefaultAsObject);
                madeChanges = true;
            } 

            //This is not really a general facet 
            //If we are dealing with a 1.1 Schema, Add a facet for CollectionKind 
            if (somProperty.Schema.SchemaVersion == XmlConstants.EdmVersionForV1_1)
            { 
                Facet newFacet = Facet.Create(MetadataItem.CollectionKindFacetDescription, somProperty.CollectionKind);
                facets.Add(newFacet.Name, newFacet);
                madeChanges = true;
            } 

            if (madeChanges) 
            { 
                propertyTypeUsage = TypeUsage.Create(propertyTypeUsage.EdmType, facets.Values);
            } 
        }

        private static DataSpace GetDataSpace(DbProviderManifest providerManifest)
        { 
            Debug.Assert(providerManifest != null, "null provider manifest will be consider as SSpace");
            // Target attributes is for types and sets in target space. 
            if (providerManifest is EdmProviderManifest) 
            {
                return DataSpace.CSpace; 
            }
            else
            {
                return DataSpace.SSpace; 
            }
        } 
 
        /// 
        /// Get a primitive type when converting a CSDL schema 
        /// 
        /// The schema type representing the primitive type
        /// The provider manifest for retrieving the store types
        private static PrimitiveType GetSsdlPrimitiveType(Som.ScalarType scalarType, 
                                                          DbProviderManifest providerManifest)
        { 
            PrimitiveType returnValue = null; 
            string scalarTypeName = scalarType.Name;
 
            foreach (PrimitiveType primitiveType in providerManifest.GetStoreTypes())
            {
                if (primitiveType.Name == scalarTypeName)
                { 
                    returnValue = primitiveType;
                    break; 
                } 
            }
 
            Debug.Assert(scalarType != null, "Som scalar type should always resolve to a primitive type");
            return returnValue;
        }
 
        // This will update the sentinel values in the facets if required
        private static void UpdateSentinelValuesInFacets(ref TypeUsage typeUsage) 
        { 
            // For string and decimal types, replace the sentinel by the max possible value
            PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType; 
            if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String ||
                primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary)
            {
                Facet maxLengthFacet = typeUsage.Facets[EdmProviderManifest.MaxLengthFacetName]; 
                if (Helper.IsUnboundedFacetValue(maxLengthFacet))
                { 
                    typeUsage = typeUsage.ShallowCopy( 
                            new FacetValues{ MaxLength = Helper.GetFacet(primitiveType.FacetDescriptions,
                                                                EdmProviderManifest.MaxLengthFacetName).MaxValue }); 
                }
            }

        } 

        ///  
        /// Get the type usage for a structured primitive property when converting a CSDL schema 
        /// 
        /// Som Property that contains the type for which we need to get the mapping provider type 
        /// The item collection for currently existing metadata objects
        private static TypeUsage GetCsdlPrimitiveTypeUsageWithFacets(Som.StructuredProperty somProperty,
                                                      ConversionCache convertedItemCache)
        { 
            Debug.Assert(somProperty.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
            // try to get the instance of the primitive type from the item collection so that it back pointer is set. 
            EdmType propertyType = convertedItemCache.ItemCollection.GetItem(somProperty.TypeUsage.EdmType.FullName); 
            TypeUsage typeUsage = null;
            if (somProperty.CollectionKind != CollectionKind.None) 
            {
                propertyType = new CollectionType(propertyType);
                typeUsage = TypeUsage.Create(propertyType);
            } 
            else
            { 
                typeUsage = TypeUsage.Create(propertyType); 
                ApplyPrimitiveTypePropertyFacets(somProperty.TypeUsage, ref typeUsage);
            } 
            return typeUsage;
        }
        #endregion
 
        #region Nested types
        ///  
        /// Cache containing item collection and type usages to support looking up and generating 
        /// metadata types.
        ///  
        internal class ConversionCache
        {
            #region Fields
            internal readonly ItemCollection ItemCollection; 
            private readonly Dictionary _nullFacetsTypeUsage;
            private readonly Dictionary _nullFacetsCollectionTypeUsage; 
            #endregion 

            #region Constructors 
            internal ConversionCache(ItemCollection itemCollection)
            {
                this.ItemCollection = itemCollection;
                this._nullFacetsTypeUsage = new Dictionary(); 
                this._nullFacetsCollectionTypeUsage = new Dictionary();
            } 
            #endregion 

            #region Methods 
            /// 
            /// Gets type usage for the given type with null facet values. Caches usage to avoid creating
            /// redundant type usages.
            ///  
            internal TypeUsage GetTypeUsageWithNullFacets(EdmType edmType)
            { 
                // check for cached result 
                TypeUsage result;
                if (_nullFacetsTypeUsage.TryGetValue(edmType, out result)) 
                {
                    return result;
                }
 
                // construct result
                result = TypeUsage.Create(edmType, FacetValues.NullFacetValues); 
 
                // cache result
                _nullFacetsTypeUsage.Add(edmType, result); 

                return result;
            }
 
            /// 
            /// Gets collection type usage for the given type with null facet values. Caches usage to avoid creating 
            /// redundant type usages. 
            /// 
            internal TypeUsage GetCollectionTypeUsageWithNullFacets(EdmType edmType) 
            {
                // check for cached result
                TypeUsage result;
                if (_nullFacetsCollectionTypeUsage.TryGetValue(edmType, out result)) 
                {
                    return result; 
                } 

                // construct collection type from cached element type 
                TypeUsage elementTypeUsage = GetTypeUsageWithNullFacets(edmType);
                result = TypeUsage.Create(new CollectionType(elementTypeUsage), FacetValues.NullFacetValues);

                // cache result 
                _nullFacetsCollectionTypeUsage.Add(edmType, result);
 
                return result; 
            }
            #endregion 
        }
        #endregion
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK