ObjectContextServiceProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Server / System / Data / Services / Providers / ObjectContextServiceProvider.cs / 1 / ObjectContextServiceProvider.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the interface definition for web data service
//      data sources. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data;
    using System.Data.EntityClient;
    using System.Data.Metadata.Edm;
    using System.Data.Objects; 
    using System.Data.Services.Caching;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.Linq;
    using System.Reflection; 
    using System.Text;
    using System.Xml;

    #endregion Namespaces. 

    ///  
    /// Provides a reflection-based IDataServiceProvider implementation. 
    /// 
    [DebuggerDisplay("ObjectContextServiceProvider: {Type}")] 
    internal class ObjectContextServiceProvider : BaseServiceProvider
    {
        #region Private fields.
 
        /// 
        /// List of objects that we need to be replaced. The key value 
        /// indicates the new instance of the type with whatever values 
        /// are specified in the payload. The value is the actual object
        /// which is attached to the object context 
        /// 
        private Dictionary objectsToBeReplaced = new Dictionary();

        ///  
        /// List of cspace types for which ospace metadata couldn't be found.
        ///  
        private List typesWithoutOSpaceMetadata; 

        #endregion Private fields. 

        /// 
        /// Initializes a new System.Data.Services.ReflectionServiceProvider instance.
        ///  
        /// Metadata for this provider.
        /// instance of the data source provider. 
        internal ObjectContextServiceProvider(MetadataCacheItem metadata, object dataSourceInstance) 
            : base(metadata, dataSourceInstance)
        { 
            this.typesWithoutOSpaceMetadata = new List();
        }

        /// Gets a value indicating whether null propagation is required in expression trees. 
        public override bool NullPropagationRequired
        { 
            get { return false; } 
        }
 
        /// 
        /// Provides a name for the context in which all resource containers are.
        /// 
        public override string ResourceContextName 
        {
            get 
            { 
                return this.ObjectContext.DefaultContainerName;
            } 
        }

        /// Strongly-types instance being reflected upon.
        private ObjectContext ObjectContext 
        {
            get 
            { 
                return (ObjectContext)this.CurrentDataSource;
            } 
        }

        /// 
        /// Gets the container to the given navigation property 
        /// The declaring type container name refers to the entity set that the declaring type belongs to
        ///  
        /// name of the entity container that the declaring type belongs to 
        /// declaring type
        /// resource navigation property 
        /// name of the container that this property refers to
        public override ResourceContainer GetContainer(string declaringTypeContainerName, Type declaringResourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(!String.IsNullOrEmpty(declaringTypeContainerName), "!String.IsNullOrEmpty(declaringTypeContainerName)"); 
            Debug.Assert(declaringResourceType != null && resourceProperty != null, "declaringResourceType != null && resourceProperty != null");
 
            EntitySet entitySet = this.GetEntitySet(declaringTypeContainerName); 
            Debug.Assert(entitySet != null, "entitySet != null -- GetEntitySet should never return null");
 
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(declaringResourceType);
            EntityType entityType = this.ObjectContext.MetadataWorkspace.GetItem(resourceType.FullName, DataSpace.CSpace);
            Debug.Assert(entityType != null, "entityType != null");
 
            NavigationProperty navigationProperty;
            entityType.NavigationProperties.TryGetValue(resourceProperty.Name, false /*ignoreCase*/, out navigationProperty); 
            Debug.Assert(navigationProperty != null, "navigationProperty != null"); 

            ResourceContainer result = null; 
            foreach (EntitySetBase set in entitySet.EntityContainer.BaseEntitySets)
            {
                if (set.BuiltInTypeKind != BuiltInTypeKind.AssociationSet)
                { 
                    continue;
                } 
 
                AssociationSet associationSet = (AssociationSet)set;
                if (associationSet.ElementType == navigationProperty.RelationshipType) 
                {
                    AssociationSetEnd setEnd = associationSet.AssociationSetEnds[navigationProperty.FromEndMember.Name];
                    if (setEnd.EntitySet == entitySet)
                    { 
                        entitySet = associationSet.AssociationSetEnds[navigationProperty.ToEndMember.Name].EntitySet;
                        string entitySetName = GetEntitySetName(entitySet.Name, entitySet.EntityContainer.Name, this.ObjectContext.DefaultContainerName == entitySet.EntityContainer.Name); 
                        result = ((IDataServiceProvider)this).TryResolveContainerName(entitySetName); 
                        break;
                    } 
                }
            }

            Debug.Assert(result != null, "result != null -- we should be able to find the entity set for the given navigation property"); 
            return result;
        } 
 
        /// Gets the name of the container that holds this resource type.This method is called for open types only
        /// Resource to get container for. 
        /// 
        /// The name of the container for the specified resource; null if it cannot
        /// be determined.
        ///  
        public override ResourceContainer GetContainerForResourceType(Type resourceType)
        { 
            throw Error.NotSupported(); 
        }
 
        /// 
        /// Returns the metadata in edm format
        /// 
        /// Writer to which metadata XML should be written. 
        public override void GetMetadata(XmlWriter xmlWriter)
        { 
            Debug.Assert(xmlWriter != null, "xmlWriter != null"); 
            InitializeObjectItemCollection(this.ObjectContext, this.Type.Assembly);
 
            var typeManager = new TypeManager(this.ObjectContext.MetadataWorkspace);
            BaseServiceProvider.WriteTopLevelSchemaElements(xmlWriter);
            bool entityContainerDefinitionWritten = false;
 
            // Write all the types in their respective namespaces
            foreach (KeyValuePair> typesInNamespace in typeManager.NamespaceAlongWithTypes) 
            { 
                BaseServiceProvider.WriteSchemaElement(xmlWriter, typesInNamespace.Key, this.CompatibleWithV1Schema);
 
                // Write the entity container in the same namespace as that of the type
                if (!entityContainerDefinitionWritten && typesInNamespace.Key == this.Type.Namespace)
                {
                    this.WriteEntityContainers(xmlWriter, typeManager.GetEntityContainers(), this.GetDefaultEntityContainer()); 
                    entityContainerDefinitionWritten = true;
                } 
 
                this.WriteEdmTypes(xmlWriter, typesInNamespace.Value);
                xmlWriter.WriteEndElement(); 
            }

            // If the entity container is in a different namespace than the types, then write the entity container definition
            // in a different namespace 
            if (!entityContainerDefinitionWritten)
            { 
                BaseServiceProvider.WriteSchemaElement(xmlWriter, this.Type.Namespace, this.CompatibleWithV1Schema); 
                this.WriteEntityContainers(xmlWriter, typeManager.GetEntityContainers(), this.GetDefaultEntityContainer());
                xmlWriter.WriteEndElement(); 
            }

            // These end elements balance the elements written out in WriteTopLevelSchemaElements
            xmlWriter.WriteEndElement(); 
            xmlWriter.WriteEndElement();
            xmlWriter.Flush(); 
        } 

        ///  
        /// Get the list of etag property names given the entity set name and the instance of the resource
        /// 
        /// name of the entity set
        /// clr type of the resource whose etag properties need to be fetched 
        /// list of etag property names
        public override ICollection GetETagProperties(string containerName, Type resourceClrType) 
        { 
            Debug.Assert(!String.IsNullOrEmpty(containerName), "container name must not be empty");
            Debug.Assert(resourceClrType != null, "clrType cannot be null"); 

            EntitySetBase entitySet = this.GetEntitySet(containerName);
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType);
            EntityType entityType = this.ObjectContext.MetadataWorkspace.GetItem(resourceType.FullName, DataSpace.CSpace); 
            Debug.Assert(entityType != null, "entityType != null");
            List etagProperties = new List(); 
 
            // Workspace associated directly with the ObjectContext has metadata only about OSpace, CSpace and OCSpace.
            // Since GetRequiredOriginalValueMembers depends on mapping information (CSSpace metadata), 
            // we need to make sure we call this API on a workspace which has information about the CS Mapping.
            // Hence getting workspace from the underlying Entity connection.
            MetadataWorkspace workspace = ((EntityConnection)this.ObjectContext.Connection).GetMetadataWorkspace();
            foreach (EdmMember member in workspace.GetRequiredOriginalValueMembers(entitySet, entityType)) 
            {
                ResourceProperty property = resourceType.TryResolvePropertyName(member.Name); 
                Debug.Assert(property != null, "property != null"); 
                Debug.Assert(property.TypeKind == ResourceTypeKind.Primitive, "property.TypeKind == ResourceTypeKind.Primitive");
 
                // Ignore key properties if they are part of etag, since the uri already has the key information
                // and it makes no sense to duplicate them in etag
                if (!property.IsOfKind(ResourcePropertyKind.Key))
                { 
                    etagProperties.Add(property);
                } 
            } 

            return etagProperties; 
        }

        #region IUpdatable Members
 
        /// 
        /// Creates the resource of the given type and belonging to the given container 
        ///  
        /// container name to which the resource needs to be added
        /// full type name i.e. Namespace qualified type name of the resource 
        /// object representing a resource of given type and belonging to the given container
        public override object CreateResource(string containerName, string fullTypeName)
        {
            ResourceType resourceType = ((IDataServiceProvider)this).TryResolveTypeName(fullTypeName); 
            Debug.Assert(resourceType != null, "resourceType != null");
 
            if (resourceType.Type.IsAbstract) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.CannotCreateInstancesOfAbstractType(resourceType.FullName)); 
            }

            object resource = resourceType.ConstructorDelegate();
            if (containerName != null) 
            {
                this.ObjectContext.AddObject(containerName, resource); 
            } 

            return resource; 
        }

        /// 
        /// Gets the resource of the given type that the query points to 
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource 
        /// object representing a resource of given type and as referenced by the query
        public override object GetResource(IQueryable query, string fullTypeName) 
        {
            Debug.Assert(query != null, "query != null");

            ObjectQuery objectQuery = query as ObjectQuery; 
            Debug.Assert(objectQuery != null, "objectQuery != null - otherwise we're passed an IQueryable we didn't produce");
 
            objectQuery.MergeOption = MergeOption.AppendOnly; 
            object result = null;
            foreach (object resource in objectQuery) 
            {
                if (result != null)
                {
                    throw new InvalidOperationException(Strings.SingleResourceExpected); 
                }
 
                result = resource; 
            }
 
            if (result != null && fullTypeName != null)
            {
                ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(result.GetType());
                Debug.Assert(resourceType != null, "the result must return a known type"); 
                if (resourceType.FullName != fullTypeName)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.TargetElementTypeOfTheUriSpecifiedDoesNotMatchWithTheExpectedType(resourceType.FullName, fullTypeName)); 
                }
            } 

            return result;
        }
 
        /// 
        /// Resets the value of the given resource to its default value 
        ///  
        /// resource whose value needs to be reset
        /// same resource with its value reset 
        public override object ResetResource(object resource)
        {
            Debug.Assert(resource != null, "resource != null");
 
            Type resourceClrType = resource.GetType();
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType); 
            if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
            {
                // For entity types, do the following: 
                // create a new instance of the same type and set the key values on it
                // detach the given instance and attach the new instance
                // mark all the properties as modified on the new instance so that the default values get persisted
                object newInstance = resourceType.ConstructorDelegate(); 

                // set the key value on the new instance 
                foreach (ResourceProperty property in resourceType.KeyProperties) 
                {
                    object propertyValue = property.GetValue(resource); 
                    property.SetValue(newInstance, propertyValue);
                }

                this.objectsToBeReplaced.Add(newInstance, resource); 
                return newInstance;
            } 
            else if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType) 
            {
                // For complex types, just return a brand new instance. 
                return resourceType.ConstructorDelegate();
            }

            return resource; 
        }
 
        ///  
        /// Sets the value of the given property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// value of the property
        public override void SetValue(object targetResource, string propertyName, object propertyValue) 
        {
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType()); 
            Debug.Assert(resourceType != null, "resourceType != null"); 
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName);
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            resourceProperty.SetValue(targetResource, propertyValue);
        }

        ///  
        /// Gets the value of the given property on the target object
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// the value of the property for the given target resource 
        public override object GetValue(object targetResource, string propertyName)
        {
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType());
            Debug.Assert(resourceType != null, "resourceType != null"); 
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName);
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            object resource = resourceProperty.GetValue(targetResource); 
            return resource;
        } 

        /// 
        /// Sets the value of the given reference property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property 
        public override void SetReference(object targetResource, string propertyName, object propertyValue)
        { 
            // Set the value of the reference property
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType());
            Debug.Assert(resourceType != null, "resourceType != null");
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
            resourceProperty.SetValue(targetResource, propertyValue); 
        } 

        ///  
        /// Adds the given value to the collection
        /// 
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be added
        public override void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) 
        { 
            Debug.Assert(targetResource != null, "propertyValue != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            Debug.Assert(resourceToBeAdded != null, "propertyValue != null");

            var entityToBeAdded = (System.Data.Objects.DataClasses.IEntityWithRelationships)resourceToBeAdded;
            ObjectStateEntry stateEntry = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(targetResource); 
            try
            { 
                // Get the EntityCollection value 
                object collection = targetResource.GetType().InvokeMember(
                    propertyName, 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
                    null,
                    targetResource,
                    new object[0], 
                    CultureInfo.InvariantCulture);
 
                Debug.Assert(collection != null, "collection != null"); 
                var end = (System.Data.Objects.DataClasses.IRelatedEnd)collection;
                if (stateEntry.State == EntityState.Added || stateEntry.State == EntityState.Unchanged) 
                {
                    end.Add(entityToBeAdded);
                }
                else 
                {
                    end.Attach(entityToBeAdded); 
                } 
            }
            catch (TargetInvocationException e) 
            {
                ErrorHandler.HandleTargetInvocationException(e);
                throw;
            } 
        }
 
        /// Applies expansions to the specified . 
        ///  object to expand.
        /// A collection of ordered  paths. 
        /// 
        /// An  object of the same type as the given ,
        /// with the results including the specified .
        ///  
        /// 
        /// This method may modify the  to indicate which expansions 
        /// are included. 
        ///
        /// The returned  may implement the  
        /// interface to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects.
        /// 
        public override IEnumerable ApplyExpansions(IQueryable queryable, ICollection expandPaths) 
        {
            IExpandProvider provider = this.CurrentDataSource as IExpandProvider; 
            if (provider != null) 
            {
                return provider.ApplyExpansions(queryable, expandPaths); 
            }
            else
            {
                // Start by adding all the containers for the root type, in case the query originates from 
                // a service operation and we don't know what the origin is.
                HashSet containers = new HashSet(EqualityComparer.Default); 
                foreach (var set in this.EntitySets) 
                {
                    if (set.Value.ElementType.IsAssignableFrom(queryable.ElementType)) 
                    {
                        containers.Add(set.Value);
                    }
                } 

                bool useBasicExpandProvider = false; 
                foreach (ExpandSegmentCollection path in expandPaths) 
                {
                    if (!useBasicExpandProvider) 
                    {
                        if (path.Any(segment => segment.HasFilterOrMaxResults))
                        {
                            useBasicExpandProvider = true; 
                        }
                        else 
                        { 
                            // If we expand properties that come from a container we've already encountered,
                            // we should use the basic provider; otherwise the EF materializer will throw because 
                            // tracking is turned off for querying.
                            foreach (ExpandSegment segment in path)
                            {
                                Debug.Assert( 
                                    segment.Container != null,
                                    "segment.Container != null -- otherwise we have an open property in EF or forgot to bind a segment"); 
                                if (!containers.Add(segment.Container)) 
                                {
                                    useBasicExpandProvider = true; 
                                    break;
                                }
                            }
                        } 
                    }
 
                    if (path.Count > 8) 
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.ObjectContext_ExpandTooDeep); 
                    }
                }

                if (useBasicExpandProvider) 
                {
                    return new BasicExpandProvider(this, false).ApplyExpansions(queryable, expandPaths); 
                } 

                MethodInfo includeMethod = typeof(ObjectContextServiceProvider).GetMethod("Include", BindingFlags.Static | BindingFlags.NonPublic); 
                includeMethod = includeMethod.MakeGenericMethod(queryable.ElementType);
                IQueryable result = queryable;
                foreach (ExpandSegmentCollection path in expandPaths)
                { 
                    string dottedPath = JoinIdentifiers(path);
                    result = (IQueryable)includeMethod.Invoke(null, new object[] { result, dottedPath }); 
                } 

                return result; 
            }
        }

        ///  
        /// Removes the given value from the collection
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// value of the property which needs to be removed 
        public override void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            Debug.Assert(resourceToBeRemoved != null, "resourceToBeRemoved != null");
 
            try 
            {
                // Get the EntityCollection value 
                object collection = targetResource.GetType().InvokeMember(
                    propertyName,
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
                    null, 
                    targetResource,
                    new object[0], 
                    CultureInfo.InvariantCulture); 

                Debug.Assert(collection != null, "collection != null"); 

                // For many to many relationships, we need to attach the other end first, otherwise
                // the collection is null and hence removing it won't have any effect.
                collection.GetType().InvokeMember( 
                    "Attach",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
                    null, 
                    collection,
                    new object[] { resourceToBeRemoved }, 
                    CultureInfo.InvariantCulture);

                collection.GetType().InvokeMember(
                    "Remove", 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, 
                    collection, 
                    new object[] { resourceToBeRemoved },
                    CultureInfo.InvariantCulture); 
            }
            catch (TargetInvocationException exception)
            {
                ErrorHandler.HandleTargetInvocationException(exception); 
                throw;
            } 
        } 

        ///  
        /// Delete the given resource
        /// 
        /// resource that needs to be deleted
        public override void DeleteResource(object resource) 
        {
            this.ObjectContext.DeleteObject(resource); 
        } 

        ///  
        /// Saves all the pending changes made till now
        /// 
        public override void SaveChanges()
        { 
            // handle the resource which need to be replaced.
            foreach (KeyValuePair objectToBeReplaced in this.objectsToBeReplaced) 
            { 
                // Get the key from the actual object
                EntityKey entityKey = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(objectToBeReplaced.Value).EntityKey; 

                // Apply property changes as specified in the new object.
                this.ObjectContext.ApplyPropertyChanges(entityKey.EntitySetName, objectToBeReplaced.Key);
            } 

            // clear all these once we have processed all the entities that need to be replaced. 
            this.objectsToBeReplaced.Clear(); 

            // Save Changes 
            this.ObjectContext.SaveChanges();
        }

        ///  
        /// Returns the actual instance of the resource represented by the given resource object
        ///  
        /// object representing the resource whose instance needs to be fetched 
        /// The actual instance of the resource represented by the given resource object
        public override object ResolveResource(object resource) 
        {
            Debug.Assert(resource != null, "resource != null");
            return resource;
        } 

        ///  
        /// Revert all the pending changes. 
        /// 
        public override void ClearChanges() 
        {
            // Detach all the existing entries in the object context
            foreach (ObjectStateEntry entry in this.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged))
            { 
                // entry.State != Entry.Detached: Also, if they are stub entries (no entity object
                // associated with the entry yet - these get automatically populated when we query the related entity), 
                // they also get automatically detached once we detach the associated entity). 
                // Both Entity and IsRelationship property throws if the entry is detached.
                // !entry.IsRelationship: We just need to remove the key entries. 
                // While detaching the key entries, the relationship entries associated
                // with the key entries also get detached.
                // entry.Entity != null:  Since they are no ordering gaurantees, the stub key entries
                // can come first, we need to skip these. 
                if (entry.State != EntityState.Detached && !entry.IsRelationship && entry.Entity != null)
                { 
                    this.ObjectContext.Detach(entry.Entity); 
                }
            } 

            // clear the list of objects that need to be special handled during save changes for replace semantics
            this.objectsToBeReplaced.Clear();
        } 

        #endregion 
 
