/// <summary>
        ///     Creates a structural OSpace type based on CLR type and CSpace type.
        /// </summary>
        /// <param name="type"> CLR type. </param>
        /// <param name="cspaceType"> CSpace Type </param>
        /// <param name="newOSpaceType">
        ///     OSpace type created based on CLR <paramref name="type" /> and <paramref name="cspaceType" />
        /// </param>
        /// <returns>
        ///     <c>true</c> if the type was created successfully. Otherwise <c>false</c> .
        /// </returns>
        private bool TryCreateStructuralType(Type type, StructuralType cspaceType, out EdmType newOSpaceType)
        {
            DebugCheck.NotNull(type);
            DebugCheck.NotNull(cspaceType);

            var referenceResolutionListForCurrentType = new List <Action>();

            newOSpaceType = null;
            Debug.Assert(TypesMatchByConvention(type, cspaceType), "The types passed as parameters don't match by convention.");

            StructuralType ospaceType;

            if (Helper.IsEntityType(cspaceType))
            {
                ospaceType = new ClrEntityType(type, cspaceType.NamespaceName, cspaceType.Name);
            }
            else
            {
                Debug.Assert(Helper.IsComplexType(cspaceType), "Invalid type attribute encountered");
                ospaceType = new ClrComplexType(type, cspaceType.NamespaceName, cspaceType.Name);
            }

            if (cspaceType.BaseType != null)
            {
                if (TypesMatchByConvention(type.BaseType, cspaceType.BaseType))
                {
                    TrackClosure(type.BaseType);
                    referenceResolutionListForCurrentType.Add(
                        () => ospaceType.BaseType = ResolveBaseType((StructuralType)cspaceType.BaseType, type));
                }
                else
                {
                    var message = Strings.Validator_OSpace_Convention_BaseTypeIncompatible(
                        type.BaseType.FullName, type.FullName, cspaceType.BaseType.FullName);
                    SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
                    return(false);
                }
            }

            // Load the properties for this type
            if (!TryCreateMembers(type, cspaceType, ospaceType, referenceResolutionListForCurrentType))
            {
                return(false);
            }

            // Add this to the known type map so we won't try to load it again
            SessionData.TypesInLoading.Add(type.FullName, ospaceType);

            // we only add the referenceResolution to the list unless we structrually matched this type
            foreach (var referenceResolution in referenceResolutionListForCurrentType)
            {
                _referenceResolutions.Add(referenceResolution);
            }

            newOSpaceType = ospaceType;
            return(true);
        }
Example #2
0
        public void LoadTypes_sets_all_loaded_types_to_read_only()
        {
            var mockFactory   = CreateMockFactory();
            var clrEntityType = new ClrEntityType(typeof(Random), "Cheese", "Pickle");

            mockFactory.Object.LoadedTypes.Add("Pickle", clrEntityType);

            new CodeFirstOSpaceLoader(mockFactory.Object).LoadTypes(new EdmItemCollection(), new ObjectItemCollection());

            Assert.True(clrEntityType.IsReadOnly);
        }
