ObjectItemCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Serialization; 
using System.Xml;
using System.Xml.Schema; 
using System.Data.Common.Utils; 
using System.Diagnostics;
using System.Collections.ObjectModel; 
// Using an alias for this because a lot of names in this namespace conflicts with names in metadata
using DataClasses = System.Data.Objects.DataClasses;
using System.Globalization;
using System.Data.Entity; 
using System.Data.Common;
 
namespace System.Data.Metadata.Edm 
{
    ///  
    /// Class for representing a collection of items for the object layer.
    /// Most of the implemetation for actual maintainance of the collection is
    /// done by ItemCollection
    ///  
    [CLSCompliant(false)]
    public sealed partial class ObjectItemCollection : ItemCollection 
    { 
        #region Constructors
 
        /// 
        /// The ObjectItemCollection that loads metadata from assemblies
        /// 
        public ObjectItemCollection() 
            : base(DataSpace.OSpace)
        { 
            foreach (PrimitiveType type in ClrProviderManifest.Instance.GetStoreTypes()) 
            {
                AddInternal(type); 
                _primitiveTypeMaps.Add(type);
            }
        }
        #endregion 

        #region Fields 
 
        // Cache for primitive type maps for Edm to provider
        private readonly CacheForPrimitiveTypes _primitiveTypeMaps = new CacheForPrimitiveTypes(); 

        // Used for tracking the loading of an assembly and its referenced assemblies. Though the value of an entry is bool, the logic represented
        // by an entry is tri-state, the third state represented by a "missing" entry. To summarize:
        // 1. The  associated with an  is "true"  : Specified and all referenced assemblies have been loaded 
        // 2. The  associated with an  is "false" : Specified assembly loaded. Its referenced assemblies may not be loaded
        // 3. The  is missing                            : Specified assembly has not been loaded 
        private KnownAssembliesSet _knownAssemblies = new KnownAssembliesSet(); 

        // Dictionary which keeps tracks of oc mapping information - the key is the conceptual name of the type 
        // and the value is the reference to the ospace type
        private Dictionary _ocMapping = new Dictionary();

        private object _loaderCookie; 
        private object _loadAssemblyLock = new object();
 
        internal object LoadAssemblyLock 
        {
            get 
            {
                return _loadAssemblyLock;
            }
        } 

        internal static IList ViewGenerationAssemblies 
        { 
            get
            { 
                return AssemblyCache.ViewGenerationAssemblies;
            }
        }
 
        #endregion
 
        #region Methods 

 
        internal static bool IsCompiledViewGenAttributePresent(Assembly assembly)
        {
            return assembly.IsDefined(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/);
        } 

        ///  
        /// The method loads the O-space metadata for all the referenced assemblies starting from the given assembly 
        /// in a recursive way.
        /// The assembly should be from Assembly.GetCallingAssembly via one of our public API's. 
        /// 
        /// assembly whose dependency list we are going to traverse
        internal void ImplicitLoadAllReferencedAssemblies(Assembly assembly, EdmItemCollection edmItemCollection)
        { 
            if (!MetadataAssemblyHelper.ShouldFilterAssembly(assembly))
            { 
                bool loadAllReferencedAssemblies = true; 
                LoadAssemblyFromCache(this, assembly, loadAllReferencedAssemblies, edmItemCollection, null);
            } 
        }

        internal void ImplicitLoadViewsFromAllReferencedAssemblies(Assembly assembly)
        { 
            // we filter implicit loads
            if (MetadataAssemblyHelper.ShouldFilterAssembly(assembly)) 
            { 
                return;
            } 
            lock (this)
            {
                CollectIfViewGenAssembly(assembly);
 
                foreach (Assembly referenceAssembly in MetadataAssemblyHelper.GetNonSystemReferencedAssemblies(assembly))
                { 
                    EntityBid.Trace(" loadededAssembly='%ls'\n", referenceAssembly.FullName); 
                    CollectIfViewGenAssembly(referenceAssembly);
                } 
            }
        }

        ///  
        /// Load metadata from the given assembly
        ///  
        /// The assembly from which to load metadata 
        /// thrown if assembly argument is null
        public void LoadFromAssembly(Assembly assembly) 
        {
            ExplicitLoadFromAssembly(assembly, null, null);
        }
 