#if ASTORIA_CONTAINMENT
 
        /// 
        /// Returns an object that can enumerate all 
        /// instances that apply to this model.
        ///  
        /// 
        /// An object that can enumerate all  
        /// instances that apply to this model. 
        /// 
        protected override IEnumerable EnumerateAccessPathAttributes() 
        {
            // To synthesize AccessPathAttribute instances, we look for Association types with the
            // ReferentialConstraint property set. Additionally we have attributes on EntitySet
            // to determine whether top-level visibility is enabled, and on NavigationProperty to 
            // determine whether an access path is canonical or non-canonical.
            Debug.Assert(this.ObjectContext != null, "this.ObjectContext != null"); 
            MetadataWorkspace workspace = this.ObjectContext.MetadataWorkspace; 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace))
            { 
                foreach (AssociationSet association in container.BaseEntitySets.OfType())
                {
                    AssociationType type = association.ElementType;
                    foreach (ReferentialConstraint constraint in type.ReferentialConstraints) 
                    {
                        EntitySet fromSet = association.AssociationSetEnds[constraint.ToRole.Name].EntitySet; 
                        NavigationProperty fromNavigationProperty = PropertyForEnd(fromSet, constraint.ToRole); 
                        if (fromNavigationProperty == null)
                        { 
                            // If there is no navigation property, no traversal is possible - simply ignore.
                            continue;
                        }
 
                        bool canonical = GetNavigationPropertyCanonical(fromNavigationProperty);
                        EntitySet targetSet = association.AssociationSetEnds[constraint.FromRole.Name].EntitySet; 
                        bool topLevelAccess = GetEntitySetTopLevelAccess(targetSet); 
                        AccessPathAttribute attribute;
                        if (canonical) 
                        {
                            CanonicalAccessPathAttribute ca = new CanonicalAccessPathAttribute();
                            ca.TopLevelAccess = topLevelAccess;
                            attribute = ca; 
                        }
                        else 
                        { 
                            attribute = new AccessPathAttribute();
                        } 

                        attribute.AnnotatedContainer = this.EntitySets[targetSet.Name];
                        attribute.InternalChildKeyMapping = PropertyNamesToStrings(constraint.FromProperties);
                        attribute.InferredFromSchema = true; 
                        attribute.Parent = fromSet.Name;
                        attribute.InternalParentKeyMapping = PropertyNamesToStrings(constraint.ToProperties); 
                        attribute.ParentNavigationProperty = fromNavigationProperty.Name; 
                        yield return attribute;
                    } 
                }
            }
        }
 
#endif
 
        /// Checks that the applied configuration is consistent. 
        /// Instance of the data source for the provider.
        /// At this point in initialization, metadata trimming hasn't taken place. 
        protected override void CheckConfigurationConsistency(object dataSourceInstance)
        {
            base.CheckConfigurationConsistency(dataSourceInstance);
 
            // Check that rights are consistent in MEST scenarios.
            // 
            // Strictly we should only check for consistent visibility 
            // for all entity sets of a given type, however the current
            // metadata design doesn't differentiate between resource 
            // container types and resource container instances on
            // associations, and therefore all rights are checked at
            // the resource type level, which forces this check to have
            // consistent rights. 
            //
            // The only exception could be references which are not connected 
            // (technically those that are not targets, but in EDM all 
            // associations are two-way). These can have entity sets
            // with different rights, enforced at the container level. 

            // Discover connected types.
            HashSet connectedTypes = new HashSet(EqualityComparer.Default);
            foreach (ResourceType type in this.Types) 
            {
                foreach (ResourceProperty property in type.PropertiesDeclaredInThisType) 
                { 
                    if (property.TypeKind == ResourceTypeKind.EntityType)
                    { 
                        connectedTypes.Add(property.ResourceType);
                    }
                }
            } 

            // Discover containers of same type with conflicting rights. 
            Dictionary typeRights = new Dictionary(); 
            foreach (KeyValuePair containerEntry in this.EntitySets)
            { 
                Debug.Assert(containerEntry.Key != null, "containerEntry.Key != null");
                Debug.Assert(containerEntry.Value != null, "containerEntry.Value != null");

                ResourceType resourceType = containerEntry.Value.ResourceType; 

                // Disregard types that are not connected to any other types. 
                if (!connectedTypes.Contains(resourceType)) 
                {
                    continue; 
                }

                ResourceContainer previouslyFoundContainer;
                if (typeRights.TryGetValue(resourceType, out previouslyFoundContainer)) 
                {
                    if (containerEntry.Value.Rights != previouslyFoundContainer.Rights) 
                    { 
                        throw new InvalidOperationException(Strings.ObjectContext_DifferentContainerRights(
                            previouslyFoundContainer.Name, 
                            previouslyFoundContainer.Rights,
                            containerEntry.Value.Name,
                            containerEntry.Value.Rights));
                    } 
                }
                else 
                { 
                    typeRights.Add(resourceType, containerEntry.Value);
                } 
            }

            CheckNavigationPropertiesBound(dataSourceInstance);
        } 

        ///  
        /// Populates metadata from the given object context 
        /// 
        /// dictionary of already known types 
        /// list of already known entity sets
        protected override void PopulateMetadata(
            IDictionary knownTypes, IDictionary entitySets)
        { 
            Debug.Assert(knownTypes != null, "knownTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 
            Debug.Assert(this.ObjectContext != null, "this.ObjectContext != null"); 

            InitializeObjectItemCollection(this.ObjectContext, this.Type.Assembly); 
            MetadataWorkspace metadataWorkspace = this.ObjectContext.MetadataWorkspace;

            // Create Resource types for all the top level entity types and complexTypes
            foreach (StructuralType edmType in metadataWorkspace.GetItems(DataSpace.CSpace)) 
            {
                if (edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || 
                    edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType) 
                {
                    // Populates metadata for the given types and all its base types 
                    if (PopulateTypeMetadata(metadataWorkspace, edmType, knownTypes) == null)
                    {
                        this.typesWithoutOSpaceMetadata.Add(edmType);
                    } 
                }
            } 
 
            foreach (EntityContainer entityContainer in metadataWorkspace.GetItems(DataSpace.CSpace))
            { 
                bool defaultEntityContainer = entityContainer.Name == this.ObjectContext.DefaultContainerName;

                // Get the list of entity sets (Ignore the relationship sets, since we won't allow that to be queried directly
                foreach (EntitySetBase entitySetBase in entityContainer.BaseEntitySets) 
                {
                    // Ignore all the association sets for the type being, since we are caching only entity sets 
                    if (entitySetBase.BuiltInTypeKind != BuiltInTypeKind.EntitySet) 
                    {
                        continue; 
                    }

                    EntitySet entitySet = (EntitySet)entitySetBase;
                    Type elementType = GetClrTypeForCSpaceType(metadataWorkspace, entitySet.ElementType); 
                    ResourceType resourceType = knownTypes[elementType];
                    string entitySetName = GetEntitySetName(entitySet.Name, entitySet.EntityContainer.Name, defaultEntityContainer); 
                    ResourceContainer resourceContainer = new ResourceContainer(entitySetName, resourceType); 
                    entitySets.Add(entitySetName, resourceContainer);
                } 
            }

            // Now go and populate the member information for each resource type
            foreach (ResourceType resourceType in knownTypes.Values) 
            {
                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive) 
                { 
                    continue;
                } 

                PopulateMemberMetadata(resourceType, metadataWorkspace, entitySets, knownTypes);
            }
        } 

        ///  
        /// Creates the object query for the given resource container and returns it 
        /// 
        /// resource container for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource container
        protected override IQueryable GetResourceContainerInstance(ResourceContainer resourceContainer)
        {
            Debug.Assert(resourceContainer != null, "resourceContainer != null"); 
            ObjectQuery result = this.InternalGetResourceContainerInstance(resourceContainer);
            result.MergeOption = MergeOption.NoTracking; 
            return result; 
        }
 
        /// 
        /// Populate types for metadata specified by the provider
        /// 
        /// list of types specified by the provider 
        /// list of already known types
        /// list of entity sets as specified in the data source type 
        protected override void PopulateMetadataForUserSpecifiedTypes( 
            IEnumerable userSpecifiedTypes, IDictionary knownTypes, IEnumerable entitySets)
        { 
            foreach (Type type in userSpecifiedTypes)
            {
                if (this.PopulateMetadataForType(type, knownTypes, entitySets) == null)
                { 
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName));
                } 
            } 

            // If there is a type in the model, for which we couldn't load the metadata, we should throw. 
            if (this.typesWithoutOSpaceMetadata.Count != 0)
            {
                throw new InvalidOperationException(Strings.ObjectContext_UnableToLoadMetadataForType(this.typesWithoutOSpaceMetadata[0].FullName));
            } 

            this.typesWithoutOSpaceMetadata = null; 
        } 

        ///  
        /// Populate metadata for the given clr type.
        /// 
        /// type whose metadata needs to be loaded.
        /// list of already known resource types. 
        /// list of entity sets as specified in the data source.
        /// resource type containing metadata for the given clr type. 
        protected override ResourceType PopulateMetadataForType( 
            Type type,
            IDictionary knownTypes, 
            IEnumerable entitySets)
        {
            ResourceType resourceType;
            if (!knownTypes.TryGetValue(type, out resourceType)) 
            {
                InitializeObjectItemCollection(this.ObjectContext, type.Assembly); 
                ObjectItemCollection objectItemCollection = (ObjectItemCollection)this.ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.OSpace); 
                StructuralType ospaceType, cspaceType;
                if (objectItemCollection.TryGetItem(type.FullName, out ospaceType)) 
                {
                    if (this.ObjectContext.MetadataWorkspace.TryGetEdmSpaceType(ospaceType, out cspaceType))
                    {
                        ResourceType baseType = null; 
                        if (cspaceType.BaseType != null)
                        { 
                            baseType = this.PopulateMetadataForType(type.BaseType, knownTypes, entitySets); 
                        }
 
                        resourceType = CreateResourceType(cspaceType, type, baseType, knownTypes);
                        this.typesWithoutOSpaceMetadata.Remove(cspaceType);
                    }
                } 
            }
 
            return resourceType; 
        }
 
        /// 
        /// Checks that all navigation properties are bound to some association set for every entity set.
        /// 
        /// Instance of the data source for the provider. 
        private static void CheckNavigationPropertiesBound(object dataSourceInstance)
        { 
            // For every navigation property, ensure that all of the EntitySets that can 
            // take their EntityType have an AssociationSet of the appropriate Association type.
            Debug.Assert(dataSourceInstance != null, "dataSourceInstance != null"); 
            MetadataWorkspace workspace = ((ObjectContext)dataSourceInstance).MetadataWorkspace;
            foreach (EntityType type in workspace.GetItems(DataSpace.CSpace))
            {
                foreach (NavigationProperty navigationProperty in type.NavigationProperties) 
                {
                    foreach (EntitySet entitySet in GetEntitySetsForType(workspace, type)) 
                    { 
                        IEnumerable entitySetsWithAssocation = GetEntitySetsWithAssociationSets(
                            workspace, 
                            navigationProperty.RelationshipType,
                            navigationProperty.FromEndMember);
                        if (!entitySetsWithAssocation.Contains(entitySet))
                        { 
                            throw new InvalidOperationException(Strings.ObjectContext_NavigationPropertyUnbound(
                                navigationProperty.Name, 
                                type.FullName, 
                                entitySet.Name));
                        } 
                    }
                }
            }
        } 

        /// Finds a target container for the specified . 
        /// CLR type to find. 
        /// Containers to examine.
        /// The resolved ; never null. 
        private static ResourceContainer FindSampleTargetContainer(Type clrType, IEnumerable containers)
        {
            Debug.Assert(clrType != null, "clrType != null");
            Debug.Assert(containers != null, "clrType != containers"); 

            ResourceContainer result = null; 
            foreach (ResourceContainer container in containers) 
            {
                if (container.ElementType.IsAssignableFrom(clrType)) 
                {
                    result = container;
                    break;
                } 
            }
 
            Debug.Assert(result != null, "result != null - otherwise unable to find container for " + clrType); 
            return result;
        } 

        /// Gets the CLR type mapped to the specified C-Space type.
        /// Workspace in which the type is defined.
        /// C-Space type whose matching clr type needs to be looked up. 
        /// The resolved  for the given .
        private static Type GetClrTypeForCSpaceType(MetadataWorkspace workspace, StructuralType edmType) 
        { 
            Debug.Assert(workspace != null, "workspace != null");
            Debug.Assert(edmType != null, "edmType != null"); 
            Debug.Assert(
               edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
               "Must be entityType or complexType");
 
            StructuralType ospaceType;
            if (workspace.TryGetObjectSpaceType(edmType, out ospaceType)) 
            { 
                ObjectItemCollection objectItemCollection = (ObjectItemCollection)workspace.GetItemCollection(DataSpace.OSpace);
                return objectItemCollection.GetClrType(ospaceType); 
            }

            return null;
        } 

        ///  
        /// Gets all  instance that may hold an entity of type . 
        /// 
        /// Workspace with metadata. 
        /// Entity type to get entity sets for.
        /// An enumeration of  instances that can hold .
        private static IEnumerable GetEntitySetsForType(MetadataWorkspace workspace, EntityType type)
        { 
            Debug.Assert(type != null, "type != null");
            Debug.Assert(workspace != null, "workspace != null"); 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace)) 
            {
                foreach (EntitySet entitySet in container.BaseEntitySets.OfType()) 
                {
                    if (IsAssignableFrom(entitySet.ElementType, type))
                    {
                        yield return entitySet; 
                    }
                } 
            } 
        }
 
        /// 
        /// Gets all entity sets that participate as members for the specified .
        /// 
        /// Workspace with metadata. 
        /// Type of assocation to check.
        /// Member of association to check. 
        ///  
        /// All  instances that are are on the  role for
        /// some association of . 
        /// 
        private static IEnumerable GetEntitySetsWithAssociationSets(
            MetadataWorkspace workspace,
            RelationshipType associationType, 
            RelationshipEndMember member)
        { 
            Debug.Assert(workspace != null, "workspace != null"); 
            Debug.Assert(associationType != null, "associationType != null");
            Debug.Assert(member != null, "member != null"); 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace))
            {
                foreach (AssociationSet associationSet in container.BaseEntitySets.OfType())
                { 
                    if (associationSet.ElementType == associationType)
                    { 
                        foreach (AssociationSetEnd end in associationSet.AssociationSetEnds) 
                        {
                            if (end.CorrespondingAssociationEndMember == member) 
                            {
                                yield return end.EntitySet;
                            }
                        } 
                    }
                } 
            } 
        }
 
        /// Reads the TopLevelAccess property from the specified .
        /// Set to read attribute from.
        /// true or false depending on the value; true if the value is missing.
        private static bool GetEntitySetTopLevelAccess(EntitySet set) 
        {
            Debug.Assert(set != null, "set != null"); 
            const string TopLevelAttributeName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebAccessTopLevelAccessAttribute; 
            bool result = true;
            MetadataProperty property; 
            if (set.MetadataProperties.TryGetValue(TopLevelAttributeName, false /* ignoreCase */, out property))
            {
                string text = (string)property.Value;
                if (String.IsNullOrEmpty(text)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_TopLevelEmpty(set.Name)); 
                } 

                if (!bool.TryParse(text, out result)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_TopLevelIncorrect(property.Name, text));
                }
            } 

            return result; 
        } 

        /// Gets the MIME type specified for the specified member. 
        /// C-Space member for which we need to find the C-Space mime type attribute.
        /// The MIME type for the specified member, null if none deifned.
        private static string GetMimeTypeForMappedMember(EdmMember csdlMember)
        { 
            const string MimePropertyName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebMimeTypeAttributeName;
            string mimeType = null; 
            MetadataProperty property; 
            if (csdlMember.MetadataProperties.TryGetValue(MimePropertyName, false /* ignoreCase */, out property))
            { 
                mimeType = (string)property.Value;
                if (mimeType != null && mimeType.Length == 0)
                {
                    throw new InvalidOperationException(Strings.ObjectContext_MimeTypeAttributeEmpty(csdlMember.Name, csdlMember.DeclaringType.FullName)); 
                }
 
                if (!IsPrimitiveType(csdlMember.TypeUsage.EdmType)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_MimeTypeAttributeOnNonPrimitive(csdlMember.DeclaringType.FullName, csdlMember.Name, csdlMember.TypeUsage.EdmType.FullName)); 
                }
            }

            return mimeType; 
        }
 
