/// <summary>
        /// A helper method returning the underlying CLR type for the specified OSpace enum or structural type argument.
        /// If the DataSpace of the parameter is not OSpace, the method returns false and sets
        /// the out parameter to null.
        /// </summary>
        /// <param name="objectSpaceType">The OSpace enum type to look up</param>
        /// <param name="clrType">The CLR enum type of the OSpace argument</param>
        /// <returns>true on success, false on failure</returns>
        private static bool TryGetClrType(EdmType objectSpaceType, out Type clrType)
        {
            Debug.Assert(objectSpaceType == null || objectSpaceType is StructuralType || objectSpaceType is EnumType,
                         "Only enum or structural type expected");

            EntityUtil.CheckArgumentNull(objectSpaceType, "objectSpaceType");

            if (objectSpaceType.DataSpace != DataSpace.OSpace)
            {
                throw EntityUtil.Argument(Strings.ArgumentMustBeOSpaceType, "objectSpaceType");
            }

            clrType = null;

            if (Helper.IsEntityType(objectSpaceType) || Helper.IsComplexType(objectSpaceType) || Helper.IsEnumType(objectSpaceType))
            {
                Debug.Assert(objectSpaceType is ClrEntityType || objectSpaceType is ClrComplexType || objectSpaceType is ClrEnumType,
                             "Unexpected OSpace object type.");

                clrType = objectSpaceType.ClrType;

                Debug.Assert(clrType != null, "ClrType property of ClrEntityType/ClrComplexType/ClrEnumType objects must not be null");
            }

            return(clrType != null);
        }
Beispiel #2
0
        private void AddScalarMember(Type type, PropertyInfo clrProperty, StructuralType ospaceType, EdmProperty cspaceProperty, EdmType propertyType)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(clrProperty != null, "clrProperty != null");
            Debug.Assert(clrProperty.CanRead && clrProperty.CanWrite, "The clr property has to have a setter and a getter.");
            Debug.Assert(ospaceType != null, "ospaceType != null");
            Debug.Assert(cspaceProperty != null, "cspaceProperty != null");
            Debug.Assert(propertyType != null, "propertyType != null");
            Debug.Assert(Helper.IsScalarType(propertyType), "Property has to be primitive or enum.");

            var cspaceType = cspaceProperty.DeclaringType;

            bool isKeyMember = Helper.IsEntityType(cspaceType) && ((EntityType)cspaceType).KeyMemberNames.Contains(clrProperty.Name);

            // the property is nullable only if it is not a key and can actually be set to null (i.e. is not a value type or is a nullable value type)
            bool nullableFacetValue = !isKeyMember && (!clrProperty.PropertyType.IsValueType || Nullable.GetUnderlyingType(clrProperty.PropertyType) != null);

            EdmProperty ospaceProperty =
                new EdmProperty(
                    cspaceProperty.Name,
                    TypeUsage.Create(propertyType, new FacetValues {
                Nullable = nullableFacetValue
            }),
                    clrProperty,
                    type.TypeHandle);

            if (isKeyMember)
            {
                ((EntityType)ospaceType).AddKeyMember(ospaceProperty);
            }
            else
            {
                ospaceType.AddMember(ospaceProperty);
            }
        }
Beispiel #3
0
        /// <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)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(cspaceType != null, "cspaceType != null");

            List <Action> 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
                {
                    string 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, (StructuralType)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)
            {
                this._referenceResolutions.Add(referenceResolution);
            }

            newOSpaceType = ospaceType;
            return(true);
        }
        /// <summary>
        /// Get the OSpace type given the CSpace typename
        /// </summary>
        /// <param name="cspaceTypeName"></param>
        /// <param name="ignoreCase"></param>
        /// <param name="edmType"></param>
        /// <returns></returns>
        internal bool TryGetOSpaceType(EdmType cspaceType, out EdmType edmType)
        {
            Debug.Assert(DataSpace.CSpace == cspaceType.DataSpace, "DataSpace should be CSpace");

            // check if there is an entity, complex type or enum type mapping with this name
            if (Helper.IsEntityType(cspaceType) || Helper.IsComplexType(cspaceType) || Helper.IsEnumType(cspaceType))
            {
                return(_ocMapping.TryGetValue(cspaceType.Identity, out edmType));
            }

            return(TryGetItem <EdmType>(cspaceType.Identity, out edmType));
        }