        /// 
        /// Load metadata from the given assembly 
        ///  
        /// The assembly from which to load metadata
        /// thrown if assembly argument is null 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
        public void LoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection, Action logLoadMessage)
        {
            EntityUtil.CheckArgumentNull(assembly, "assembly"); 
            EntityUtil.CheckArgumentNull(edmItemCollection, "edmItemCollection");
            EntityUtil.CheckArgumentNull(logLoadMessage, "logLoadMessage"); 
 
            ExplicitLoadFromAssembly(assembly, edmItemCollection, logLoadMessage);
        } 

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
        public void LoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection)
        { 
            EntityUtil.CheckArgumentNull(assembly, "assembly");
            EntityUtil.CheckArgumentNull(edmItemCollection, "edmItemCollection"); 
 
            ExplicitLoadFromAssembly(assembly, edmItemCollection, null);
        } 
        /// 
        /// Explicit loading means that the user specifically asked us to load this assembly.
        /// We won't do any filtering, they "know what they are doing"
        ///  
        internal void ExplicitLoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection, Action logLoadMessage)
        { 
            EntityBid.Trace(" assembly='%ls'\n", assembly.FullName); 
            LoadAssemblyFromCache(this, assembly, false /*loadAllReferencedAssemblies*/, edmItemCollection, logLoadMessage);
            //Since User called LoadFromAssembly, so we should collect the generated views if present 
            //even if the schema attribute is not present
            if (IsCompiledViewGenAttributePresent(assembly) && !ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(assembly))
            {
                CollectIfViewGenAssembly(assembly); 
            }
        } 
 
        /// 
        /// Implicit loading means that we are trying to help the user find the right 
        /// assembly, but they didn't explicitly ask for it. Our Implicit rules require that
        /// we filter out assemblies with the Ecma or MicrosoftPublic PublicKeyToken on them
        /// 
        internal void ImplicitLoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection) 
        {
            EntityBid.Trace(" assembly='%ls'\n", assembly.FullName); 
            if (!MetadataAssemblyHelper.ShouldFilterAssembly(assembly)) 
            {
                // it meets the Implicit rules Load it 
                ExplicitLoadFromAssembly(assembly, edmItemCollection, null);
            }
        }
 
        /// 
        /// Implicit loading means that we are trying to help the user find the right 
        /// assembly, but they didn't explicitly ask for it. Our Implicit rules require that 
        /// we filter out assemblies with the Ecma or MicrosoftPublic PublicKeyToken on them
        /// 
        /// Load metadata from the type's assembly.
        /// 
        /// The type's assembly is loaded into the OSpace ItemCollection
        /// true if the type and all its generic arguments are filtered out (did not attempt to load assembly) 
        internal bool ImplicitLoadAssemblyForType(Type type, EdmItemCollection edmItemCollection)
        { 
            bool result; 

            if (!MetadataAssemblyHelper.ShouldFilterAssembly(type.Assembly)) 
            {
                // InternalLoadFromAssembly will check _knownAssemblies
                result = LoadAssemblyFromCache(this, type.Assembly, false /*loadAllReferencedAssemblies*/, edmItemCollection, null);
            } 
            else
            { 
                result = false; 
            }
 
            if (type.IsGenericType)
            {
                // recursively load all generic types
                // interesting code paths are ObjectQuery>, ObjectQuery> 
                foreach (Type t in type.GetGenericArguments())
                { 
                    result |= ImplicitLoadAssemblyForType(t, edmItemCollection); 
                }
            } 
            return result;
        }

        ///  
        /// internal static method to get the relationship name
        ///  
        ///  
        /// 
        ///  
        internal AssociationType GetRelationshipType(Type entityClrType, string relationshipName)
        {
            AssociationType associationType;
            if (TryGetItem(relationshipName, out associationType)) 
            {
                return associationType; 
            } 
            return null;
        } 

        /// 
        /// Loads the OSpace types in the assembly and returns them as a dictionary
        ///  
        /// The assembly to load
        /// A mapping from names to OSpace EdmTypes 
        internal static Dictionary LoadTypesExpensiveWay(Assembly assembly) 
        {
            Dictionary typesInLoading = null; 

            List errors;
            KnownAssembliesSet knownAssemblies = new KnownAssembliesSet();
 
            AssemblyCache.LoadAssembly(assembly, false /*loadAllReferencedAssemblies*/,
                knownAssemblies, out typesInLoading, out errors); 
 
            // Check for errors
            if (errors.Count != 0) 
            {
                throw EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors));
            }
 
            return typesInLoading;
        } 
 
        /// 
        /// internal static method to get the relationship name 
        /// 
        /// 
        /// 
        ///  
        internal static AssociationType GetRelationshipTypeExpensiveWay(Type entityClrType, string relationshipName)
        { 
            Dictionary typesInLoading = LoadTypesExpensiveWay(entityClrType.Assembly); 
            if (typesInLoading != null)
            { 
                EdmType edmType;
                // Look in typesInLoading for relationship type
                if (typesInLoading.TryGetValue(relationshipName, out edmType) && Helper.IsRelationshipType(edmType))
                { 
                    return (AssociationType)edmType;
                } 
            } 
            return null;
        } 

        /// 
        /// internal static method to get all the AssociationTypes from an assembly
        ///  
        /// The assembly from which to load relationship types
        /// An enumeration of OSpace AssociationTypes that are present in this assembly 
        internal static IEnumerable GetAllRelationshipTypesExpensiveWay(Assembly assembly) 
        {
            Dictionary typesInLoading = LoadTypesExpensiveWay(assembly); 
            if (typesInLoading != null)
            {
                // Iterate through the EdmTypes looking for AssociationTypes
                foreach (EdmType edmType in typesInLoading.Values) 
                {
                    if (Helper.IsAssociationType(edmType)) 
                    { 
                        yield return (AssociationType)edmType;
                    } 
                }
            }
            yield break;
        } 

        private static bool LoadAssemblyFromCache(ObjectItemCollection objectItemCollection, Assembly assembly, 
            bool loadReferencedAssemblies, EdmItemCollection edmItemCollection, Action logLoadMessage) 
        {
            // Check if its loaded in the cache - if the call is for loading referenced assemblies, make sure that all referenced 
            // assemblies are also loaded
            KnownAssemblyEntry entry;
            if (objectItemCollection._knownAssemblies.TryGetKnownAssembly(assembly, objectItemCollection._loaderCookie, edmItemCollection, out entry))
            { 
                // Proceed if only we need to load the referenced assemblies and they are not loaded
                if (loadReferencedAssemblies == false) 
                { 
                    // don't say we loaded anything, unless we actually did before
                    return entry.CacheEntry.TypesInAssembly.Count != 0; 
                }
                else if (entry.ReferencedAssembliesAreLoaded == true)
                {
                    // this assembly was part of a all hands reference search 
                    return true;
                } 
            } 

            lock (objectItemCollection.LoadAssemblyLock) 
            {
                // Check after acquiring the lock, since the known assemblies might have got modified
                // Check if the assembly is already loaded. The reason we need to check if the assembly is already loaded, is that
                if (objectItemCollection._knownAssemblies.TryGetKnownAssembly(assembly, objectItemCollection._loaderCookie, edmItemCollection, out entry)) 
                {
                    // Proceed if only we need to load the referenced assemblies and they are not loaded 
                    if (loadReferencedAssemblies == false || entry.ReferencedAssembliesAreLoaded == true) 
                    {
                        return true; 
                    }
                }

                Dictionary typesInLoading; 
                List errors;
                KnownAssembliesSet knownAssemblies; 
 
                if (objectItemCollection != null)
                { 
                    knownAssemblies = new KnownAssembliesSet(objectItemCollection._knownAssemblies);
                }
                else
                { 
                    knownAssemblies = new KnownAssembliesSet();
                } 
 
                // Load the assembly from the cache
                AssemblyCache.LoadAssembly(assembly, loadReferencedAssemblies, knownAssemblies, edmItemCollection, logLoadMessage, ref objectItemCollection._loaderCookie, out typesInLoading, out errors); 

                // Throw if we have encountered errors
                if (errors.Count != 0)
                { 
                    throw EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors));
                } 
 
                // We can encounter new assemblies, but they may not have any time in them
                if (typesInLoading.Count != 0) 
                {
                    // No errors, so go ahead and add the types and make them readonly
                    // The existence of the loading lock tells us whether we should be thread safe or not, if we need
                    // to be thread safe, then we need to use AtomicAddRange. We don't need to actually use the lock 
                    // because the caller should have done it already
                    // Recheck the assemblies added, another list is created just to match up the collection type 
                    // taken in by AtomicAddRange() 
                    List globalItems = new List();
                    foreach (EdmType edmType in typesInLoading.Values) 
                    {
                        globalItems.Add(edmType);

                        string cspaceTypeName = ""; 
                        try
                        { 
                            // Also populate the ocmapping information 
                            if (Helper.IsEntityType(edmType))
                            { 
                                cspaceTypeName = ((ClrEntityType)edmType).CSpaceTypeName;
                                objectItemCollection._ocMapping.Add(cspaceTypeName, edmType);
                            }
                            else if (Helper.IsComplexType(edmType)) 
                            {
                                cspaceTypeName = ((ClrComplexType)edmType).CSpaceTypeName; 
                                objectItemCollection._ocMapping.Add(cspaceTypeName, edmType); 
                            }
                            // for rest of the types like relationship type, we do not have oc mapping, so we don't keep 
                            // to keep that information
                        }
                        catch (ArgumentException e)
                        { 
                            throw new MappingException(Strings.Mapping_CannotMapCLRTypeMultipleTimes(cspaceTypeName), e);
                        } 
                    } 

                    // Create a new ObjectItemCollection and add all the global items to it. 
                    // Also copy all the existing items from the existing collection
                    objectItemCollection.AtomicAddRange(globalItems);
                }
 

                // Update the value of known assemblies 
                objectItemCollection._knownAssemblies = knownAssemblies; 

                foreach (Assembly loadedAssembly in knownAssemblies.Assemblies) 
                {
                    CollectIfViewGenAssembly(loadedAssembly);
                }
 
                return typesInLoading.Count != 0;
            } 
        } 

        ///  
        /// Check to see if the assembly has the custom view generation attribute AND
        /// collect the assembly into the local list if it has cutom attribute.
        /// 
        ///  
        /// 
        private static void CollectIfViewGenAssembly(Assembly assembly) 
        { 
            if (assembly.IsDefined(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/))
            { 
                if (!AssemblyCache.ViewGenerationAssemblies.Contains(assembly))
                {
                    AssemblyCache.ViewGenerationAssemblies.Add(assembly);
                } 
            }
        } 
 
        /// 
        /// Get the list of primitive types for the given space 
        /// 
        /// 
        public IEnumerable GetPrimitiveTypes()
        { 
            return _primitiveTypeMaps.GetTypes();
        } 
 
        /// 
        /// The method returns the underlying CLR type for the specified OSpace type argument. 
        /// If the DataSpace of the parameter is not OSpace, an ArgumentException is thrown.
        /// 
        /// The OSpace type to look up
        /// The CLR type of the OSpace argument 
        public Type GetClrType(StructuralType objectSpaceType)
        { 
            Type clrType; 
            if (!this.TryGetClrType(objectSpaceType, out clrType))
            { 
                throw EntityUtil.Argument(Strings.FailedToFindClrTypeMapping(objectSpaceType.Identity));
            }

            return clrType; 
        }
 
        ///  
        /// The method returns the underlying CLR type for the specified OSpace type argument.
        /// If the DataSpace of the parameter is not OSpace, the method returns false and sets 
        /// the out parameter to null.
        /// 
        /// The OSpace type to look up
        /// The CLR type of the OSpace argument 
        /// true on success, false on failure
        public bool TryGetClrType(StructuralType objectSpaceType, out Type clrType) 
        { 
            EntityUtil.CheckArgumentNull(objectSpaceType, "objectSpaceType");
 
            if (objectSpaceType.DataSpace != DataSpace.OSpace)
            {
                throw EntityUtil.Argument(Strings.ArgumentMustBeOSpaceType, "objectSpaceType");
            } 

            clrType = null; 
 
            if (BuiltInTypeKind.EntityType == objectSpaceType.BuiltInTypeKind)
            { 
                clrType = ((ClrEntityType)objectSpaceType).ClrType;
            }
            else
                if (BuiltInTypeKind.ComplexType == objectSpaceType.BuiltInTypeKind) 
                {
                    clrType = ((ClrComplexType)objectSpaceType).ClrType; 
                } 

            return clrType != null; 
        }

        /// 
        /// Given the canonical primitive type, get the mapping primitive type in the given dataspace 
        /// 
        /// canonical primitive type 
        /// The mapped scalar type 
        internal override PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind modelType)
        { 
            PrimitiveType type = null;
            _primitiveTypeMaps.TryGetType(modelType, null, out type);
            return type;
        } 

        ///  
        /// Get the OSpace type given the CSpace typename 
        /// 
        ///  
        /// 
        /// 
        /// 
        internal bool TryGetOSpaceType(EdmType cspaceType, out EdmType edmType) 
        {
            Debug.Assert(DataSpace.CSpace == cspaceType.DataSpace, "DataSpace should be CSpace"); 
 
            // check if there is an entity or complex type mapping with this name
            if (BuiltInTypeKind.EntityType == cspaceType.BuiltInTypeKind || 
                BuiltInTypeKind.ComplexType == cspaceType.BuiltInTypeKind)
            {
                return _ocMapping.TryGetValue(cspaceType.Identity, out edmType);
            } 

            return TryGetItem(cspaceType.Identity, out edmType); 
        } 

        ///  
        /// Given the ospace type, returns the fullname of the mapped cspace type.
        /// Today, since we allow non-default mapping between entity type and complex type,
        /// this is only possible for entity and complex type.
        ///  
        /// 
        ///  
        internal static string TryGetMappingCSpaceTypeIdentity(EdmType edmType) 
        {
            Debug.Assert(DataSpace.OSpace == edmType.DataSpace, "DataSpace must be OSpace"); 

            if (BuiltInTypeKind.EntityType == edmType.BuiltInTypeKind)
            {
                return ((ClrEntityType)edmType).CSpaceTypeName; 
            }
            else if (BuiltInTypeKind.ComplexType == edmType.BuiltInTypeKind) 
            { 
                return ((ClrComplexType)edmType).CSpaceTypeName;
            } 

            return edmType.Identity;
        }
 
        public override System.Collections.ObjectModel.ReadOnlyCollection GetItems()
        { 
            return base.InternalGetItems(typeof(T)) as System.Collections.ObjectModel.ReadOnlyCollection; 
        }
        #endregion 
    }
}

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

Link Menu

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