#if ASTORIA_CONTAINMENT 

        ///  
        /// Reads the AccessPath canonical-ness property from the specified .
        /// 
        /// Property to read attribute from.
        /// true or false depending on the value; false if the value is missing. 
        private static bool GetNavigationPropertyCanonical(NavigationProperty property)
        { 
            Debug.Assert(property != null, "property != null"); 
            const string AccessPathAttributeName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebAccessPathAttribute;
            bool result = false; 
            MetadataProperty metadata;
            if (property.MetadataProperties.TryGetValue(AccessPathAttributeName, false /* ignoreCase */, out metadata))
            {
                string text = (string)metadata.Value; 
                if (String.IsNullOrEmpty(text))
                { 
                    throw new InvalidOperationException(Strings.ObjectContext_AccessPathEmpty(property.Name)); 
                }
 
                if (text == XmlConstants.DataWebAccessPathCanonicalValue)
                {
                    result = true;
                } 
                else if (text == XmlConstants.DataWebAccessPathNonCanonicalValue)
                { 
                    result = false; 
                }
                else 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_AccessPathIncorrect(property.Name, text));
                }
            } 

            return result; 
        } 

#endif 

        /// Generic method to invoke an Include method on an ObjectQuery source.
        /// Element type of the source.
        /// Source query. 
        /// Path to include.
        /// A new query that includes  in . 
        private static ObjectQuery Include(IQueryable query, string dottedPath) 
        {
            Debug.Assert(query != null, "query != null"); 
            Debug.Assert(dottedPath != null, "dottedPath != null");

            ObjectQuery typedQuery = (ObjectQuery)query;
            return typedQuery.Include(dottedPath); 
        }
 
        /// Checks whether  may be assigned to . 
        /// Type to check assignment to.
        /// Type to check assignment from. 
        /// 
        /// true if an instance of  can be assigned to a variable of
        /// ; false otherwise.
        ///  
        private static bool IsAssignableFrom(EntityType baseType, EntityType derivedType)
        { 
            while (derivedType != null) 
            {
                if (derivedType == baseType) 
                {
                    return true;
                }
 
                derivedType = (EntityType)derivedType.BaseType;
            } 
 
            return false;
        } 

        /// Checks whether the specified type is a known primitive type.
        /// Type to check.
        /// true if the specified type is known to be a primitive type; false otherwise. 
        private static bool IsPrimitiveType(EdmType type)
        { 
            Debug.Assert(type != null, "type != null"); 
            if (type.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType)
            { 
                return false;
            }
            else
            { 
                Debug.Assert(
                    WebUtil.IsPrimitiveType(((PrimitiveType)type).ClrEquivalentType), 
                    "WebUtil.IsPrimitiveType(((PrimitiveType)type).ClrEquivalentType) - all EDM primitive types are Astoria primitive types"); 
                return true;
            } 
        }

        /// Joins the list of segment identifiers by dots.
        /// List of segments to join. 
        /// A string with the identifiers joined by dots.
        private static string JoinIdentifiers(List segments) 
        { 
            Debug.Assert(segments != null, "segments != null");
 
            int capacity = 0;
            foreach (ExpandSegment segment in segments)
            {
                capacity += segment.Name.Length; 
            }
 
            capacity += segments.Count - 1; 

            StringBuilder builder = new StringBuilder(capacity); 
            foreach (ExpandSegment segment in segments)
            {
                if (builder.Length > 0)
                { 
                    builder.Append('.');
                } 
 
                builder.Append(segment.Name);
            } 

            return builder.ToString();
        }
 
        /// 
        /// Populates the metadata for the given type and its base type 
        ///  
        /// metadata workspace containing all the metadata information
        ///  type whose metadata needs to be populated  
        /// list of known types 
        /// returns the resource type corresponding to the given edmType
        private static ResourceType PopulateTypeMetadata(
            MetadataWorkspace workspace, 
            StructuralType edmType,
            IDictionary knownTypes) 
        { 
            Debug.Assert(
                edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || 
                edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                "type must be entity or complex type");

            ResourceType resourceType = null; 
            Type clrType = GetClrTypeForCSpaceType(workspace, edmType);
            if (clrType != null && !knownTypes.TryGetValue(clrType, out resourceType)) 
            { 
                ResourceType baseType = null;
                if (edmType.BaseType != null) 
                {
                    baseType = PopulateTypeMetadata(workspace, (StructuralType)edmType.BaseType, knownTypes);
                }
 
                resourceType = CreateResourceType(edmType, clrType, baseType, knownTypes);
            } 
 
            return resourceType;
        } 

        /// 
        /// Creates a new instance of resource type given the cspace structural type and mapping clr type.
        ///  
        /// cspace structural type.
        /// mapping clr type for the given structural type. 
        /// the base resource type for the given resource type. 
        /// list of already known resource types.
        /// the new resource type instance created for the given cspace type. 
        private static ResourceType CreateResourceType(
            StructuralType cspaceType,
            Type clrType,
            ResourceType baseResourceType, 
            IDictionary knownTypes)
        { 
            ResourceTypeKind resourceTypeKind = cspaceType.BuiltInTypeKind == BuiltInTypeKind.EntityType ? ResourceTypeKind.EntityType : ResourceTypeKind.ComplexType; 
            ResourceType resourceType = new ResourceType(clrType, resourceTypeKind, baseResourceType, cspaceType.FullName, cspaceType.Name);
            knownTypes.Add(clrType, resourceType); 
            return resourceType;
        }

        ///  
        /// Populates the member metadata for the given type
        ///  
        /// resource type whose member metadata needs to be filled 
        /// workspace containing the metadata information
        /// Available entity sets. 
        /// list of already known types
        private static void PopulateMemberMetadata(
            ResourceType resourceType,
            MetadataWorkspace workspace, 
            IDictionary entitySets,
            IDictionary knownTypes) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
            Debug.Assert(workspace != null, "workspace != null"); 
            Debug.Assert(entitySets != null, "entitySets != null");

            // Find the type from the OSpace
            StructuralType edmType = workspace.GetItem(resourceType.FullName, DataSpace.CSpace); 
            foreach (EdmMember member in edmType.Members)
            { 
                // only look at the instance members 
                if (member.DeclaringType != edmType)
                { 
                    continue;
                }

                ResourceContainer resourceContainer = null; 
                ResourcePropertyKind kind = (ResourcePropertyKind)(-1);
                PropertyInfo propertyInfo = resourceType.Type.GetProperty(member.Name); 
                ResourceType propertyType = null; 
                switch (member.TypeUsage.EdmType.BuiltInTypeKind)
                { 
                    case BuiltInTypeKind.PrimitiveType:
                        propertyType = knownTypes[Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType];
                        if (edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType &&
                            ((EntityType)edmType).KeyMembers.Contains(member)) 
                        {
                            kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive; 
                        } 
                        else
                        { 
                            kind = ResourcePropertyKind.Primitive;
                        }

                        break; 
                    case BuiltInTypeKind.ComplexType:
                        kind = ResourcePropertyKind.ComplexType; 
                        propertyType = knownTypes[propertyInfo.PropertyType]; 
                        break;
                    case BuiltInTypeKind.EntityType: 
                        kind = ResourcePropertyKind.ResourceReference;
                        propertyType = knownTypes[propertyInfo.PropertyType];
                        resourceContainer = FindSampleTargetContainer(propertyType.Type, entitySets.Values);
                        break; 
                    case BuiltInTypeKind.CollectionType:
                        kind = ResourcePropertyKind.ResourceSetReference; 
                        Type propertyClrType = GetClrTypeForCSpaceType(workspace, (EntityType)((CollectionType)member.TypeUsage.EdmType).TypeUsage.EdmType); 
                        propertyType = knownTypes[propertyClrType];
                        resourceContainer = FindSampleTargetContainer(propertyType.Type, entitySets.Values); 
                        break;
                    default:
                        Debug.Assert(false, "Invalid member type encountered on " + member.Name + " - " + member.TypeUsage.EdmType.BuiltInTypeKind);
                        break; 
                }
 
                Debug.Assert(propertyType != null, "propertyType != null"); 
                string mimeType = GetMimeTypeForMappedMember(member);
                ResourceProperty resourceProperty = new ResourceProperty(propertyInfo, kind, mimeType, propertyType, resourceContainer); 
                resourceType.AddProperty(resourceProperty);
            }

            resourceType.SortKeyMembers(); 
        }
 
        /// Gets the NavigationProperty for the member of a set type if available. 
        /// Set for which to return navigation property.
        /// Relationship end member for the navigation property. 
        /// The NavigationProperty for the member of a set type if available; null otherwise.
        private static NavigationProperty PropertyForEnd(EntitySet set, RelationshipEndMember member)
        {
            Debug.Assert(set != null, "set != null"); 
            Debug.Assert(member != null, "member != null");
            foreach (NavigationProperty p in set.ElementType.NavigationProperties) 
            { 
                if (p.FromEndMember == member)
                { 
                    return p;
                }
            }
 
            return null;
        } 
 
        /// Creates a string array with property names.
        /// Properties to include in name. 
        /// A string array with property names.
        private static string[] PropertyNamesToStrings(ReadOnlyMetadataCollection properties)
        {
            Debug.Assert(properties != null, "properties != null"); 
            string[] result = new string[properties.Count];
            for (int i = 0; i < properties.Count; i++) 
            { 
                result[i] = properties[i].Name;
            } 

            return result;
        }
 
        /// 
        /// Write the child element of the referential constraint 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// name of the xmlnode : Principal or Dependent 
        /// role name
        /// list of properties
        private static void WriteReferentialConstraintChildElement(
            XmlWriter xmlWriter, 
            string nodeName,
            string roleName, 
            ReadOnlyMetadataCollection properties) 
        {
            // Write the principal role 
            xmlWriter.WriteStartElement(nodeName);
            xmlWriter.WriteAttributeString(XmlConstants.Role, roleName);

            foreach (EdmProperty property in properties) 
            {
                xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, property.Name); 
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata for the given members in the given xml writer 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// type whose members metadata needs to be written 
        /// Metadata for type as a web data service resource.
        private static void WriteMembers(XmlWriter xmlWriter, StructuralType declaringType, ResourceType resourceType)
        {
            foreach (EdmMember member in declaringType.Members) 
            {
                // Ignore members which are not defined on this type 
                if (member.DeclaringType != declaringType) 
                {
                    continue; 
                }

                // Ignore properties with no metadata.
                if (resourceType.TryResolvePropertyName(member.Name) == null) 
                {
                    continue; 
                } 

                if (member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty) 
                {
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, member.Name);
                    xmlWriter.WriteAttributeString(XmlConstants.Type, member.TypeUsage.EdmType.FullName); 
                    WriteFacets(xmlWriter, member.TypeUsage);
                } 
                else 
                {
                    Debug.Assert( 
                        BuiltInTypeKind.NavigationProperty == member.BuiltInTypeKind,
                        "Invalid Member type encountered");
                    NavigationProperty navProperty = (NavigationProperty)member;
                    xmlWriter.WriteStartElement(XmlConstants.NavigationProperty); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, navProperty.Name);
                    xmlWriter.WriteAttributeString(XmlConstants.Relationship, navProperty.RelationshipType.FullName); 
                    xmlWriter.WriteAttributeString(XmlConstants.FromRole, navProperty.FromEndMember.Name); 
                    xmlWriter.WriteAttributeString(XmlConstants.ToRole, navProperty.ToEndMember.Name);
                } 

                WriteUserDefinedAnnotations(xmlWriter, member.MetadataProperties);
                xmlWriter.WriteEndElement();
            } 
        }
 
        ///  
        /// Write the metadata for the given facets in the given xml writer
        ///  
        /// xmlWriter to which metadata needs to be written
        /// typeusage whose metadata needs to be written
        private static void WriteFacets(XmlWriter xmlWriter, TypeUsage typeUsage)
        { 
            foreach (Facet facet in typeUsage.Facets)
            { 
                if (facet.Value != null) 
                {
                    WriteFacetValue(xmlWriter, facet.Name, facet.Value); 
                }
            }
        }
 
        /// 
        /// Write the metadata for the given facet 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// name of the facet 
        /// value of the facet
        private static void WriteFacetValue(XmlWriter xmlWriter, string facetName, object facetValue)
        {
            Type facetValueType = facetValue.GetType(); 

            // We need to special case the boolean facets, since ToString returns True and False as values 
            // and for xml, they need to be lower case 
            if (facetValueType == typeof(bool))
            { 
                if ((bool)facetValue)
                {
                    xmlWriter.WriteAttributeString(facetName, XmlConstants.XmlTrueLiteral);
                } 
                else
                { 
                    xmlWriter.WriteAttributeString(facetName, XmlConstants.XmlFalseLiteral); 
                }
            } 
            else if (facetValueType == typeof(int))
            {
                xmlWriter.WriteAttributeString(facetName, XmlConvert.ToString((int)facetValue));
            } 
            else if (facetValueType.IsEnum)
            { 
                xmlWriter.WriteAttributeString(facetName, facetValue.ToString()); 
            }
            else if (facetValueType == typeof(byte)) 
            {
                xmlWriter.WriteAttributeString(facetName, XmlConvert.ToString((byte)facetValue));
            }
            else 
            {
                xmlWriter.WriteAttributeString(facetName, facetValue.ToString()); 
            } 
        }
 
        /// 
        /// Write the user annotations to the csdl
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// list of metadata properties from which extended ones needs to be written
        private static void WriteUserDefinedAnnotations(XmlWriter xmlWriter, ReadOnlyMetadataCollection metadataProperties) 
        { 
            Debug.Assert(xmlWriter != null, "xmlWriter != null");
            Debug.Assert(metadataProperties != null, "metadataProperties != null"); 
            Debug.Assert(xmlWriter.WriteState == WriteState.Element, "xmlWriter.WriteState == WriteState.Element - annotations are written on elements");

            foreach (MetadataProperty metadataProperty in metadataProperties)
            { 
                if (metadataProperty.PropertyKind == PropertyKind.Extended)
                { 
                    int index = metadataProperty.Name.LastIndexOf(":", StringComparison.Ordinal); 
                    Debug.Assert(index != -1, "empty space is a reserved namespace for edm. So this should never be the case");
                    string xmlNamespace = metadataProperty.Name.Substring(0, index); 
                    string attributeName = metadataProperty.Name.Substring(index + 1);
                    xmlWriter.WriteAttributeString(attributeName, xmlNamespace, (string)metadataProperty.Value);
                }
            } 
        }
 
        ///  
        /// Returns the entity set name for the given entity set. If this entity set belongs to the default container name,
        /// then it returns the entity set name, otherwise qualifies it with the entitycontainer name 
        /// 
        /// entity set name
        /// entity container name
        /// true if the given entity set belongs to the default entity container 
        /// returns the entity set name
        private static string GetEntitySetName(string entitySetName, string entityContainerName, bool containedInDefaultEntityContainer) 
        { 
            if (containedInDefaultEntityContainer)
            { 
                return entitySetName;
            }
            else
            { 
                return entityContainerName + "." + entitySetName;
            } 
        } 

        ///  
        /// Returns the escaped entity set name for the given entity set. If this entity set belongs to the default container name,
        /// then it returns the escaped entity set name, otherwise it escapes both the container and set name
        /// 
        /// qualified entity set name whose name needs to be escaped 
        /// returns the escaped entityset name
        private static string GetEscapedEntitySetName(string qualifiedEntitySetName) 
        { 
            int indexOfLastPeriod = qualifiedEntitySetName.LastIndexOf('.');
 
            if (-1 == indexOfLastPeriod)
            {
                return "[" + qualifiedEntitySetName + "]";
            } 
            else
            { 
                return "[" + qualifiedEntitySetName.Substring(0, indexOfLastPeriod) + "].[" + qualifiedEntitySetName.Substring(indexOfLastPeriod + 1) + "]"; 
            }
        } 

        /// 
        /// Returns the edm schema multiplicity value for the given multiplicity enum
        ///  
        /// enum multiplicity value
        /// returns edm schema multiplicity value 
        private static string GetMultiplicity(RelationshipMultiplicity multiplicity) 
        {
            string multiplicityValue; 
            if (RelationshipMultiplicity.Many == multiplicity)
            {
                multiplicityValue = XmlConstants.Many;
            } 
            else if (RelationshipMultiplicity.One == multiplicity)
            { 
                multiplicityValue = XmlConstants.One; 
            }
            else 
            {
                Debug.Assert(
                    RelationshipMultiplicity.ZeroOrOne == multiplicity,
                    "Invalid value for multiplicity encountered"); 
                multiplicityValue = XmlConstants.ZeroOrOne;
            } 
 
            return multiplicityValue;
        } 

        /// Initializes metadata for the given object context.
        /// Instance of data source to use if pure static analysis isn't possible.
        /// assembly whose metadata needs to be loaded. 
        private static void InitializeObjectItemCollection(ObjectContext objectContext, Assembly assembly)
        { 
            objectContext.MetadataWorkspace.LoadFromAssembly(assembly); 
        }
 
        /// 
        /// Get the entity set metadata object given the qualified entity set name
        /// 
        /// qualified entity set name i.e. if the entity set 
        /// belongs to entity container other than the default one, then the entity container name should
        /// be part of the qualified name 
        /// the entity set metadata object 
        private EntitySet GetEntitySet(string qualifiedEntitySetName)
        { 
            Debug.Assert(
                !String.IsNullOrEmpty(qualifiedEntitySetName),
                "!String.IsNullOrEmpty(qualifiedEntitySetName) -- otherwise qualifiedEntitySetName didn't come from internal metadata");
 
            string entityContainerName;
            string entitySetName; 
 
            // entity set name is fully qualified
            int index = qualifiedEntitySetName.LastIndexOf('.'); 
            if (index != -1)
            {
                entityContainerName = qualifiedEntitySetName.Substring(0, index - 1);
                entitySetName = qualifiedEntitySetName.Substring(index + 1); 
            }
            else 
            { 
                entityContainerName = this.ObjectContext.DefaultContainerName;
                entitySetName = qualifiedEntitySetName; 
            }

            EntityContainer entityContainer = this.ObjectContext.MetadataWorkspace.GetEntityContainer(entityContainerName, DataSpace.CSpace);
            Debug.Assert( 
                entityContainer != null,
                "entityContainer != null -- otherwise entityContainerName '" + entityContainerName + "' didn't come from metadata"); 
 
            EntitySet entitySet = entityContainer.GetEntitySetByName(entitySetName, false /*ignoreCase*/);
            Debug.Assert( 
                entitySet != null,
                "entitySet != null -- otherwise entitySetName '" + entitySetName + "' didn't come from metadata");

            return entitySet; 
        }
 
        ///  
        /// Finds a  with the same CLR type as the
        /// specified . 
        /// 
        /// EDM type to look up.
        /// 
        /// A  with the same CLR type as the 
        /// specified ; possibly null.
        ///  
        private ResourceType FindResourceType(StructuralType edmType) 
        {
            // Skip entity types with no metadata. 
            Type type = GetClrTypeForCSpaceType(this.ObjectContext.MetadataWorkspace, edmType);
            foreach (ResourceType resourceType in this.Types)
            {
                if (resourceType.Type == type) 
                {
                    return resourceType; 
                } 
            }
 
            return null;
        }

        ///  
        /// Get the default entity container
        ///  
        /// returns the default entity container 
        private EntityContainer GetDefaultEntityContainer()
        { 
            EntityContainer entityContainer;

            if (String.IsNullOrEmpty(this.ObjectContext.DefaultContainerName))
            { 
                throw new InvalidOperationException(Strings.ObjectContext_DefaultEntityContainerNameMissing);
            } 
 
            if (!this.ObjectContext.MetadataWorkspace.TryGetEntityContainer(
                    this.ObjectContext.DefaultContainerName, DataSpace.CSpace, out entityContainer)) 
            {
                throw new InvalidOperationException(
                    Strings.ObjectContext_InvalidDefaultEntityContainerName(this.ObjectContext.DefaultContainerName));
            } 

            return entityContainer; 
        } 

        /// Creates the object query for the given resource container and returns it. 
        /// Resource container for which a query instance needs to be created.
        /// Returns the ObjectQuery instance for the given resource container.
        private ObjectQuery InternalGetResourceContainerInstance(ResourceContainer container)
        { 
            Debug.Assert(container != null, "container != null");
            if (container.ReadFromContextDelegate == null) 
            { 
                Type[] parameterTypes = new Type[] { typeof(object) };
                string escapedEntitySetName = GetEscapedEntitySetName(container.Name); 
                MethodInfo genericMethod = typeof(ObjectContext).GetMethod("CreateQuery", WebUtil.PublicInstanceBindingFlags).MakeGenericMethod(container.ElementType);

                // ((ObjectContext)arg0).CreateQuery("escapedEntitySetName", new ObjectParameter[0]);
                System.Reflection.Emit.DynamicMethod readerMethod = new System.Reflection.Emit.DynamicMethod("queryable_reader", typeof(IQueryable), parameterTypes, false); 
                var generator = readerMethod.GetILGenerator();
                generator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); 
                generator.Emit(System.Reflection.Emit.OpCodes.Castclass, typeof(ObjectContext)); 
                generator.Emit(System.Reflection.Emit.OpCodes.Ldstr, escapedEntitySetName);
                generator.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); 
                generator.Emit(System.Reflection.Emit.OpCodes.Newarr, typeof(ObjectParameter));
                generator.Emit(System.Reflection.Emit.OpCodes.Call, genericMethod);
                generator.Emit(System.Reflection.Emit.OpCodes.Ret);
                container.ReadFromContextDelegate = (Func)readerMethod.CreateDelegate(typeof(Func)); 
            }
 
            return (ObjectQuery)container.ReadFromContextDelegate(this.ObjectContext); 
        }
 
        /// 
        /// Write the metadata for the given association set element in the given xml writer
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// association set whose metadata needs to be written
        /// Name of container for the entity set. 
        private void WriteAssociationSet(XmlWriter xmlWriter, AssociationSet associationSet, string containerName) 
        {
            // Skip association sets where any end is hidden. 
            foreach (AssociationSetEnd end in associationSet.AssociationSetEnds)
            {
                string lookupName = end.EntitySet.Name;
                if (!String.IsNullOrEmpty(containerName)) 
                {
                    lookupName = containerName + "." + lookupName; 
                } 

                if (((IDataServiceProvider)this).TryResolveContainerName(lookupName) == null) 
                {
                    return;
                }
            } 

            xmlWriter.WriteStartElement(XmlConstants.AssociationSet); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, associationSet.Name); 
            xmlWriter.WriteAttributeString(
                XmlConstants.Association, associationSet.ElementType.FullName); 

            // Write the user defined annotations
            WriteUserDefinedAnnotations(xmlWriter, associationSet.MetadataProperties);
            for (int i = 0; i < associationSet.AssociationSetEnds.Count; i++) 
            {
                xmlWriter.WriteStartElement(XmlConstants.End); 
                xmlWriter.WriteAttributeString(XmlConstants.Role, associationSet.AssociationSetEnds[i].Name); 
                xmlWriter.WriteAttributeString(XmlConstants.EntitySet, associationSet.AssociationSetEnds[i].EntitySet.Name);
 
                // Write the user defined annotations
                WriteUserDefinedAnnotations(xmlWriter, associationSet.AssociationSetEnds[i].MetadataProperties);
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement(); 
        } 

        ///  
        /// Write the entity set element in the given xml writer
        /// 
        /// xmlWriter to which metadata needs to be written
        /// entity set whose metadata needs to be written 
        /// Name of the container for the entity set.
        private void WriteEntitySet(XmlWriter xmlWriter, EntitySet entitySet, string containerName) 
        { 
            // Skip entity sets with no backing metadata.
            string lookupName = entitySet.Name; 
            if (!String.IsNullOrEmpty(containerName))
            {
                lookupName = containerName + "." + lookupName;
            } 

            if (((IDataServiceProvider)this).TryResolveContainerName(lookupName) == null) 
            { 
                return;
            } 

            xmlWriter.WriteStartElement(XmlConstants.EntitySet);
            xmlWriter.WriteAttributeString(XmlConstants.Name, entitySet.Name);
            xmlWriter.WriteAttributeString(XmlConstants.EntityType, entitySet.ElementType.FullName); 

            // Write the user defined annotations 
            WriteUserDefinedAnnotations(xmlWriter, entitySet.MetadataProperties); 
            xmlWriter.WriteEndElement();
        } 

        /// 
        /// Writes the metadata for all the edmTypes
        ///  
        /// xmlWriter to which metadata needs to be written
        /// edmtypes whose metadata needs to be written 
        private void WriteEdmTypes(XmlWriter xmlWriter, List edmTypes) 
        {
            // Top Level EdmTypes are EntityType, ComplexType and AssociationType. 
            foreach (EdmType edmType in edmTypes)
            {
                switch (edmType.BuiltInTypeKind)
                { 
                    case BuiltInTypeKind.EntityType:
                        this.WriteEntityType(xmlWriter, (EntityType)edmType); 
                        break; 
                    case BuiltInTypeKind.ComplexType:
                        this.WriteComplexType(xmlWriter, (ComplexType)edmType); 
                        break;
                    case BuiltInTypeKind.AssociationType:
                        this.WriteAssociationType(xmlWriter, (AssociationType)edmType);
                        break; 
                    default:
                        Debug.Assert(false, "Unexpected EdmType encountered"); 
                        break; 
                }
            } 
        }

        /// 
        /// Write the metadata for the given EntityType element in the given xml writer 
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// entity type whose metadata needs to be written 
        private void WriteEntityType(XmlWriter xmlWriter, EntityType entityType)
        { 
            // Skip entity types with no metadata.
            ResourceType resourceType = this.FindResourceType(entityType);
            if (resourceType == null)
            { 
                return;
            } 
 
            xmlWriter.WriteStartElement(XmlConstants.EntityType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, entityType.Name); 
            if (entityType.Abstract)
            {
                xmlWriter.WriteAttributeString(XmlConstants.Abstract, XmlConstants.XmlTrueLiteral);
            } 

            if (entityType.BaseType != null) 
            { 
                xmlWriter.WriteAttributeString(XmlConstants.BaseType, entityType.BaseType.FullName);
 
                // Write the user defined annotations
                WriteUserDefinedAnnotations(xmlWriter, entityType.MetadataProperties);
            }
            else 
            {
                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, entityType.MetadataProperties); 

                // If there is no base type, then the key must be defined on this entity type. 
                xmlWriter.WriteStartElement(XmlConstants.Key);
                foreach (EdmMember member in entityType.KeyMembers)
                {
                    xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, member.Name);
                    xmlWriter.WriteEndElement(); 
                } 

                xmlWriter.WriteEndElement(); 
            }

            WriteMembers(xmlWriter, entityType, resourceType);
            xmlWriter.WriteEndElement(); 
        }
 
        ///  
        /// Write the metadata for the given complex type element in the given xml writer
        ///  
        /// xmlWriter to which metadata needs to be written
        /// complex type whose metadata needs to be written
        private void WriteComplexType(XmlWriter xmlWriter, ComplexType complexType)
        { 
            // Skip complex types with no metadata.
            ResourceType resourceType = this.FindResourceType(complexType); 
            if (resourceType == null) 
            {
                return; 
            }

            xmlWriter.WriteStartElement(XmlConstants.ComplexType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, complexType.Name); 

            // Write the user defined annotations 
            WriteUserDefinedAnnotations(xmlWriter, complexType.MetadataProperties); 

            // Write the metadata for complex type properties 
            WriteMembers(xmlWriter, complexType, resourceType);
            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata for the given association type element in the given xml writer 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// association type whose metadata needs to be written 
        private void WriteAssociationType(XmlWriter xmlWriter, AssociationType associationType)
        {
            // Skip association types were any ends are not visible.
            foreach (AssociationEndMember member in associationType.AssociationEndMembers) 
            {
                RefType reference = (RefType)member.TypeUsage.EdmType; 
                ResourceType referenceResourceType = this.FindResourceType(reference.ElementType); 
                if (referenceResourceType == null)
                { 
                    return;
                }
            }
 
            xmlWriter.WriteStartElement(XmlConstants.Association);
            xmlWriter.WriteAttributeString(XmlConstants.Name, associationType.Name); 
 
            // Write the user defined annotations
            WriteUserDefinedAnnotations(xmlWriter, associationType.MetadataProperties); 

            foreach (AssociationEndMember end in associationType.RelationshipEndMembers)
            {
                xmlWriter.WriteStartElement(XmlConstants.End); 
                xmlWriter.WriteAttributeString(XmlConstants.Role, end.Name);
 
                // The ends are of reference type 
                xmlWriter.WriteAttributeString(XmlConstants.Type, ((RefType)end.TypeUsage.EdmType).ElementType.FullName);
 
                // Write the multiplicity value
                xmlWriter.WriteAttributeString(XmlConstants.Multiplicity, GetMultiplicity(end.RelationshipMultiplicity));

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, end.MetadataProperties);
 
                // write the action value 
                if (OperationAction.None != end.DeleteBehavior)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.OnDelete);
                    xmlWriter.WriteAttributeString(XmlConstants.Action, end.DeleteBehavior.ToString());
                    xmlWriter.WriteEndElement();
                } 

                xmlWriter.WriteEndElement(); 
            } 

            foreach (ReferentialConstraint referentialConstraint in associationType.ReferentialConstraints) 
            {
                xmlWriter.WriteStartElement(XmlConstants.ReferentialConstraint);

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, referentialConstraint.MetadataProperties);
                WriteReferentialConstraintChildElement(xmlWriter, XmlConstants.Principal, referentialConstraint.FromRole.Name, referentialConstraint.FromProperties); 
                WriteReferentialConstraintChildElement(xmlWriter, XmlConstants.Dependent, referentialConstraint.ToRole.Name, referentialConstraint.ToProperties); 
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Writes all the entity container definition in the given xml writer. 
        /// Also emits a special annotation for the default entity container so that 
        /// client can figure out which one is the default entity container name
        ///  
        /// xmlWriter to which metadata needs to be written
        /// list of entity containers
        /// default entity container
        private void WriteEntityContainers( 
            XmlWriter xmlWriter,
            List entityContainers, 
            EntityContainer defaultEntityContainer) 
        {
            for (int i = 0; i < entityContainers.Count; i++) 
            {
                EntityContainer current = entityContainers[i];
                xmlWriter.WriteStartElement(XmlConstants.EntityContainer);
                xmlWriter.WriteAttributeString(XmlConstants.Name, current.Name); 

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, current.MetadataProperties); 
                if (current == defaultEntityContainer)
                { 
                    BaseServiceProvider.WriteDataWebMetadata(
                        xmlWriter, XmlConstants.IsDefaultEntityContainerAttribute, XmlConstants.XmlTrueLiteral);
                    this.WriteServiceOperations(xmlWriter, this.ServiceOperations);
                } 

                string containerName = (current == defaultEntityContainer) ? "" : current.Name; 
                foreach (EntitySetBase entitySetBase in current.BaseEntitySets) 
                {
                    if (BuiltInTypeKind.EntitySet == entitySetBase.BuiltInTypeKind) 
                    {
                        this.WriteEntitySet(xmlWriter, (EntitySet)entitySetBase, containerName);
                    }
                    else if (BuiltInTypeKind.AssociationSet == entitySetBase.BuiltInTypeKind) 
                    {
                        this.WriteAssociationSet(xmlWriter, (AssociationSet)entitySetBase, containerName); 
                    } 
                }
 
                xmlWriter.WriteEndElement();
            }
        }
 
        /// 
        /// Stores the types as per the namespaces they belong to 
        ///  
        private class TypeManager
        { 
            /// 
            /// To keep track of the all the namespace encountered
            /// 
            private Dictionary> namespaces = new Dictionary>(StringComparer.Ordinal); 

            ///  
            /// List of entity containers in the metadataworkspace 
            /// 
            private List entityContainers = new List(); 

            /// 
            /// Populates the type manager with the types in the workspace
            ///  
            /// workspace containing the metadata
            internal TypeManager(MetadataWorkspace workspace) 
            { 
                //
                foreach (GlobalItem globalItem in workspace.GetItems(DataSpace.CSpace)) 
                {
                    // ignore all the primitive types and functions
                    if (BuiltInTypeKind.PrimitiveType == globalItem.BuiltInTypeKind ||
                        BuiltInTypeKind.EdmFunction == globalItem.BuiltInTypeKind) 
                    {
                        continue; 
                    } 

                    if (globalItem.BuiltInTypeKind == BuiltInTypeKind.EntityContainer) 
                    {
                        this.entityContainers.Add((EntityContainer)globalItem);
                    }
                    else 
                    {
                        List edmTypesInSameNamespace; 
                        EdmType edmType = (EdmType)globalItem; 

                        // Check if the namespace is already present 
                        if (!this.namespaces.TryGetValue(edmType.NamespaceName, out edmTypesInSameNamespace))
                        {
                            edmTypesInSameNamespace = new List();
                            this.namespaces.Add(edmType.NamespaceName, edmTypesInSameNamespace); 
                        }
 
                        edmTypesInSameNamespace.Add(edmType); 
                    }
                } 
            }

            /// 
            /// Returns IEnumerable containing the namespace and list of types in that namespace 
            /// 
            /// Returns IEnumerable containing the namespace and list of types in that namespace 
            internal IEnumerable>> NamespaceAlongWithTypes 
            {
                get 
                {
                    return this.namespaces;
                }
            } 

            ///  
            /// Returns the list of entity containers in the workspace 
            /// 
            /// returns the list of entity containers 
            internal List GetEntityContainers()
            {
                return this.entityContainers;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the interface definition for web data service
//      data sources. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data;
    using System.Data.EntityClient;
    using System.Data.Metadata.Edm;
    using System.Data.Objects; 
    using System.Data.Services.Caching;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.Linq;
    using System.Reflection; 
    using System.Text;
    using System.Xml;

    #endregion Namespaces. 

    ///  
    /// Provides a reflection-based IDataServiceProvider implementation. 
    /// 
    [DebuggerDisplay("ObjectContextServiceProvider: {Type}")] 
    internal class ObjectContextServiceProvider : BaseServiceProvider
    {
        #region Private fields.
 
        /// 
        /// List of objects that we need to be replaced. The key value 
        /// indicates the new instance of the type with whatever values 
        /// are specified in the payload. The value is the actual object
        /// which is attached to the object context 
        /// 
        private Dictionary objectsToBeReplaced = new Dictionary();

        ///  
        /// List of cspace types for which ospace metadata couldn't be found.
        ///  
        private List typesWithoutOSpaceMetadata; 

        #endregion Private fields. 

        /// 
        /// Initializes a new System.Data.Services.ReflectionServiceProvider instance.
        ///  
        /// Metadata for this provider.
        /// instance of the data source provider. 
        internal ObjectContextServiceProvider(MetadataCacheItem metadata, object dataSourceInstance) 
            : base(metadata, dataSourceInstance)
        { 
            this.typesWithoutOSpaceMetadata = new List();
        }

        /// Gets a value indicating whether null propagation is required in expression trees. 
        public override bool NullPropagationRequired
        { 
            get { return false; } 
        }
 
        /// 
        /// Provides a name for the context in which all resource containers are.
        /// 
        public override string ResourceContextName 
        {
            get 
            { 
                return this.ObjectContext.DefaultContainerName;
            } 
        }

        /// Strongly-types instance being reflected upon.
        private ObjectContext ObjectContext 
        {
            get 
            { 
                return (ObjectContext)this.CurrentDataSource;
            } 
        }

        /// 
        /// Gets the container to the given navigation property 
        /// The declaring type container name refers to the entity set that the declaring type belongs to
        ///  
        /// name of the entity container that the declaring type belongs to 
        /// declaring type
        /// resource navigation property 
        /// name of the container that this property refers to
        public override ResourceContainer GetContainer(string declaringTypeContainerName, Type declaringResourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(!String.IsNullOrEmpty(declaringTypeContainerName), "!String.IsNullOrEmpty(declaringTypeContainerName)"); 
            Debug.Assert(declaringResourceType != null && resourceProperty != null, "declaringResourceType != null && resourceProperty != null");
 
            EntitySet entitySet = this.GetEntitySet(declaringTypeContainerName); 
            Debug.Assert(entitySet != null, "entitySet != null -- GetEntitySet should never return null");
 
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(declaringResourceType);
            EntityType entityType = this.ObjectContext.MetadataWorkspace.GetItem(resourceType.FullName, DataSpace.CSpace);
            Debug.Assert(entityType != null, "entityType != null");
 
            NavigationProperty navigationProperty;
            entityType.NavigationProperties.TryGetValue(resourceProperty.Name, false /*ignoreCase*/, out navigationProperty); 
            Debug.Assert(navigationProperty != null, "navigationProperty != null"); 

            ResourceContainer result = null; 
            foreach (EntitySetBase set in entitySet.EntityContainer.BaseEntitySets)
            {
                if (set.BuiltInTypeKind != BuiltInTypeKind.AssociationSet)
                { 
                    continue;
                } 
 
                AssociationSet associationSet = (AssociationSet)set;
                if (associationSet.ElementType == navigationProperty.RelationshipType) 
                {
                    AssociationSetEnd setEnd = associationSet.AssociationSetEnds[navigationProperty.FromEndMember.Name];
                    if (setEnd.EntitySet == entitySet)
                    { 
                        entitySet = associationSet.AssociationSetEnds[navigationProperty.ToEndMember.Name].EntitySet;
                        string entitySetName = GetEntitySetName(entitySet.Name, entitySet.EntityContainer.Name, this.ObjectContext.DefaultContainerName == entitySet.EntityContainer.Name); 
                        result = ((IDataServiceProvider)this).TryResolveContainerName(entitySetName); 
                        break;
                    } 
                }
            }

            Debug.Assert(result != null, "result != null -- we should be able to find the entity set for the given navigation property"); 
            return result;
        } 
 
        /// Gets the name of the container that holds this resource type.This method is called for open types only
        /// Resource to get container for. 
        /// 
        /// The name of the container for the specified resource; null if it cannot
        /// be determined.
        ///  
        public override ResourceContainer GetContainerForResourceType(Type resourceType)
        { 
            throw Error.NotSupported(); 
        }
 
        /// 
        /// Returns the metadata in edm format
        /// 
        /// Writer to which metadata XML should be written. 
        public override void GetMetadata(XmlWriter xmlWriter)
        { 
            Debug.Assert(xmlWriter != null, "xmlWriter != null"); 
            InitializeObjectItemCollection(this.ObjectContext, this.Type.Assembly);
 
            var typeManager = new TypeManager(this.ObjectContext.MetadataWorkspace);
            BaseServiceProvider.WriteTopLevelSchemaElements(xmlWriter);
            bool entityContainerDefinitionWritten = false;
 
            // Write all the types in their respective namespaces
            foreach (KeyValuePair> typesInNamespace in typeManager.NamespaceAlongWithTypes) 
            { 
                BaseServiceProvider.WriteSchemaElement(xmlWriter, typesInNamespace.Key, this.CompatibleWithV1Schema);
 
                // Write the entity container in the same namespace as that of the type
                if (!entityContainerDefinitionWritten && typesInNamespace.Key == this.Type.Namespace)
                {
                    this.WriteEntityContainers(xmlWriter, typeManager.GetEntityContainers(), this.GetDefaultEntityContainer()); 
                    entityContainerDefinitionWritten = true;
                } 
 
                this.WriteEdmTypes(xmlWriter, typesInNamespace.Value);
                xmlWriter.WriteEndElement(); 
            }

            // If the entity container is in a different namespace than the types, then write the entity container definition
            // in a different namespace 
            if (!entityContainerDefinitionWritten)
            { 
                BaseServiceProvider.WriteSchemaElement(xmlWriter, this.Type.Namespace, this.CompatibleWithV1Schema); 
                this.WriteEntityContainers(xmlWriter, typeManager.GetEntityContainers(), this.GetDefaultEntityContainer());
                xmlWriter.WriteEndElement(); 
            }

            // These end elements balance the elements written out in WriteTopLevelSchemaElements
            xmlWriter.WriteEndElement(); 
            xmlWriter.WriteEndElement();
            xmlWriter.Flush(); 
        } 

        ///  
        /// Get the list of etag property names given the entity set name and the instance of the resource
        /// 
        /// name of the entity set
        /// clr type of the resource whose etag properties need to be fetched 
        /// list of etag property names
        public override ICollection GetETagProperties(string containerName, Type resourceClrType) 
        { 
            Debug.Assert(!String.IsNullOrEmpty(containerName), "container name must not be empty");
            Debug.Assert(resourceClrType != null, "clrType cannot be null"); 

            EntitySetBase entitySet = this.GetEntitySet(containerName);
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType);
            EntityType entityType = this.ObjectContext.MetadataWorkspace.GetItem(resourceType.FullName, DataSpace.CSpace); 
            Debug.Assert(entityType != null, "entityType != null");
            List etagProperties = new List(); 
 
            // Workspace associated directly with the ObjectContext has metadata only about OSpace, CSpace and OCSpace.
            // Since GetRequiredOriginalValueMembers depends on mapping information (CSSpace metadata), 
            // we need to make sure we call this API on a workspace which has information about the CS Mapping.
            // Hence getting workspace from the underlying Entity connection.
            MetadataWorkspace workspace = ((EntityConnection)this.ObjectContext.Connection).GetMetadataWorkspace();
            foreach (EdmMember member in workspace.GetRequiredOriginalValueMembers(entitySet, entityType)) 
            {
                ResourceProperty property = resourceType.TryResolvePropertyName(member.Name); 
                Debug.Assert(property != null, "property != null"); 
                Debug.Assert(property.TypeKind == ResourceTypeKind.Primitive, "property.TypeKind == ResourceTypeKind.Primitive");
 
                // Ignore key properties if they are part of etag, since the uri already has the key information
                // and it makes no sense to duplicate them in etag
                if (!property.IsOfKind(ResourcePropertyKind.Key))
                { 
                    etagProperties.Add(property);
                } 
            } 

            return etagProperties; 
        }

        #region IUpdatable Members
 
        /// 
        /// Creates the resource of the given type and belonging to the given container 
        ///  
        /// container name to which the resource needs to be added
        /// full type name i.e. Namespace qualified type name of the resource 
        /// object representing a resource of given type and belonging to the given container
        public override object CreateResource(string containerName, string fullTypeName)
        {
            ResourceType resourceType = ((IDataServiceProvider)this).TryResolveTypeName(fullTypeName); 
            Debug.Assert(resourceType != null, "resourceType != null");
 
            if (resourceType.Type.IsAbstract) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.CannotCreateInstancesOfAbstractType(resourceType.FullName)); 
            }

            object resource = resourceType.ConstructorDelegate();
            if (containerName != null) 
            {
                this.ObjectContext.AddObject(containerName, resource); 
            } 

            return resource; 
        }

        /// 
        /// Gets the resource of the given type that the query points to 
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource 
        /// object representing a resource of given type and as referenced by the query
        public override object GetResource(IQueryable query, string fullTypeName) 
        {
            Debug.Assert(query != null, "query != null");

            ObjectQuery objectQuery = query as ObjectQuery; 
            Debug.Assert(objectQuery != null, "objectQuery != null - otherwise we're passed an IQueryable we didn't produce");
 
            objectQuery.MergeOption = MergeOption.AppendOnly; 
            object result = null;
            foreach (object resource in objectQuery) 
            {
                if (result != null)
                {
                    throw new InvalidOperationException(Strings.SingleResourceExpected); 
                }
 
                result = resource; 
            }
 
            if (result != null && fullTypeName != null)
            {
                ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(result.GetType());
                Debug.Assert(resourceType != null, "the result must return a known type"); 
                if (resourceType.FullName != fullTypeName)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.TargetElementTypeOfTheUriSpecifiedDoesNotMatchWithTheExpectedType(resourceType.FullName, fullTypeName)); 
                }
            } 

            return result;
        }
 
        /// 
        /// Resets the value of the given resource to its default value 
        ///  
        /// resource whose value needs to be reset
        /// same resource with its value reset 
        public override object ResetResource(object resource)
        {
            Debug.Assert(resource != null, "resource != null");
 
            Type resourceClrType = resource.GetType();
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType); 
            if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
            {
                // For entity types, do the following: 
                // create a new instance of the same type and set the key values on it
                // detach the given instance and attach the new instance
                // mark all the properties as modified on the new instance so that the default values get persisted
                object newInstance = resourceType.ConstructorDelegate(); 

                // set the key value on the new instance 
                foreach (ResourceProperty property in resourceType.KeyProperties) 
                {
                    object propertyValue = property.GetValue(resource); 
                    property.SetValue(newInstance, propertyValue);
                }

                this.objectsToBeReplaced.Add(newInstance, resource); 
                return newInstance;
            } 
            else if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType) 
            {
                // For complex types, just return a brand new instance. 
                return resourceType.ConstructorDelegate();
            }

            return resource; 
        }
 
        ///  
        /// Sets the value of the given property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// value of the property
        public override void SetValue(object targetResource, string propertyName, object propertyValue) 
        {
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType()); 
            Debug.Assert(resourceType != null, "resourceType != null"); 
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName);
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            resourceProperty.SetValue(targetResource, propertyValue);
        }

        ///  
        /// Gets the value of the given property on the target object
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// the value of the property for the given target resource 
        public override object GetValue(object targetResource, string propertyName)
        {
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType());
            Debug.Assert(resourceType != null, "resourceType != null"); 
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName);
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            object resource = resourceProperty.GetValue(targetResource); 
            return resource;
        } 

        /// 
        /// Sets the value of the given reference property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property 
        public override void SetReference(object targetResource, string propertyName, object propertyValue)
        { 
            // Set the value of the reference property
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(targetResource.GetType());
            Debug.Assert(resourceType != null, "resourceType != null");
            ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
            resourceProperty.SetValue(targetResource, propertyValue); 
        } 

        ///  
        /// Adds the given value to the collection
        /// 
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be added
        public override void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) 
        { 
            Debug.Assert(targetResource != null, "propertyValue != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            Debug.Assert(resourceToBeAdded != null, "propertyValue != null");

            var entityToBeAdded = (System.Data.Objects.DataClasses.IEntityWithRelationships)resourceToBeAdded;
            ObjectStateEntry stateEntry = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(targetResource); 
            try
            { 
                // Get the EntityCollection value 
                object collection = targetResource.GetType().InvokeMember(
                    propertyName, 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
                    null,
                    targetResource,
                    new object[0], 
                    CultureInfo.InvariantCulture);
 
                Debug.Assert(collection != null, "collection != null"); 
                var end = (System.Data.Objects.DataClasses.IRelatedEnd)collection;
                if (stateEntry.State == EntityState.Added || stateEntry.State == EntityState.Unchanged) 
                {
                    end.Add(entityToBeAdded);
                }
                else 
                {
                    end.Attach(entityToBeAdded); 
                } 
            }
            catch (TargetInvocationException e) 
            {
                ErrorHandler.HandleTargetInvocationException(e);
                throw;
            } 
        }
 
        /// Applies expansions to the specified . 
        ///  object to expand.
        /// A collection of ordered  paths. 
        /// 
        /// An  object of the same type as the given ,
        /// with the results including the specified .
        ///  
        /// 
        /// This method may modify the  to indicate which expansions 
        /// are included. 
        ///
        /// The returned  may implement the  
        /// interface to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects.
        /// 
        public override IEnumerable ApplyExpansions(IQueryable queryable, ICollection expandPaths) 
        {
            IExpandProvider provider = this.CurrentDataSource as IExpandProvider; 
            if (provider != null) 
            {
                return provider.ApplyExpansions(queryable, expandPaths); 
            }
            else
            {
                // Start by adding all the containers for the root type, in case the query originates from 
                // a service operation and we don't know what the origin is.
                HashSet containers = new HashSet(EqualityComparer.Default); 
                foreach (var set in this.EntitySets) 
                {
                    if (set.Value.ElementType.IsAssignableFrom(queryable.ElementType)) 
                    {
                        containers.Add(set.Value);
                    }
                } 

                bool useBasicExpandProvider = false; 
                foreach (ExpandSegmentCollection path in expandPaths) 
                {
                    if (!useBasicExpandProvider) 
                    {
                        if (path.Any(segment => segment.HasFilterOrMaxResults))
                        {
                            useBasicExpandProvider = true; 
                        }
                        else 
                        { 
                            // If we expand properties that come from a container we've already encountered,
                            // we should use the basic provider; otherwise the EF materializer will throw because 
                            // tracking is turned off for querying.
                            foreach (ExpandSegment segment in path)
                            {
                                Debug.Assert( 
                                    segment.Container != null,
                                    "segment.Container != null -- otherwise we have an open property in EF or forgot to bind a segment"); 
                                if (!containers.Add(segment.Container)) 
                                {
                                    useBasicExpandProvider = true; 
                                    break;
                                }
                            }
                        } 
                    }
 
                    if (path.Count > 8) 
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.ObjectContext_ExpandTooDeep); 
                    }
                }

                if (useBasicExpandProvider) 
                {
                    return new BasicExpandProvider(this, false).ApplyExpansions(queryable, expandPaths); 
                } 

                MethodInfo includeMethod = typeof(ObjectContextServiceProvider).GetMethod("Include", BindingFlags.Static | BindingFlags.NonPublic); 
                includeMethod = includeMethod.MakeGenericMethod(queryable.ElementType);
                IQueryable result = queryable;
                foreach (ExpandSegmentCollection path in expandPaths)
                { 
                    string dottedPath = JoinIdentifiers(path);
                    result = (IQueryable)includeMethod.Invoke(null, new object[] { result, dottedPath }); 
                } 

                return result; 
            }
        }

        ///  
        /// Removes the given value from the collection
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// value of the property which needs to be removed 
        public override void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            Debug.Assert(resourceToBeRemoved != null, "resourceToBeRemoved != null");
 
            try 
            {
                // Get the EntityCollection value 
                object collection = targetResource.GetType().InvokeMember(
                    propertyName,
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
                    null, 
                    targetResource,
                    new object[0], 
                    CultureInfo.InvariantCulture); 

                Debug.Assert(collection != null, "collection != null"); 

                // For many to many relationships, we need to attach the other end first, otherwise
                // the collection is null and hence removing it won't have any effect.
                collection.GetType().InvokeMember( 
                    "Attach",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
                    null, 
                    collection,
                    new object[] { resourceToBeRemoved }, 
                    CultureInfo.InvariantCulture);

                collection.GetType().InvokeMember(
                    "Remove", 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, 
                    collection, 
                    new object[] { resourceToBeRemoved },
                    CultureInfo.InvariantCulture); 
            }
            catch (TargetInvocationException exception)
            {
                ErrorHandler.HandleTargetInvocationException(exception); 
                throw;
            } 
        } 

        ///  
        /// Delete the given resource
        /// 
        /// resource that needs to be deleted
        public override void DeleteResource(object resource) 
        {
            this.ObjectContext.DeleteObject(resource); 
        } 

        ///  
        /// Saves all the pending changes made till now
        /// 
        public override void SaveChanges()
        { 
            // handle the resource which need to be replaced.
            foreach (KeyValuePair objectToBeReplaced in this.objectsToBeReplaced) 
            { 
                // Get the key from the actual object
                EntityKey entityKey = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(objectToBeReplaced.Value).EntityKey; 

                // Apply property changes as specified in the new object.
                this.ObjectContext.ApplyPropertyChanges(entityKey.EntitySetName, objectToBeReplaced.Key);
            } 

            // clear all these once we have processed all the entities that need to be replaced. 
            this.objectsToBeReplaced.Clear(); 

            // Save Changes 
            this.ObjectContext.SaveChanges();
        }

        ///  
        /// Returns the actual instance of the resource represented by the given resource object
        ///  
        /// object representing the resource whose instance needs to be fetched 
        /// The actual instance of the resource represented by the given resource object
        public override object ResolveResource(object resource) 
        {
            Debug.Assert(resource != null, "resource != null");
            return resource;
        } 

        ///  
        /// Revert all the pending changes. 
        /// 
        public override void ClearChanges() 
        {
            // Detach all the existing entries in the object context
            foreach (ObjectStateEntry entry in this.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged))
            { 
                // entry.State != Entry.Detached: Also, if they are stub entries (no entity object
                // associated with the entry yet - these get automatically populated when we query the related entity), 
                // they also get automatically detached once we detach the associated entity). 
                // Both Entity and IsRelationship property throws if the entry is detached.
                // !entry.IsRelationship: We just need to remove the key entries. 
                // While detaching the key entries, the relationship entries associated
                // with the key entries also get detached.
                // entry.Entity != null:  Since they are no ordering gaurantees, the stub key entries
                // can come first, we need to skip these. 
                if (entry.State != EntityState.Detached && !entry.IsRelationship && entry.Entity != null)
                { 
                    this.ObjectContext.Detach(entry.Entity); 
                }
            } 

            // clear the list of objects that need to be special handled during save changes for replace semantics
            this.objectsToBeReplaced.Clear();
        } 

        #endregion 
 