Beispiel #5
0
        internal ObjectItemLoadingSessionData(KnownAssembliesSet knownAssemblies, LockedAssemblyCache lockedAssemblyCache, EdmItemCollection edmItemCollection, Action <String> logLoadMessage, object loaderCookie)
        {
            Debug.Assert(loaderCookie == null || loaderCookie is Func <Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "This is a bad loader cookie");

            _typesInLoading      = new Dictionary <string, EdmType>(StringComparer.Ordinal);
            _errors              = new List <EdmItemError>();
            _knownAssemblies     = knownAssemblies;
            _lockedAssemblyCache = lockedAssemblyCache;
            _loadersThatNeedLevel1PostSessionProcessing = new HashSet <ObjectItemAssemblyLoader>();
            _loadersThatNeedLevel2PostSessionProcessing = new HashSet <ObjectItemAssemblyLoader>();
            _edmItemCollection    = edmItemCollection;
            _loadMessageLogger    = new LoadMessageLogger(logLoadMessage);
            _cspaceToOspace       = new Dictionary <EdmType, EdmType>();
            _loaderFactory        = (Func <Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>)loaderCookie;
            _originalLoaderCookie = loaderCookie;
            if (_loaderFactory == ObjectItemConventionAssemblyLoader.Create && _edmItemCollection != null)
            {
                foreach (KnownAssemblyEntry entry in _knownAssemblies.GetEntries(_loaderFactory, edmItemCollection))
                {
                    foreach (EdmType type in entry.CacheEntry.TypesInAssembly.OfType <EdmType>())
                    {
                        if (Helper.IsEntityType(type))
                        {
                            ClrEntityType entityType = (ClrEntityType)type;
                            _cspaceToOspace.Add(_edmItemCollection.GetItem <StructuralType>(entityType.CSpaceTypeName), entityType);
                        }
                        else if (Helper.IsComplexType(type))
                        {
                            ClrComplexType complexType = (ClrComplexType)type;
                            _cspaceToOspace.Add(_edmItemCollection.GetItem <StructuralType>(complexType.CSpaceTypeName), complexType);
                        }
                        else if (Helper.IsEnumType(type))
                        {
                            ClrEnumType enumType = (ClrEnumType)type;
                            _cspaceToOspace.Add(_edmItemCollection.GetItem <EnumType>(enumType.CSpaceTypeName), enumType);
                        }
                        else
                        {
                            Debug.Assert(Helper.IsAssociationType(type));
                            _cspaceToOspace.Add(_edmItemCollection.GetItem <StructuralType>(type.FullName), type);
                        }
                    }
                }
            }
        }
        private bool TryGetRelationshipEndEntityType(Type type, out EntityType entityType)
        {
            if (type == null)
            {
                entityType = null;
                return(false);
            }

            EdmType edmType;

            if (!TryGetLoadedType(type, out edmType) || !Helper.IsEntityType(edmType))
            {
                entityType = null;
                return(false);
            }
            entityType = (EntityType)edmType;
            return(true);
        }
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="edmType"></param>
        /// <returns></returns>
        internal static string TryGetMappingCSpaceTypeIdentity(EdmType edmType)
        {
            Debug.Assert(DataSpace.OSpace == edmType.DataSpace, "DataSpace must be OSpace");

            if (Helper.IsEntityType(edmType))
            {
                return(((ClrEntityType)edmType).CSpaceTypeName);
            }
            else if (Helper.IsComplexType(edmType))
            {
                return(((ClrComplexType)edmType).CSpaceTypeName);
            }
            else if (Helper.IsEnumType(edmType))
            {
                return(((ClrEnumType)edmType).CSpaceTypeName);
            }

            return(edmType.Identity);
        }