Example #3
0
 internal ObjectItemLoadingSessionData(
     KnownAssembliesSet knownAssemblies,
     LockedAssemblyCache lockedAssemblyCache,
     EdmItemCollection edmItemCollection,
     Action <string> logLoadMessage,
     object loaderCookie)
 {
     this._typesInLoading       = new Dictionary <string, EdmType>((IEqualityComparer <string>)StringComparer.Ordinal);
     this._errors               = new List <EdmItemError>();
     this._knownAssemblies      = knownAssemblies;
     this._lockedAssemblyCache  = lockedAssemblyCache;
     this._edmItemCollection    = edmItemCollection;
     this._loadMessageLogger    = new LoadMessageLogger(logLoadMessage);
     this._cspaceToOspace       = new Dictionary <EdmType, EdmType>();
     this._loaderFactory        = (Func <Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>)loaderCookie;
     this._originalLoaderCookie = loaderCookie;
     if (!(this._loaderFactory == new Func <Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>(ObjectItemConventionAssemblyLoader.Create)) || this._edmItemCollection == null)
     {
         return;
     }
     foreach (KnownAssemblyEntry entry in this._knownAssemblies.GetEntries((object)this._loaderFactory, edmItemCollection))
     {
         foreach (EdmType edmType in entry.CacheEntry.TypesInAssembly.OfType <EdmType>())
         {
             if (Helper.IsEntityType(edmType))
             {
                 ClrEntityType clrEntityType = (ClrEntityType)edmType;
                 this._cspaceToOspace.Add((EdmType)this._edmItemCollection.GetItem <StructuralType>(clrEntityType.CSpaceTypeName), (EdmType)clrEntityType);
             }
             else if (Helper.IsComplexType(edmType))
             {
                 ClrComplexType clrComplexType = (ClrComplexType)edmType;
                 this._cspaceToOspace.Add((EdmType)this._edmItemCollection.GetItem <StructuralType>(clrComplexType.CSpaceTypeName), (EdmType)clrComplexType);
             }
             else if (Helper.IsEnumType(edmType))
             {
                 ClrEnumType clrEnumType = (ClrEnumType)edmType;
                 this._cspaceToOspace.Add((EdmType)this._edmItemCollection.GetItem <EnumType>(clrEnumType.CSpaceTypeName), (EdmType)clrEnumType);
             }
             else
             {
                 this._cspaceToOspace.Add((EdmType)this._edmItemCollection.GetItem <StructuralType>(edmType.FullName), edmType);
             }
         }
     }
 }
 public ProxyTypeBuilder(ClrEntityType ospaceEntityType)
 {
     _ospaceEntityType = ospaceEntityType;
     _baseImplementor = new BaseProxyImplementor();
     _ipocoImplementor = new IPOCOImplementor(ospaceEntityType);
     _lazyLoadImplementor = new LazyLoadImplementor(ospaceEntityType);
     _dataContractImplementor = new DataContractImplementor(ospaceEntityType);
     _iserializableImplementor = new SerializableImplementor(ospaceEntityType);
 }
        /// <summary>
        ///     Build a CLR proxy type for the supplied EntityType.
        /// </summary>
        /// <param name="ospaceEntityType"> EntityType in O-Space that represents the CLR type to be proxied. </param>
        /// <returns> EntityProxyTypeInfo object that contains the constructed proxy type, along with any behaviors associated with that type; or null if a proxy type cannot be constructed for the specified EntityType. </returns>
        private static EntityProxyTypeInfo BuildType(
            ModuleBuilder moduleBuilder,
            ClrEntityType ospaceEntityType,
            MetadataWorkspace workspace)
        {
            Debug.Assert(
                _typeMapLock.IsUpgradeableReadLockHeld,
                "EntityProxyTypeInfo.BuildType method was called without first acquiring an upgradeable read lock from _typeMapLock.");

            EntityProxyTypeInfo proxyTypeInfo;

            var proxyTypeBuilder = new ProxyTypeBuilder(ospaceEntityType);
            var proxyType = proxyTypeBuilder.CreateType(moduleBuilder);

            if (proxyType != null)
            {
                // Set the runtime assembly of the proxy types if it hasn't already been set.
                // This is used by the IsProxyType method.
                var typeAssembly = proxyType.Assembly;
                if (!_proxyRuntimeAssemblies.Contains(typeAssembly))
                {
                    _proxyRuntimeAssemblies.Add(typeAssembly);
                    AddAssemblyToResolveList(typeAssembly);
                }

                proxyTypeInfo = new EntityProxyTypeInfo(
                    proxyType,
                    ospaceEntityType,
                    proxyTypeBuilder.CreateInitalizeCollectionMethod(proxyType),
                    proxyTypeBuilder.BaseGetters,
                    proxyTypeBuilder.BaseSetters,
                    workspace);

                foreach (var member in proxyTypeBuilder.LazyLoadMembers)
                {
                    InterceptMember(member, proxyType, proxyTypeInfo);
                }

                SetResetFKSetterFlagDelegate(proxyType, proxyTypeInfo);
                SetCompareByteArraysDelegate(proxyType);
            }
            else
            {
                proxyTypeInfo = null;
            }

            return proxyTypeInfo;
        }
        /// <summary>
        ///     Return proxy type information for the specified O-Space EntityType.
        /// </summary>
        /// <param name="ospaceEntityType"> EntityType in O-Space that represents the CLR type to be proxied. Must not be null. </param>
        /// <returns> A non-null EntityProxyTypeInfo instance that contains information about the type of proxy for the specified O-Space EntityType; or null if no proxy can be created for the specified type. </returns>
        internal static EntityProxyTypeInfo GetProxyType(ClrEntityType ospaceEntityType, MetadataWorkspace workspace)
        {
            DebugCheck.NotNull(ospaceEntityType);
            DebugCheck.NotNull(workspace);
            Debug.Assert(ospaceEntityType.DataSpace == DataSpace.OSpace, "ospaceEntityType.DataSpace must be OSpace");

            EntityProxyTypeInfo proxyTypeInfo = null;

            // Check if an entry for the proxy type already exists.
            if (TryGetProxyType(ospaceEntityType.ClrType, ospaceEntityType.CSpaceTypeName, out proxyTypeInfo))
            {
                if (proxyTypeInfo != null)
                {
                    proxyTypeInfo.ValidateType(ospaceEntityType);
                }
                return proxyTypeInfo;
            }

            // No entry found, may need to create one.
            // Acquire an upgradeable read lock so that:
            // 1. Other readers aren't blocked while the second existence check is performed.
            // 2. Other threads that may have also detected the absence of an entry block while the first thread handles proxy type creation.

            _typeMapLock.EnterUpgradeableReadLock();
            try
            {
                return TryCreateProxyType(ospaceEntityType, workspace);
            }
            finally
            {
                _typeMapLock.ExitUpgradeableReadLock();
            }
        }
        private bool TryCreateStructuralType(Type type, StructuralType cspaceType, out EdmType newOSpaceType)
        {
            DebugCheck.NotNull(type);
            DebugCheck.NotNull(cspaceType);

            var referenceResolutionListForCurrentType = new List<Action>();
            newOSpaceType = null;

            StructuralType ospaceType;
            if (Helper.IsEntityType(cspaceType))
            {
                ospaceType = new ClrEntityType(type, cspaceType.NamespaceName, cspaceType.Name);
            }
            else
            {
                Debug.Assert(Helper.IsComplexType(cspaceType), "Invalid type attribute encountered");
                ospaceType = new ClrComplexType(type, cspaceType.NamespaceName, cspaceType.Name);
            }

            if (cspaceType.BaseType != null)
            {
                if (TypesMatchByConvention(type.BaseType(), cspaceType.BaseType))
                {
                    TrackClosure(type.BaseType());
                    referenceResolutionListForCurrentType.Add(
                        () => ospaceType.BaseType = ResolveBaseType((StructuralType)cspaceType.BaseType, type));
                }
                else
                {
                    var message = Strings.Validator_OSpace_Convention_BaseTypeIncompatible(
                        type.BaseType().FullName, type.FullName, cspaceType.BaseType.FullName);
                    LogLoadMessage(message, cspaceType);
                    return false;
                }
            }

            // Load the properties for this type
            if (!TryCreateMembers(type, cspaceType, ospaceType, referenceResolutionListForCurrentType))
            {
                return false;
            }

            // Add this to the known type map so we won't try to load it again
            LoadedTypes.Add(type.FullName, ospaceType);

            // we only add the referenceResolution to the list unless we structrually matched this type
            foreach (var referenceResolution in referenceResolutionListForCurrentType)
            {
                ReferenceResolutions.Add(referenceResolution);
            }

            newOSpaceType = ospaceType;
            return true;
        }
        /// <summary>
        ///     Load metadata of the given type - when you call this method, you should check and make sure that the type has
        ///     edm attribute. If it doesn't,we won't load the type and it will be returned as null
        /// </summary>
        /// <param name="clrType"> </param>
        /// <param name="context"> </param>
        /// <returns> </returns>
        private void LoadType(Type clrType)
        {
            Debug.Assert(clrType.Assembly == SourceAssembly, "Why are we loading a type that is not in our assembly?");
            Debug.Assert(!SessionData.TypesInLoading.ContainsKey(clrType.FullName), "Trying to load a type that is already loaded???");
            Debug.Assert(!clrType.IsGenericType, "Generic type is not supported");

            EdmType edmType = null;

            var typeAttributes = (EdmTypeAttribute[])clrType.GetCustomAttributes(typeof(EdmTypeAttribute), false /*inherit*/);

            // the CLR doesn't allow types to have duplicate/multiple attribute declarations

            if (typeAttributes.Length != 0)
            {
                if (clrType.IsNested)
                {
                    SessionData.EdmItemErrors.Add(
                        new EdmItemError(Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly.FullName)));
                    return;
                }
                var typeAttribute = typeAttributes[0];
                var cspaceTypeName = String.IsNullOrEmpty(typeAttribute.Name) ? clrType.Name : typeAttribute.Name;
                if (String.IsNullOrEmpty(typeAttribute.NamespaceName)
                    && clrType.Namespace == null)
                {
                    SessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_TypeHasNoNamespace));
                    return;
                }

                var cspaceNamespaceName = String.IsNullOrEmpty(typeAttribute.NamespaceName)
                                              ? clrType.Namespace
                                              : typeAttribute.NamespaceName;

                if (typeAttribute.GetType()
                    == typeof(EdmEntityTypeAttribute))
                {
                    edmType = new ClrEntityType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else if (typeAttribute.GetType()
                         == typeof(EdmComplexTypeAttribute))
                {
                    edmType = new ClrComplexType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else
                {
                    Debug.Assert(typeAttribute is EdmEnumTypeAttribute, "Invalid type attribute encountered");

                    // Note that TryGetPrimitiveType() will return false not only for types that are not primitive 
                    // but also for CLR primitive types that are valid underlying enum types in CLR but are not 
                    // a valid Edm primitive types (e.g. ulong) 
                    PrimitiveType underlyingEnumType;
                    if (!ClrProviderManifest.Instance.TryGetPrimitiveType(clrType.GetEnumUnderlyingType(), out underlyingEnumType))
                    {
                        SessionData.EdmItemErrors.Add(
                            new EdmItemError(
                                Strings.Validator_UnsupportedEnumUnderlyingType(clrType.GetEnumUnderlyingType().FullName)));

                        return;
                    }

                    edmType = new ClrEnumType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
            }
            else
            {
                // not a type we are interested
                return;
            }

            Debug.Assert(
                !CacheEntry.ContainsType(edmType.Identity), "This type must not be already present in the list of types for this assembly");
            // Also add this to the list of the types for this assembly
            CacheEntry.TypesInAssembly.Add(edmType);

            // Add this to the known type map so we won't try to load it again
            SessionData.TypesInLoading.Add(clrType.FullName, edmType);

            // Load properties for structural type
            if (Helper.IsStructuralType(edmType))
            {
                //Load base type only for entity type - not sure if we will allow complex type inheritance
                if (Helper.IsEntityType(edmType))
                {
                    TrackClosure(clrType.BaseType);
                    AddTypeResolver(
                        () => edmType.BaseType = ResolveBaseType(clrType.BaseType));
                }

                // Load the properties for this type
                LoadPropertiesFromType((StructuralType)edmType);
            }

            return;
        }
        internal EntityProxyTypeInfo(
            Type proxyType,
            ClrEntityType ospaceEntityType,
            DynamicMethod initializeCollections,
            List<PropertyInfo> baseGetters,
            List<PropertyInfo> baseSetters,
            MetadataWorkspace workspace)
        {
            DebugCheck.NotNull(proxyType);
            DebugCheck.NotNull(workspace);

            _proxyType = proxyType;
            _entityType = ospaceEntityType;

            _initializeCollections = initializeCollections;

            foreach (var relationshipType in GetAllRelationshipsForType(workspace, proxyType))
            {
                _navigationPropertyAssociationTypes.Add(relationshipType.FullName, relationshipType);

                if (relationshipType.Name != relationshipType.FullName)
                {
                    // Sometimes there isn't enough metadata to have a container name
                    // Default codegen doesn't qualify names
                    _navigationPropertyAssociationTypes.Add(relationshipType.Name, relationshipType);
                }
            }

            var entityWrapperField = proxyType.GetField(
                EntityWrapperFieldName, BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

            var Object_Parameter = Expression.Parameter(typeof(object), "proxy");
            var Value_Parameter = Expression.Parameter(typeof(object), "value");

            Debug.Assert(entityWrapperField != null, "entityWrapperField does not exist");

            // Create the Wrapper Getter
            var lambda = Expression.Lambda<Func<object, object>>(
                Expression.Field(
                    Expression.Convert(Object_Parameter, entityWrapperField.DeclaringType), entityWrapperField),
                Object_Parameter);
            var getEntityWrapperDelegate = lambda.Compile();
            Proxy_GetEntityWrapper = (object proxy) =>
                {
                    // This code validates that the wrapper points to the proxy that holds the wrapper.
                    // This guards against mischief by switching this wrapper out for another one obtained
                    // from a different object.
                    var wrapper = ((IEntityWrapper)getEntityWrapperDelegate(proxy));
                    if (wrapper != null
                        && !ReferenceEquals(wrapper.Entity, proxy))
                    {
                        throw new InvalidOperationException(Strings.EntityProxyTypeInfo_ProxyHasWrongWrapper);
                    }
                    return wrapper;
                };

            // Create the Wrapper setter
            Proxy_SetEntityWrapper = Expression.Lambda<Func<object, object, object>>(
                Expression.Assign(
                    Expression.Field(
                        Expression.Convert(Object_Parameter, entityWrapperField.DeclaringType),
                        entityWrapperField),
                    Value_Parameter),
                Object_Parameter, Value_Parameter).Compile();

            var PropertyName_Parameter = Expression.Parameter(typeof(string), "propertyName");
            var baseGetterMethod = proxyType.GetMethod(
                "GetBasePropertyValue", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null);
            if (baseGetterMethod != null)
            {
                _baseGetter = Expression.Lambda<Func<object, string, object>>(
                    Expression.Call(Expression.Convert(Object_Parameter, proxyType), baseGetterMethod, PropertyName_Parameter),
                    Object_Parameter, PropertyName_Parameter).Compile();
            }

            var PropertyValue_Parameter = Expression.Parameter(typeof(object), "propertyName");
            var baseSetterMethod = proxyType.GetMethod(
                "SetBasePropertyValue", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string), typeof(object) }, null);
            if (baseSetterMethod != null)
            {
                _baseSetter = Expression.Lambda<Action<object, string, object>>(
                    Expression.Call(
                        Expression.Convert(Object_Parameter, proxyType), baseSetterMethod, PropertyName_Parameter, PropertyValue_Parameter),
                    Object_Parameter, PropertyName_Parameter, PropertyValue_Parameter).Compile();
            }

            _propertiesWithBaseGetter = new HashSet<string>(baseGetters.Select(p => p.Name));
            _propertiesWithBaseSetter = new HashSet<string>(baseSetters.Select(p => p.Name));

            _createObject = DelegateFactory.CreateConstructor(proxyType);
        }
 public void ValidateType(ClrEntityType ospaceEntityType)
 {
     if (ospaceEntityType != _entityType
         && ospaceEntityType.HashedDescription != _entityType.HashedDescription)
     {
         Debug.Assert(ospaceEntityType.ClrType == _entityType.ClrType);
         throw new InvalidOperationException(Strings.EntityProxyTypeInfo_DuplicateOSpaceType(ospaceEntityType.ClrType.FullName));
     }
 }
        private void LoadType(Type clrType)
        {
            Debug.Assert(clrType.Assembly() == SourceAssembly, "Why are we loading a type that is not in our assembly?");
            Debug.Assert(!SessionData.TypesInLoading.ContainsKey(clrType.FullName), "Trying to load a type that is already loaded???");
            Debug.Assert(!clrType.IsGenericType(), "Generic type is not supported");

            EdmType edmType = null;

            var typeAttributes = clrType.GetCustomAttributes <EdmTypeAttribute>(inherit: false);

            // the CLR doesn't allow types to have duplicate/multiple attribute declarations

            if (typeAttributes.Any())
            {
                if (clrType.IsNested)
                {
                    SessionData.EdmItemErrors.Add(
                        new EdmItemError(Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly().FullName)));
                    return;
                }
                var typeAttribute  = typeAttributes.First();
                var cspaceTypeName = String.IsNullOrEmpty(typeAttribute.Name) ? clrType.Name : typeAttribute.Name;
                if (String.IsNullOrEmpty(typeAttribute.NamespaceName) &&
                    clrType.Namespace == null)
                {
                    SessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_TypeHasNoNamespace));
                    return;
                }

                var cspaceNamespaceName = String.IsNullOrEmpty(typeAttribute.NamespaceName)
                                              ? clrType.Namespace
                                              : typeAttribute.NamespaceName;

                if (typeAttribute.GetType() == typeof(EdmEntityTypeAttribute))
                {
                    edmType = new ClrEntityType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else if (typeAttribute.GetType() == typeof(EdmComplexTypeAttribute))
                {
                    edmType = new ClrComplexType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else
                {
                    Debug.Assert(typeAttribute is EdmEnumTypeAttribute, "Invalid type attribute encountered");

                    // Note that TryGetPrimitiveType() will return false not only for types that are not primitive
                    // but also for CLR primitive types that are valid underlying enum types in CLR but are not
                    // a valid Edm primitive types (e.g. ulong)
                    PrimitiveType underlyingEnumType;
                    if (!ClrProviderManifest.Instance.TryGetPrimitiveType(clrType.GetEnumUnderlyingType(), out underlyingEnumType))
                    {
                        SessionData.EdmItemErrors.Add(
                            new EdmItemError(
                                Strings.Validator_UnsupportedEnumUnderlyingType(clrType.GetEnumUnderlyingType().FullName)));

                        return;
                    }

                    edmType = new ClrEnumType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
            }
            else
            {
                // not a type we are interested
                return;
            }

            Debug.Assert(
                !CacheEntry.ContainsType(edmType.Identity), "This type must not be already present in the list of types for this assembly");
            // Also add this to the list of the types for this assembly
            CacheEntry.TypesInAssembly.Add(edmType);

            // Add this to the known type map so we won't try to load it again
            SessionData.TypesInLoading.Add(clrType.FullName, edmType);

            // Load properties for structural type
            if (Helper.IsStructuralType(edmType))
            {
                //Load base type only for entity type - not sure if we will allow complex type inheritance
                if (Helper.IsEntityType(edmType))
                {
                    TrackClosure(clrType.BaseType());
                    AddTypeResolver(
                        () => edmType.BaseType = ResolveBaseType(clrType.BaseType()));
                }

                // Load the properties for this type
                LoadPropertiesFromType((StructuralType)edmType);
            }

            return;
        }