#if ASTORIA_CONTAINMENT
 
        /// 
        /// Returns an object that can enumerate all 
        /// instances that apply to this model.
        ///  
        /// 
        /// An object that can enumerate all  
        /// instances that apply to this model. 
        /// 
        protected override IEnumerable EnumerateAccessPathAttributes() 
        {
            // To synthesize AccessPathAttribute instances, we look for Association types with the
            // ReferentialConstraint property set. Additionally we have attributes on EntitySet
            // to determine whether top-level visibility is enabled, and on NavigationProperty to 
            // determine whether an access path is canonical or non-canonical.
            Debug.Assert(this.ObjectContext != null, "this.ObjectContext != null"); 
            MetadataWorkspace workspace = this.ObjectContext.MetadataWorkspace; 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace))
            { 
                foreach (AssociationSet association in container.BaseEntitySets.OfType())
                {
                    AssociationType type = association.ElementType;
                    foreach (ReferentialConstraint constraint in type.ReferentialConstraints) 
                    {
                        EntitySet fromSet = association.AssociationSetEnds[constraint.ToRole.Name].EntitySet; 
                        NavigationProperty fromNavigationProperty = PropertyForEnd(fromSet, constraint.ToRole); 
                        if (fromNavigationProperty == null)
                        { 
                            // If there is no navigation property, no traversal is possible - simply ignore.
                            continue;
                        }
 
                        bool canonical = GetNavigationPropertyCanonical(fromNavigationProperty);
                        EntitySet targetSet = association.AssociationSetEnds[constraint.FromRole.Name].EntitySet; 
                        bool topLevelAccess = GetEntitySetTopLevelAccess(targetSet); 
                        AccessPathAttribute attribute;
                        if (canonical) 
                        {
                            CanonicalAccessPathAttribute ca = new CanonicalAccessPathAttribute();
                            ca.TopLevelAccess = topLevelAccess;
                            attribute = ca; 
                        }
                        else 
                        { 
                            attribute = new AccessPathAttribute();
                        } 

                        attribute.AnnotatedContainer = this.EntitySets[targetSet.Name];
                        attribute.InternalChildKeyMapping = PropertyNamesToStrings(constraint.FromProperties);
                        attribute.InferredFromSchema = true; 
                        attribute.Parent = fromSet.Name;
                        attribute.InternalParentKeyMapping = PropertyNamesToStrings(constraint.ToProperties); 
                        attribute.ParentNavigationProperty = fromNavigationProperty.Name; 
                        yield return attribute;
                    } 
                }
            }
        }
 