Beispiel #8
0
 /// <summary>
 /// Determines if the given edmType is equal comparable. Consult "EntitySql Language Specification",
 /// section 7 - Comparison and Dependent Operations for details.
 /// </summary>
 /// <param name="edmType">an instance of an EdmType</param>
 /// <returns>true if edmType is equal-comparable, false otherwise</returns>
 private static bool IsEqualComparable(EdmType edmType)
 {
     if (Helper.IsPrimitiveType(edmType) || Helper.IsRefType(edmType) || Helper.IsEntityType(edmType) || Helper.IsEnumType(edmType))
     {
         return(true);
     }
     else if (Helper.IsRowType(edmType))
     {
         RowType rowType = (RowType)edmType;
         foreach (EdmProperty rowProperty in rowType.Properties)
         {
             if (!IsEqualComparable(rowProperty.TypeUsage))
             {
                 return(false);
             }
         }
         return(true);
     }
     return(false);
 }
        /// <summary>
        /// Load all the property metadata of the given type
        /// </summary>
        /// <param name="type">The CLR entity type</param>
        /// <param name="structuralType">The type where properties are loaded</param>
        /// <param name="context"></param>
        private void LoadPropertiesFromType(StructuralType structuralType)
        {
            // Look at both public, internal, and private instanced properties declared at this type, inherited members
            // are not looked at.  Internal and private properties are also looked at because they are also schematized fields
            PropertyInfo[] properties = structuralType.ClrType.GetProperties(PropertyReflectionBindingFlags);

            foreach (PropertyInfo property in properties)
            {
                EdmMember newMember           = null;
                bool      isEntityKeyProperty = false; //used for EdmScalarProperties only

                // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute
                // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute
                // we will just ignore it and skip to the next property.
                if (property.IsDefined(typeof(EdmRelationshipNavigationPropertyAttribute), false))
                {
                    // keep the loop var from being lifted
                    PropertyInfo pi = property;
                    _unresolvedNavigationProperties.Add(() =>
                                                        ResolveNavigationProperty(structuralType, pi));
                }
                else if (property.IsDefined(typeof(EdmScalarPropertyAttribute), false))
                {
                    if ((Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType).IsEnum)
                    {
                        TrackClosure(property.PropertyType);
                        PropertyInfo local = property;
                        AddTypeResolver(() => ResolveEnumTypeProperty(structuralType, local));
                    }
                    else
                    {
                        newMember = LoadScalarProperty(structuralType.ClrType, property, out isEntityKeyProperty);
                    }
                }
                else if (property.IsDefined(typeof(EdmComplexPropertyAttribute), false))
                {
                    TrackClosure(property.PropertyType);
                    // keep loop var from being lifted
                    PropertyInfo local = property;
                    AddTypeResolver(() => ResolveComplexTypeProperty(structuralType, local));
                }

                if (newMember == null)
                {
                    // Property does not have one of the following attributes:
                    //     EdmScalarPropertyAttribute, EdmComplexPropertyAttribute, EdmRelationshipNavigationPropertyAttribute
                    // This means its an unmapped property and can be ignored.
                    // Or there were error encountered while loading the properties
                    continue;
                }

                // Add the property object to the type
                structuralType.AddMember(newMember);

                // Add to the entity's collection of key members
                // Do this here instead of in the if condition above for scalar properties because
                // we want to make sure the AddMember call above did not fail before updating the key members
                if (Helper.IsEntityType(structuralType) && isEntityKeyProperty)
                {
                    ((EntityType)structuralType).AddKeyMember(newMember);
                }
            }
        }
        /// <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;

            EdmTypeAttribute[] 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(System.Data.Entity.Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly.FullName), null));
                    return;
                }
                EdmTypeAttribute typeAttribute  = typeAttributes[0];
                string           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, edmType));
                    return;
                }

                string 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),
                                edmType));

                        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;
        }
Beispiel #11
0
 /// <summary>
 /// determines if type is an EntityType
 /// </summary>
 /// <param name="type"></param>
 /// <returns></returns>
 internal static bool IsEntityType(TypeUsage type)
 {
     return(Helper.IsEntityType(type.EdmType));
 }
        private static bool LoadAssemblyFromCache(ObjectItemCollection objectItemCollection, Assembly assembly,
                                                  bool loadReferencedAssemblies, EdmItemCollection edmItemCollection, Action <String> 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 <string, EdmType> typesInLoading;
                List <EdmItemError>          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 <GlobalItem> globalItems = new List <GlobalItem>();
                    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);
                            }
                            else if (Helper.IsEnumType(edmType))
                            {
                                cspaceTypeName = ((ClrEnumType)edmType).CSpaceTypeName;
                                objectItemCollection._ocMapping.Add(cspaceTypeName, edmType);
                            }
                            // for the rest of the types like a relationship type, we do not have oc mapping,
                            // so we don't 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);
            }
        }
Beispiel #13
0
 internal static bool IsEntityTypeBase(EdmType edmType)
 {
     return(Helper.IsEntityType(edmType) ||
            Helper.IsRelationshipType(edmType));
 }