#endif
 
        /// Checks that the applied configuration is consistent. 
        /// Instance of the data source for the provider.
        /// At this point in initialization, metadata trimming hasn't taken place. 
        protected override void CheckConfigurationConsistency(object dataSourceInstance)
        {
            base.CheckConfigurationConsistency(dataSourceInstance);
 
            // Check that rights are consistent in MEST scenarios.
            // 
            // Strictly we should only check for consistent visibility 
            // for all entity sets of a given type, however the current
            // metadata design doesn't differentiate between resource 
            // container types and resource container instances on
            // associations, and therefore all rights are checked at
            // the resource type level, which forces this check to have
            // consistent rights. 
            //
            // The only exception could be references which are not connected 
            // (technically those that are not targets, but in EDM all 
            // associations are two-way). These can have entity sets
            // with different rights, enforced at the container level. 

            // Discover connected types.
            HashSet connectedTypes = new HashSet(EqualityComparer.Default);
            foreach (ResourceType type in this.Types) 
            {
                foreach (ResourceProperty property in type.PropertiesDeclaredInThisType) 
                { 
                    if (property.TypeKind == ResourceTypeKind.EntityType)
                    { 
                        connectedTypes.Add(property.ResourceType);
                    }
                }
            } 

            // Discover containers of same type with conflicting rights. 
            Dictionary typeRights = new Dictionary(); 
            foreach (KeyValuePair containerEntry in this.EntitySets)
            { 
                Debug.Assert(containerEntry.Key != null, "containerEntry.Key != null");
                Debug.Assert(containerEntry.Value != null, "containerEntry.Value != null");

                ResourceType resourceType = containerEntry.Value.ResourceType; 

                // Disregard types that are not connected to any other types. 
                if (!connectedTypes.Contains(resourceType)) 
                {
                    continue; 
                }

                ResourceContainer previouslyFoundContainer;
                if (typeRights.TryGetValue(resourceType, out previouslyFoundContainer)) 
                {
                    if (containerEntry.Value.Rights != previouslyFoundContainer.Rights) 
                    { 
                        throw new InvalidOperationException(Strings.ObjectContext_DifferentContainerRights(
                            previouslyFoundContainer.Name, 
                            previouslyFoundContainer.Rights,
                            containerEntry.Value.Name,
                            containerEntry.Value.Rights));
                    } 
                }
                else 
                { 
                    typeRights.Add(resourceType, containerEntry.Value);
                } 
            }

            CheckNavigationPropertiesBound(dataSourceInstance);
        } 

        ///  
        /// Populates metadata from the given object context 
        /// 
        /// dictionary of already known types 
        /// list of already known entity sets
        protected override void PopulateMetadata(
            IDictionary knownTypes, IDictionary entitySets)
        { 
            Debug.Assert(knownTypes != null, "knownTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 
            Debug.Assert(this.ObjectContext != null, "this.ObjectContext != null"); 

            InitializeObjectItemCollection(this.ObjectContext, this.Type.Assembly); 
            MetadataWorkspace metadataWorkspace = this.ObjectContext.MetadataWorkspace;

            // Create Resource types for all the top level entity types and complexTypes
            foreach (StructuralType edmType in metadataWorkspace.GetItems(DataSpace.CSpace)) 
            {
                if (edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || 
                    edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType) 
                {
                    // Populates metadata for the given types and all its base types 
                    if (PopulateTypeMetadata(metadataWorkspace, edmType, knownTypes) == null)
                    {
                        this.typesWithoutOSpaceMetadata.Add(edmType);
                    } 
                }
            } 
 
            foreach (EntityContainer entityContainer in metadataWorkspace.GetItems(DataSpace.CSpace))
            { 
                bool defaultEntityContainer = entityContainer.Name == this.ObjectContext.DefaultContainerName;

                // Get the list of entity sets (Ignore the relationship sets, since we won't allow that to be queried directly
                foreach (EntitySetBase entitySetBase in entityContainer.BaseEntitySets) 
                {
                    // Ignore all the association sets for the type being, since we are caching only entity sets 
                    if (entitySetBase.BuiltInTypeKind != BuiltInTypeKind.EntitySet) 
                    {
                        continue; 
                    }

                    EntitySet entitySet = (EntitySet)entitySetBase;
                    Type elementType = GetClrTypeForCSpaceType(metadataWorkspace, entitySet.ElementType); 
                    ResourceType resourceType = knownTypes[elementType];
                    string entitySetName = GetEntitySetName(entitySet.Name, entitySet.EntityContainer.Name, defaultEntityContainer); 
                    ResourceContainer resourceContainer = new ResourceContainer(entitySetName, resourceType); 
                    entitySets.Add(entitySetName, resourceContainer);
                } 
            }

            // Now go and populate the member information for each resource type
            foreach (ResourceType resourceType in knownTypes.Values) 
            {
                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive) 
                { 
                    continue;
                } 

                PopulateMemberMetadata(resourceType, metadataWorkspace, entitySets, knownTypes);
            }
        } 

        ///  
        /// Creates the object query for the given resource container and returns it 
        /// 
        /// resource container for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource container
        protected override IQueryable GetResourceContainerInstance(ResourceContainer resourceContainer)
        {
            Debug.Assert(resourceContainer != null, "resourceContainer != null"); 
            ObjectQuery result = this.InternalGetResourceContainerInstance(resourceContainer);
            result.MergeOption = MergeOption.NoTracking; 
            return result; 
        }
 
        /// 
        /// Populate types for metadata specified by the provider
        /// 
        /// list of types specified by the provider 
        /// list of already known types
        /// list of entity sets as specified in the data source type 
        protected override void PopulateMetadataForUserSpecifiedTypes( 
            IEnumerable userSpecifiedTypes, IDictionary knownTypes, IEnumerable entitySets)
        { 
            foreach (Type type in userSpecifiedTypes)
            {
                if (this.PopulateMetadataForType(type, knownTypes, entitySets) == null)
                { 
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName));
                } 
            } 

            // If there is a type in the model, for which we couldn't load the metadata, we should throw. 
            if (this.typesWithoutOSpaceMetadata.Count != 0)
            {
                throw new InvalidOperationException(Strings.ObjectContext_UnableToLoadMetadataForType(this.typesWithoutOSpaceMetadata[0].FullName));
            } 

            this.typesWithoutOSpaceMetadata = null; 
        } 

        ///  
        /// Populate metadata for the given clr type.
        /// 
        /// type whose metadata needs to be loaded.
        /// list of already known resource types. 
        /// list of entity sets as specified in the data source.
        /// resource type containing metadata for the given clr type. 
        protected override ResourceType PopulateMetadataForType( 
            Type type,
            IDictionary knownTypes, 
            IEnumerable entitySets)
        {
            ResourceType resourceType;
            if (!knownTypes.TryGetValue(type, out resourceType)) 
            {
                InitializeObjectItemCollection(this.ObjectContext, type.Assembly); 
                ObjectItemCollection objectItemCollection = (ObjectItemCollection)this.ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.OSpace); 
                StructuralType ospaceType, cspaceType;
                if (objectItemCollection.TryGetItem(type.FullName, out ospaceType)) 
                {
                    if (this.ObjectContext.MetadataWorkspace.TryGetEdmSpaceType(ospaceType, out cspaceType))
                    {
                        ResourceType baseType = null; 
                        if (cspaceType.BaseType != null)
                        { 
                            baseType = this.PopulateMetadataForType(type.BaseType, knownTypes, entitySets); 
                        }
 
                        resourceType = CreateResourceType(cspaceType, type, baseType, knownTypes);
                        this.typesWithoutOSpaceMetadata.Remove(cspaceType);
                    }
                } 
            }
 
            return resourceType; 
        }
 
        /// 
        /// Checks that all navigation properties are bound to some association set for every entity set.
        /// 
        /// Instance of the data source for the provider. 
        private static void CheckNavigationPropertiesBound(object dataSourceInstance)
        { 
            // For every navigation property, ensure that all of the EntitySets that can 
            // take their EntityType have an AssociationSet of the appropriate Association type.
            Debug.Assert(dataSourceInstance != null, "dataSourceInstance != null"); 
            MetadataWorkspace workspace = ((ObjectContext)dataSourceInstance).MetadataWorkspace;
            foreach (EntityType type in workspace.GetItems(DataSpace.CSpace))
            {
                foreach (NavigationProperty navigationProperty in type.NavigationProperties) 
                {
                    foreach (EntitySet entitySet in GetEntitySetsForType(workspace, type)) 
                    { 
                        IEnumerable entitySetsWithAssocation = GetEntitySetsWithAssociationSets(
                            workspace, 
                            navigationProperty.RelationshipType,
                            navigationProperty.FromEndMember);
                        if (!entitySetsWithAssocation.Contains(entitySet))
                        { 
                            throw new InvalidOperationException(Strings.ObjectContext_NavigationPropertyUnbound(
                                navigationProperty.Name, 
                                type.FullName, 
                                entitySet.Name));
                        } 
                    }
                }
            }
        } 

        /// Finds a target container for the specified . 
        /// CLR type to find. 
        /// Containers to examine.
        /// The resolved ; never null. 
        private static ResourceContainer FindSampleTargetContainer(Type clrType, IEnumerable containers)
        {
            Debug.Assert(clrType != null, "clrType != null");
            Debug.Assert(containers != null, "clrType != containers"); 

            ResourceContainer result = null; 
            foreach (ResourceContainer container in containers) 
            {
                if (container.ElementType.IsAssignableFrom(clrType)) 
                {
                    result = container;
                    break;
                } 
            }
 
            Debug.Assert(result != null, "result != null - otherwise unable to find container for " + clrType); 
            return result;
        } 

        /// Gets the CLR type mapped to the specified C-Space type.
        /// Workspace in which the type is defined.
        /// C-Space type whose matching clr type needs to be looked up. 
        /// The resolved  for the given .
        private static Type GetClrTypeForCSpaceType(MetadataWorkspace workspace, StructuralType edmType) 
        { 
            Debug.Assert(workspace != null, "workspace != null");
            Debug.Assert(edmType != null, "edmType != null"); 
            Debug.Assert(
               edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
               "Must be entityType or complexType");
 
            StructuralType ospaceType;
            if (workspace.TryGetObjectSpaceType(edmType, out ospaceType)) 
            { 
                ObjectItemCollection objectItemCollection = (ObjectItemCollection)workspace.GetItemCollection(DataSpace.OSpace);
                return objectItemCollection.GetClrType(ospaceType); 
            }

            return null;
        } 

        ///  
        /// Gets all  instance that may hold an entity of type . 
        /// 
        /// Workspace with metadata. 
        /// Entity type to get entity sets for.
        /// An enumeration of  instances that can hold .
        private static IEnumerable GetEntitySetsForType(MetadataWorkspace workspace, EntityType type)
        { 
            Debug.Assert(type != null, "type != null");
            Debug.Assert(workspace != null, "workspace != null"); 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace)) 
            {
                foreach (EntitySet entitySet in container.BaseEntitySets.OfType()) 
                {
                    if (IsAssignableFrom(entitySet.ElementType, type))
                    {
                        yield return entitySet; 
                    }
                } 
            } 
        }
 
        /// 
        /// Gets all entity sets that participate as members for the specified .
        /// 
        /// Workspace with metadata. 
        /// Type of assocation to check.
        /// Member of association to check. 
        ///  
        /// All  instances that are are on the  role for
        /// some association of . 
        /// 
        private static IEnumerable GetEntitySetsWithAssociationSets(
            MetadataWorkspace workspace,
            RelationshipType associationType, 
            RelationshipEndMember member)
        { 
            Debug.Assert(workspace != null, "workspace != null"); 
            Debug.Assert(associationType != null, "associationType != null");
            Debug.Assert(member != null, "member != null"); 
            foreach (EntityContainer container in workspace.GetItems(DataSpace.CSpace))
            {
                foreach (AssociationSet associationSet in container.BaseEntitySets.OfType())
                { 
                    if (associationSet.ElementType == associationType)
                    { 
                        foreach (AssociationSetEnd end in associationSet.AssociationSetEnds) 
                        {
                            if (end.CorrespondingAssociationEndMember == member) 
                            {
                                yield return end.EntitySet;
                            }
                        } 
                    }
                } 
            } 
        }
 
        /// Reads the TopLevelAccess property from the specified .
        /// Set to read attribute from.
        /// true or false depending on the value; true if the value is missing.
        private static bool GetEntitySetTopLevelAccess(EntitySet set) 
        {
            Debug.Assert(set != null, "set != null"); 
            const string TopLevelAttributeName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebAccessTopLevelAccessAttribute; 
            bool result = true;
            MetadataProperty property; 
            if (set.MetadataProperties.TryGetValue(TopLevelAttributeName, false /* ignoreCase */, out property))
            {
                string text = (string)property.Value;
                if (String.IsNullOrEmpty(text)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_TopLevelEmpty(set.Name)); 
                } 

                if (!bool.TryParse(text, out result)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_TopLevelIncorrect(property.Name, text));
                }
            } 

            return result; 
        } 

        /// Gets the MIME type specified for the specified member. 
        /// C-Space member for which we need to find the C-Space mime type attribute.
        /// The MIME type for the specified member, null if none deifned.
        private static string GetMimeTypeForMappedMember(EdmMember csdlMember)
        { 
            const string MimePropertyName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebMimeTypeAttributeName;
            string mimeType = null; 
            MetadataProperty property; 
            if (csdlMember.MetadataProperties.TryGetValue(MimePropertyName, false /* ignoreCase */, out property))
            { 
                mimeType = (string)property.Value;
                if (mimeType != null && mimeType.Length == 0)
                {
                    throw new InvalidOperationException(Strings.ObjectContext_MimeTypeAttributeEmpty(csdlMember.Name, csdlMember.DeclaringType.FullName)); 
                }
 
                if (!IsPrimitiveType(csdlMember.TypeUsage.EdmType)) 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_MimeTypeAttributeOnNonPrimitive(csdlMember.DeclaringType.FullName, csdlMember.Name, csdlMember.TypeUsage.EdmType.FullName)); 
                }
            }

            return mimeType; 
        }
 
#if ASTORIA_CONTAINMENT 

        ///  
        /// Reads the AccessPath canonical-ness property from the specified .
        /// 
        /// Property to read attribute from.
        /// true or false depending on the value; false if the value is missing. 
        private static bool GetNavigationPropertyCanonical(NavigationProperty property)
        { 
            Debug.Assert(property != null, "property != null"); 
            const string AccessPathAttributeName = XmlConstants.DataWebMetadataNamespace + ":" + XmlConstants.DataWebAccessPathAttribute;
            bool result = false; 
            MetadataProperty metadata;
            if (property.MetadataProperties.TryGetValue(AccessPathAttributeName, false /* ignoreCase */, out metadata))
            {
                string text = (string)metadata.Value; 
                if (String.IsNullOrEmpty(text))
                { 
                    throw new InvalidOperationException(Strings.ObjectContext_AccessPathEmpty(property.Name)); 
                }
 
                if (text == XmlConstants.DataWebAccessPathCanonicalValue)
                {
                    result = true;
                } 
                else if (text == XmlConstants.DataWebAccessPathNonCanonicalValue)
                { 
                    result = false; 
                }
                else 
                {
                    throw new InvalidOperationException(Strings.ObjectContext_AccessPathIncorrect(property.Name, text));
                }
            } 

            return result; 
        } 

#endif 

        /// Generic method to invoke an Include method on an ObjectQuery source.
        /// Element type of the source.
        /// Source query. 
        /// Path to include.
        /// A new query that includes  in . 
        private static ObjectQuery Include(IQueryable query, string dottedPath) 
        {
            Debug.Assert(query != null, "query != null"); 
            Debug.Assert(dottedPath != null, "dottedPath != null");

            ObjectQuery typedQuery = (ObjectQuery)query;
            return typedQuery.Include(dottedPath); 
        }
 
        /// Checks whether  may be assigned to . 
        /// Type to check assignment to.
        /// Type to check assignment from. 
        /// 
        /// true if an instance of  can be assigned to a variable of
        /// ; false otherwise.
        ///  
        private static bool IsAssignableFrom(EntityType baseType, EntityType derivedType)
        { 
            while (derivedType != null) 
            {
                if (derivedType == baseType) 
                {
                    return true;
                }
 
                derivedType = (EntityType)derivedType.BaseType;
            } 
 
            return false;
        } 

        /// Checks whether the specified type is a known primitive type.
        /// Type to check.
        /// true if the specified type is known to be a primitive type; false otherwise. 
        private static bool IsPrimitiveType(EdmType type)
        { 
            Debug.Assert(type != null, "type != null"); 
            if (type.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType)
            { 
                return false;
            }
            else
            { 
                Debug.Assert(
                    WebUtil.IsPrimitiveType(((PrimitiveType)type).ClrEquivalentType), 
                    "WebUtil.IsPrimitiveType(((PrimitiveType)type).ClrEquivalentType) - all EDM primitive types are Astoria primitive types"); 
                return true;
            } 
        }

        /// Joins the list of segment identifiers by dots.
        /// List of segments to join. 
        /// A string with the identifiers joined by dots.
        private static string JoinIdentifiers(List segments) 
        { 
            Debug.Assert(segments != null, "segments != null");
 
            int capacity = 0;
            foreach (ExpandSegment segment in segments)
            {
                capacity += segment.Name.Length; 
            }
 
            capacity += segments.Count - 1; 

            StringBuilder builder = new StringBuilder(capacity); 
            foreach (ExpandSegment segment in segments)
            {
                if (builder.Length > 0)
                { 
                    builder.Append('.');
                } 
 
                builder.Append(segment.Name);
            } 

            return builder.ToString();
        }
 
        /// 
        /// Populates the metadata for the given type and its base type 
        ///  
        /// metadata workspace containing all the metadata information
        ///  type whose metadata needs to be populated  
        /// list of known types 
        /// returns the resource type corresponding to the given edmType
        private static ResourceType PopulateTypeMetadata(
            MetadataWorkspace workspace, 
            StructuralType edmType,
            IDictionary knownTypes) 
        { 
            Debug.Assert(
                edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType || 
                edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                "type must be entity or complex type");

            ResourceType resourceType = null; 
            Type clrType = GetClrTypeForCSpaceType(workspace, edmType);
            if (clrType != null && !knownTypes.TryGetValue(clrType, out resourceType)) 
            { 
                ResourceType baseType = null;
                if (edmType.BaseType != null) 
                {
                    baseType = PopulateTypeMetadata(workspace, (StructuralType)edmType.BaseType, knownTypes);
                }
 
                resourceType = CreateResourceType(edmType, clrType, baseType, knownTypes);
            } 
 
            return resourceType;
        } 

        /// 
        /// Creates a new instance of resource type given the cspace structural type and mapping clr type.
        ///  
        /// cspace structural type.
        /// mapping clr type for the given structural type. 
        /// the base resource type for the given resource type. 
        /// list of already known resource types.
        /// the new resource type instance created for the given cspace type. 
        private static ResourceType CreateResourceType(
            StructuralType cspaceType,
            Type clrType,
            ResourceType baseResourceType, 
            IDictionary knownTypes)
        { 
            ResourceTypeKind resourceTypeKind = cspaceType.BuiltInTypeKind == BuiltInTypeKind.EntityType ? ResourceTypeKind.EntityType : ResourceTypeKind.ComplexType; 
            ResourceType resourceType = new ResourceType(clrType, resourceTypeKind, baseResourceType, cspaceType.FullName, cspaceType.Name);
            knownTypes.Add(clrType, resourceType); 
            return resourceType;
        }

        ///  
        /// Populates the member metadata for the given type
        ///  
        /// resource type whose member metadata needs to be filled 
        /// workspace containing the metadata information
        /// Available entity sets. 
        /// list of already known types
        private static void PopulateMemberMetadata(
            ResourceType resourceType,
            MetadataWorkspace workspace, 
            IDictionary entitySets,
            IDictionary knownTypes) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
            Debug.Assert(workspace != null, "workspace != null"); 
            Debug.Assert(entitySets != null, "entitySets != null");

            // Find the type from the OSpace
            StructuralType edmType = workspace.GetItem(resourceType.FullName, DataSpace.CSpace); 
            foreach (EdmMember member in edmType.Members)
            { 
                // only look at the instance members 
                if (member.DeclaringType != edmType)
                { 
                    continue;
                }

                ResourceContainer resourceContainer = null; 
                ResourcePropertyKind kind = (ResourcePropertyKind)(-1);
                PropertyInfo propertyInfo = resourceType.Type.GetProperty(member.Name); 
                ResourceType propertyType = null; 
                switch (member.TypeUsage.EdmType.BuiltInTypeKind)
                { 
                    case BuiltInTypeKind.PrimitiveType:
                        propertyType = knownTypes[Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType];
                        if (edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType &&
                            ((EntityType)edmType).KeyMembers.Contains(member)) 
                        {
                            kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive; 
                        } 
                        else
                        { 
                            kind = ResourcePropertyKind.Primitive;
                        }

                        break; 
                    case BuiltInTypeKind.ComplexType:
                        kind = ResourcePropertyKind.ComplexType; 
                        propertyType = knownTypes[propertyInfo.PropertyType]; 
                        break;
                    case BuiltInTypeKind.EntityType: 
                        kind = ResourcePropertyKind.ResourceReference;
                        propertyType = knownTypes[propertyInfo.PropertyType];
                        resourceContainer = FindSampleTargetContainer(propertyType.Type, entitySets.Values);
                        break; 
                    case BuiltInTypeKind.CollectionType:
                        kind = ResourcePropertyKind.ResourceSetReference; 
                        Type propertyClrType = GetClrTypeForCSpaceType(workspace, (EntityType)((CollectionType)member.TypeUsage.EdmType).TypeUsage.EdmType); 
                        propertyType = knownTypes[propertyClrType];
                        resourceContainer = FindSampleTargetContainer(propertyType.Type, entitySets.Values); 
                        break;
                    default:
                        Debug.Assert(false, "Invalid member type encountered on " + member.Name + " - " + member.TypeUsage.EdmType.BuiltInTypeKind);
                        break; 
                }
 
                Debug.Assert(propertyType != null, "propertyType != null"); 
                string mimeType = GetMimeTypeForMappedMember(member);
                ResourceProperty resourceProperty = new ResourceProperty(propertyInfo, kind, mimeType, propertyType, resourceContainer); 
                resourceType.AddProperty(resourceProperty);
            }

            resourceType.SortKeyMembers(); 
        }
 
        /// Gets the NavigationProperty for the member of a set type if available. 
        /// Set for which to return navigation property.
        /// Relationship end member for the navigation property. 
        /// The NavigationProperty for the member of a set type if available; null otherwise.
        private static NavigationProperty PropertyForEnd(EntitySet set, RelationshipEndMember member)
        {
            Debug.Assert(set != null, "set != null"); 
            Debug.Assert(member != null, "member != null");
            foreach (NavigationProperty p in set.ElementType.NavigationProperties) 
            { 
                if (p.FromEndMember == member)
                { 
                    return p;
                }
            }
 
            return null;
        } 
 
        /// Creates a string array with property names.
        /// Properties to include in name. 
        /// A string array with property names.
        private static string[] PropertyNamesToStrings(ReadOnlyMetadataCollection properties)
        {
            Debug.Assert(properties != null, "properties != null"); 
            string[] result = new string[properties.Count];
            for (int i = 0; i < properties.Count; i++) 
            { 
                result[i] = properties[i].Name;
            } 

            return result;
        }
 
        /// 
        /// Write the child element of the referential constraint 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// name of the xmlnode : Principal or Dependent 
        /// role name
        /// list of properties
        private static void WriteReferentialConstraintChildElement(
            XmlWriter xmlWriter, 
            string nodeName,
            string roleName, 
            ReadOnlyMetadataCollection properties) 
        {
            // Write the principal role 
            xmlWriter.WriteStartElement(nodeName);
            xmlWriter.WriteAttributeString(XmlConstants.Role, roleName);

            foreach (EdmProperty property in properties) 
            {
                xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, property.Name); 
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata for the given members in the given xml writer 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// type whose members metadata needs to be written 
        /// Metadata for type as a web data service resource.
        private static void WriteMembers(XmlWriter xmlWriter, StructuralType declaringType, ResourceType resourceType)
        {
            foreach (EdmMember member in declaringType.Members) 
            {
                // Ignore members which are not defined on this type 
                if (member.DeclaringType != declaringType) 
                {
                    continue; 
                }

                // Ignore properties with no metadata.
                if (resourceType.TryResolvePropertyName(member.Name) == null) 
                {
                    continue; 
                } 

                if (member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty) 
                {
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, member.Name);
                    xmlWriter.WriteAttributeString(XmlConstants.Type, member.TypeUsage.EdmType.FullName); 
                    WriteFacets(xmlWriter, member.TypeUsage);
                } 
                else 
                {
                    Debug.Assert( 
                        BuiltInTypeKind.NavigationProperty == member.BuiltInTypeKind,
                        "Invalid Member type encountered");
                    NavigationProperty navProperty = (NavigationProperty)member;
                    xmlWriter.WriteStartElement(XmlConstants.NavigationProperty); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, navProperty.Name);
                    xmlWriter.WriteAttributeString(XmlConstants.Relationship, navProperty.RelationshipType.FullName); 
                    xmlWriter.WriteAttributeString(XmlConstants.FromRole, navProperty.FromEndMember.Name); 
                    xmlWriter.WriteAttributeString(XmlConstants.ToRole, navProperty.ToEndMember.Name);
                } 

                WriteUserDefinedAnnotations(xmlWriter, member.MetadataProperties);
                xmlWriter.WriteEndElement();
            } 
        }
 
        ///  
        /// Write the metadata for the given facets in the given xml writer
        ///  
        /// xmlWriter to which metadata needs to be written
        /// typeusage whose metadata needs to be written
        private static void WriteFacets(XmlWriter xmlWriter, TypeUsage typeUsage)
        { 
            foreach (Facet facet in typeUsage.Facets)
            { 
                if (facet.Value != null) 
                {
                    WriteFacetValue(xmlWriter, facet.Name, facet.Value); 
                }
            }
        }
 
        /// 
        /// Write the metadata for the given facet 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// name of the facet 
        /// value of the facet
        private static void WriteFacetValue(XmlWriter xmlWriter, string facetName, object facetValue)
        {
            Type facetValueType = facetValue.GetType(); 

            // We need to special case the boolean facets, since ToString returns True and False as values 
            // and for xml, they need to be lower case 
            if (facetValueType == typeof(bool))
            { 
                if ((bool)facetValue)
                {
                    xmlWriter.WriteAttributeString(facetName, XmlConstants.XmlTrueLiteral);
                } 
                else
                { 
                    xmlWriter.WriteAttributeString(facetName, XmlConstants.XmlFalseLiteral); 
                }
            } 
            else if (facetValueType == typeof(int))
            {
                xmlWriter.WriteAttributeString(facetName, XmlConvert.ToString((int)facetValue));
            } 
            else if (facetValueType.IsEnum)
            { 
                xmlWriter.WriteAttributeString(facetName, facetValue.ToString()); 
            }
            else if (facetValueType == typeof(byte)) 
            {
                xmlWriter.WriteAttributeString(facetName, XmlConvert.ToString((byte)facetValue));
            }
            else 
            {
                xmlWriter.WriteAttributeString(facetName, facetValue.ToString()); 
            } 
        }
 
        /// 
        /// Write the user annotations to the csdl
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// list of metadata properties from which extended ones needs to be written
        private static void WriteUserDefinedAnnotations(XmlWriter xmlWriter, ReadOnlyMetadataCollection metadataProperties) 
        { 
            Debug.Assert(xmlWriter != null, "xmlWriter != null");
            Debug.Assert(metadataProperties != null, "metadataProperties != null"); 
            Debug.Assert(xmlWriter.WriteState == WriteState.Element, "xmlWriter.WriteState == WriteState.Element - annotations are written on elements");

            foreach (MetadataProperty metadataProperty in metadataProperties)
            { 
                if (metadataProperty.PropertyKind == PropertyKind.Extended)
                { 
                    int index = metadataProperty.Name.LastIndexOf(":", StringComparison.Ordinal); 
                    Debug.Assert(index != -1, "empty space is a reserved namespace for edm. So this should never be the case");
                    string xmlNamespace = metadataProperty.Name.Substring(0, index); 
                    string attributeName = metadataProperty.Name.Substring(index + 1);
                    xmlWriter.WriteAttributeString(attributeName, xmlNamespace, (string)metadataProperty.Value);
                }
            } 
        }
 
        ///  
        /// Returns the entity set name for the given entity set. If this entity set belongs to the default container name,
        /// then it returns the entity set name, otherwise qualifies it with the entitycontainer name 
        /// 
        /// entity set name
        /// entity container name
        /// true if the given entity set belongs to the default entity container 
        /// returns the entity set name
        private static string GetEntitySetName(string entitySetName, string entityContainerName, bool containedInDefaultEntityContainer) 
        { 
            if (containedInDefaultEntityContainer)
            { 
                return entitySetName;
            }
            else
            { 
                return entityContainerName + "." + entitySetName;
            } 
        } 

        ///  
        /// Returns the escaped entity set name for the given entity set. If this entity set belongs to the default container name,
        /// then it returns the escaped entity set name, otherwise it escapes both the container and set name
        /// 
        /// qualified entity set name whose name needs to be escaped 
        /// returns the escaped entityset name
        private static string GetEscapedEntitySetName(string qualifiedEntitySetName) 
        { 
            int indexOfLastPeriod = qualifiedEntitySetName.LastIndexOf('.');
 
            if (-1 == indexOfLastPeriod)
            {
                return "[" + qualifiedEntitySetName + "]";
            } 
            else
            { 
                return "[" + qualifiedEntitySetName.Substring(0, indexOfLastPeriod) + "].[" + qualifiedEntitySetName.Substring(indexOfLastPeriod + 1) + "]"; 
            }
        } 

        /// 
        /// Returns the edm schema multiplicity value for the given multiplicity enum
        ///  
        /// enum multiplicity value
        /// returns edm schema multiplicity value 
        private static string GetMultiplicity(RelationshipMultiplicity multiplicity) 
        {
            string multiplicityValue; 
            if (RelationshipMultiplicity.Many == multiplicity)
            {
                multiplicityValue = XmlConstants.Many;
            } 
            else if (RelationshipMultiplicity.One == multiplicity)
            { 
                multiplicityValue = XmlConstants.One; 
            }
            else 
            {
                Debug.Assert(
                    RelationshipMultiplicity.ZeroOrOne == multiplicity,
                    "Invalid value for multiplicity encountered"); 
                multiplicityValue = XmlConstants.ZeroOrOne;
            } 
 
            return multiplicityValue;
        } 

        /// Initializes metadata for the given object context.
        /// Instance of data source to use if pure static analysis isn't possible.
        /// assembly whose metadata needs to be loaded. 
        private static void InitializeObjectItemCollection(ObjectContext objectContext, Assembly assembly)
        { 
            objectContext.MetadataWorkspace.LoadFromAssembly(assembly); 
        }
 
        /// 
        /// Get the entity set metadata object given the qualified entity set name
        /// 
        /// qualified entity set name i.e. if the entity set 
        /// belongs to entity container other than the default one, then the entity container name should
        /// be part of the qualified name 
        /// the entity set metadata object 
        private EntitySet GetEntitySet(string qualifiedEntitySetName)
        { 
            Debug.Assert(
                !String.IsNullOrEmpty(qualifiedEntitySetName),
                "!String.IsNullOrEmpty(qualifiedEntitySetName) -- otherwise qualifiedEntitySetName didn't come from internal metadata");
 
            string entityContainerName;
            string entitySetName; 
 
            // entity set name is fully qualified
            int index = qualifiedEntitySetName.LastIndexOf('.'); 
            if (index != -1)
            {
                entityContainerName = qualifiedEntitySetName.Substring(0, index - 1);
                entitySetName = qualifiedEntitySetName.Substring(index + 1); 
            }
            else 
            { 
                entityContainerName = this.ObjectContext.DefaultContainerName;
                entitySetName = qualifiedEntitySetName; 
            }

            EntityContainer entityContainer = this.ObjectContext.MetadataWorkspace.GetEntityContainer(entityContainerName, DataSpace.CSpace);
            Debug.Assert( 
                entityContainer != null,
                "entityContainer != null -- otherwise entityContainerName '" + entityContainerName + "' didn't come from metadata"); 
 
            EntitySet entitySet = entityContainer.GetEntitySetByName(entitySetName, false /*ignoreCase*/);
            Debug.Assert( 
                entitySet != null,
                "entitySet != null -- otherwise entitySetName '" + entitySetName + "' didn't come from metadata");

            return entitySet; 
        }
 
        ///  
        /// Finds a  with the same CLR type as the
        /// specified . 
        /// 
        /// EDM type to look up.
        /// 
        /// A  with the same CLR type as the 
        /// specified ; possibly null.
        ///  
        private ResourceType FindResourceType(StructuralType edmType) 
        {
            // Skip entity types with no metadata. 
            Type type = GetClrTypeForCSpaceType(this.ObjectContext.MetadataWorkspace, edmType);
            foreach (ResourceType resourceType in this.Types)
            {
                if (resourceType.Type == type) 
                {
                    return resourceType; 
                } 
            }
 
            return null;
        }

        ///  
        /// Get the default entity container
        ///  
        /// returns the default entity container 
        private EntityContainer GetDefaultEntityContainer()
        { 
            EntityContainer entityContainer;

            if (String.IsNullOrEmpty(this.ObjectContext.DefaultContainerName))
            { 
                throw new InvalidOperationException(Strings.ObjectContext_DefaultEntityContainerNameMissing);
            } 
 
            if (!this.ObjectContext.MetadataWorkspace.TryGetEntityContainer(
                    this.ObjectContext.DefaultContainerName, DataSpace.CSpace, out entityContainer)) 
            {
                throw new InvalidOperationException(
                    Strings.ObjectContext_InvalidDefaultEntityContainerName(this.ObjectContext.DefaultContainerName));
            } 

            return entityContainer; 
        } 

        /// Creates the object query for the given resource container and returns it. 
        /// Resource container for which a query instance needs to be created.
        /// Returns the ObjectQuery instance for the given resource container.
        private ObjectQuery InternalGetResourceContainerInstance(ResourceContainer container)
        { 
            Debug.Assert(container != null, "container != null");
            if (container.ReadFromContextDelegate == null) 
            { 
                Type[] parameterTypes = new Type[] { typeof(object) };
                string escapedEntitySetName = GetEscapedEntitySetName(container.Name); 
                MethodInfo genericMethod = typeof(ObjectContext).GetMethod("CreateQuery", WebUtil.PublicInstanceBindingFlags).MakeGenericMethod(container.ElementType);

                // ((ObjectContext)arg0).CreateQuery("escapedEntitySetName", new ObjectParameter[0]);
                System.Reflection.Emit.DynamicMethod readerMethod = new System.Reflection.Emit.DynamicMethod("queryable_reader", typeof(IQueryable), parameterTypes, false); 
                var generator = readerMethod.GetILGenerator();
                generator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); 
                generator.Emit(System.Reflection.Emit.OpCodes.Castclass, typeof(ObjectContext)); 
                generator.Emit(System.Reflection.Emit.OpCodes.Ldstr, escapedEntitySetName);
                generator.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); 
                generator.Emit(System.Reflection.Emit.OpCodes.Newarr, typeof(ObjectParameter));
                generator.Emit(System.Reflection.Emit.OpCodes.Call, genericMethod);
                generator.Emit(System.Reflection.Emit.OpCodes.Ret);
                container.ReadFromContextDelegate = (Func)readerMethod.CreateDelegate(typeof(Func)); 
            }
 
            return (ObjectQuery)container.ReadFromContextDelegate(this.ObjectContext); 
        }
 
        /// 
        /// Write the metadata for the given association set element in the given xml writer
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// association set whose metadata needs to be written
        /// Name of container for the entity set. 
        private void WriteAssociationSet(XmlWriter xmlWriter, AssociationSet associationSet, string containerName) 
        {
            // Skip association sets where any end is hidden. 
            foreach (AssociationSetEnd end in associationSet.AssociationSetEnds)
            {
                string lookupName = end.EntitySet.Name;
                if (!String.IsNullOrEmpty(containerName)) 
                {
                    lookupName = containerName + "." + lookupName; 
                } 

                if (((IDataServiceProvider)this).TryResolveContainerName(lookupName) == null) 
                {
                    return;
                }
            } 

            xmlWriter.WriteStartElement(XmlConstants.AssociationSet); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, associationSet.Name); 
            xmlWriter.WriteAttributeString(
                XmlConstants.Association, associationSet.ElementType.FullName); 

            // Write the user defined annotations
            WriteUserDefinedAnnotations(xmlWriter, associationSet.MetadataProperties);
            for (int i = 0; i < associationSet.AssociationSetEnds.Count; i++) 
            {
                xmlWriter.WriteStartElement(XmlConstants.End); 
                xmlWriter.WriteAttributeString(XmlConstants.Role, associationSet.AssociationSetEnds[i].Name); 
                xmlWriter.WriteAttributeString(XmlConstants.EntitySet, associationSet.AssociationSetEnds[i].EntitySet.Name);
 
                // Write the user defined annotations
                WriteUserDefinedAnnotations(xmlWriter, associationSet.AssociationSetEnds[i].MetadataProperties);
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement(); 
        } 

        ///  
        /// Write the entity set element in the given xml writer
        /// 
        /// xmlWriter to which metadata needs to be written
        /// entity set whose metadata needs to be written 
        /// Name of the container for the entity set.
        private void WriteEntitySet(XmlWriter xmlWriter, EntitySet entitySet, string containerName) 
        { 
            // Skip entity sets with no backing metadata.
            string lookupName = entitySet.Name; 
            if (!String.IsNullOrEmpty(containerName))
            {
                lookupName = containerName + "." + lookupName;
            } 

            if (((IDataServiceProvider)this).TryResolveContainerName(lookupName) == null) 
            { 
                return;
            } 

            xmlWriter.WriteStartElement(XmlConstants.EntitySet);
            xmlWriter.WriteAttributeString(XmlConstants.Name, entitySet.Name);
            xmlWriter.WriteAttributeString(XmlConstants.EntityType, entitySet.ElementType.FullName); 

            // Write the user defined annotations 
            WriteUserDefinedAnnotations(xmlWriter, entitySet.MetadataProperties); 
            xmlWriter.WriteEndElement();
        } 

        /// 
        /// Writes the metadata for all the edmTypes
        ///  
        /// xmlWriter to which metadata needs to be written
        /// edmtypes whose metadata needs to be written 
        private void WriteEdmTypes(XmlWriter xmlWriter, List edmTypes) 
        {
            // Top Level EdmTypes are EntityType, ComplexType and AssociationType. 
            foreach (EdmType edmType in edmTypes)
            {
                switch (edmType.BuiltInTypeKind)
                { 
                    case BuiltInTypeKind.EntityType:
                        this.WriteEntityType(xmlWriter, (EntityType)edmType); 
                        break; 
                    case BuiltInTypeKind.ComplexType:
                        this.WriteComplexType(xmlWriter, (ComplexType)edmType); 
                        break;
                    case BuiltInTypeKind.AssociationType:
                        this.WriteAssociationType(xmlWriter, (AssociationType)edmType);
                        break; 
                    default:
                        Debug.Assert(false, "Unexpected EdmType encountered"); 
                        break; 
                }
            } 
        }

        /// 
        /// Write the metadata for the given EntityType element in the given xml writer 
        /// 
        /// xmlWriter to which metadata needs to be written 
        /// entity type whose metadata needs to be written 
        private void WriteEntityType(XmlWriter xmlWriter, EntityType entityType)
        { 
            // Skip entity types with no metadata.
            ResourceType resourceType = this.FindResourceType(entityType);
            if (resourceType == null)
            { 
                return;
            } 
 
            xmlWriter.WriteStartElement(XmlConstants.EntityType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, entityType.Name); 
            if (entityType.Abstract)
            {
                xmlWriter.WriteAttributeString(XmlConstants.Abstract, XmlConstants.XmlTrueLiteral);
            } 

            if (entityType.BaseType != null) 
            { 
                xmlWriter.WriteAttributeString(XmlConstants.BaseType, entityType.BaseType.FullName);
 
                // Write the user defined annotations
                WriteUserDefinedAnnotations(xmlWriter, entityType.MetadataProperties);
            }
            else 
            {
                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, entityType.MetadataProperties); 

                // If there is no base type, then the key must be defined on this entity type. 
                xmlWriter.WriteStartElement(XmlConstants.Key);
                foreach (EdmMember member in entityType.KeyMembers)
                {
                    xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, member.Name);
                    xmlWriter.WriteEndElement(); 
                } 

                xmlWriter.WriteEndElement(); 
            }

            WriteMembers(xmlWriter, entityType, resourceType);
            xmlWriter.WriteEndElement(); 
        }
 
        ///  
        /// Write the metadata for the given complex type element in the given xml writer
        ///  
        /// xmlWriter to which metadata needs to be written
        /// complex type whose metadata needs to be written
        private void WriteComplexType(XmlWriter xmlWriter, ComplexType complexType)
        { 
            // Skip complex types with no metadata.
            ResourceType resourceType = this.FindResourceType(complexType); 
            if (resourceType == null) 
            {
                return; 
            }

            xmlWriter.WriteStartElement(XmlConstants.ComplexType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, complexType.Name); 

            // Write the user defined annotations 
            WriteUserDefinedAnnotations(xmlWriter, complexType.MetadataProperties); 

            // Write the metadata for complex type properties 
            WriteMembers(xmlWriter, complexType, resourceType);
            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata for the given association type element in the given xml writer 
        ///  
        /// xmlWriter to which metadata needs to be written
        /// association type whose metadata needs to be written 
        private void WriteAssociationType(XmlWriter xmlWriter, AssociationType associationType)
        {
            // Skip association types were any ends are not visible.
            foreach (AssociationEndMember member in associationType.AssociationEndMembers) 
            {
                RefType reference = (RefType)member.TypeUsage.EdmType; 
                ResourceType referenceResourceType = this.FindResourceType(reference.ElementType); 
                if (referenceResourceType == null)
                { 
                    return;
                }
            }
 
            xmlWriter.WriteStartElement(XmlConstants.Association);
            xmlWriter.WriteAttributeString(XmlConstants.Name, associationType.Name); 
 
            // Write the user defined annotations
            WriteUserDefinedAnnotations(xmlWriter, associationType.MetadataProperties); 

            foreach (AssociationEndMember end in associationType.RelationshipEndMembers)
            {
                xmlWriter.WriteStartElement(XmlConstants.End); 
                xmlWriter.WriteAttributeString(XmlConstants.Role, end.Name);
 
                // The ends are of reference type 
                xmlWriter.WriteAttributeString(XmlConstants.Type, ((RefType)end.TypeUsage.EdmType).ElementType.FullName);
 
                // Write the multiplicity value
                xmlWriter.WriteAttributeString(XmlConstants.Multiplicity, GetMultiplicity(end.RelationshipMultiplicity));

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, end.MetadataProperties);
 
                // write the action value 
                if (OperationAction.None != end.DeleteBehavior)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.OnDelete);
                    xmlWriter.WriteAttributeString(XmlConstants.Action, end.DeleteBehavior.ToString());
                    xmlWriter.WriteEndElement();
                } 

                xmlWriter.WriteEndElement(); 
            } 

            foreach (ReferentialConstraint referentialConstraint in associationType.ReferentialConstraints) 
            {
                xmlWriter.WriteStartElement(XmlConstants.ReferentialConstraint);

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, referentialConstraint.MetadataProperties);
                WriteReferentialConstraintChildElement(xmlWriter, XmlConstants.Principal, referentialConstraint.FromRole.Name, referentialConstraint.FromProperties); 
                WriteReferentialConstraintChildElement(xmlWriter, XmlConstants.Dependent, referentialConstraint.ToRole.Name, referentialConstraint.ToProperties); 
                xmlWriter.WriteEndElement();
            } 

            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Writes all the entity container definition in the given xml writer. 
        /// Also emits a special annotation for the default entity container so that 
        /// client can figure out which one is the default entity container name
        ///  
        /// xmlWriter to which metadata needs to be written
        /// list of entity containers
        /// default entity container
        private void WriteEntityContainers( 
            XmlWriter xmlWriter,
            List entityContainers, 
            EntityContainer defaultEntityContainer) 
        {
            for (int i = 0; i < entityContainers.Count; i++) 
            {
                EntityContainer current = entityContainers[i];
                xmlWriter.WriteStartElement(XmlConstants.EntityContainer);
                xmlWriter.WriteAttributeString(XmlConstants.Name, current.Name); 

                // Write the user defined annotations 
                WriteUserDefinedAnnotations(xmlWriter, current.MetadataProperties); 
                if (current == defaultEntityContainer)
                { 
                    BaseServiceProvider.WriteDataWebMetadata(
                        xmlWriter, XmlConstants.IsDefaultEntityContainerAttribute, XmlConstants.XmlTrueLiteral);
                    this.WriteServiceOperations(xmlWriter, this.ServiceOperations);
                } 

                string containerName = (current == defaultEntityContainer) ? "" : current.Name; 
                foreach (EntitySetBase entitySetBase in current.BaseEntitySets) 
                {
                    if (BuiltInTypeKind.EntitySet == entitySetBase.BuiltInTypeKind) 
                    {
                        this.WriteEntitySet(xmlWriter, (EntitySet)entitySetBase, containerName);
                    }
                    else if (BuiltInTypeKind.AssociationSet == entitySetBase.BuiltInTypeKind) 
                    {
                        this.WriteAssociationSet(xmlWriter, (AssociationSet)entitySetBase, containerName); 
                    } 
                }
 
                xmlWriter.WriteEndElement();
            }
        }
 
        /// 
        /// Stores the types as per the namespaces they belong to 
        ///  
        private class TypeManager
        { 
            /// 
            /// To keep track of the all the namespace encountered
            /// 
            private Dictionary> namespaces = new Dictionary>(StringComparer.Ordinal); 

            ///  
            /// List of entity containers in the metadataworkspace 
            /// 
            private List entityContainers = new List(); 

            /// 
            /// Populates the type manager with the types in the workspace
            ///  
            /// workspace containing the metadata
            internal TypeManager(MetadataWorkspace workspace) 
            { 
                //
                foreach (GlobalItem globalItem in workspace.GetItems(DataSpace.CSpace)) 
                {
                    // ignore all the primitive types and functions
                    if (BuiltInTypeKind.PrimitiveType == globalItem.BuiltInTypeKind ||
                        BuiltInTypeKind.EdmFunction == globalItem.BuiltInTypeKind) 
                    {
                        continue; 
                    } 

                    if (globalItem.BuiltInTypeKind == BuiltInTypeKind.EntityContainer) 
                    {
                        this.entityContainers.Add((EntityContainer)globalItem);
                    }
                    else 
                    {
                        List edmTypesInSameNamespace; 
                        EdmType edmType = (EdmType)globalItem; 

                        // Check if the namespace is already present 
                        if (!this.namespaces.TryGetValue(edmType.NamespaceName, out edmTypesInSameNamespace))
                        {
                            edmTypesInSameNamespace = new List();
                            this.namespaces.Add(edmType.NamespaceName, edmTypesInSameNamespace); 
                        }
 
                        edmTypesInSameNamespace.Add(edmType); 
                    }
                } 
            }

            /// 
            /// Returns IEnumerable containing the namespace and list of types in that namespace 
            /// 
            /// Returns IEnumerable containing the namespace and list of types in that namespace 
            internal IEnumerable>> NamespaceAlongWithTypes 
            {
                get 
                {
                    return this.namespaces;
                }
            } 

            ///  
            /// Returns the list of entity containers in the workspace 
            /// 
            /// returns the list of entity containers 
            internal List GetEntityContainers()
            {
                return this.entityContainers;
            } 
        }
    } 
} 

// 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