Beispiel #1
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);
                        }
                    }
                }
            }
        }
Beispiel #2
0
        protected override void LoadTypesFromAssembly()
        {
            foreach (Type type in EntityUtil.GetTypesSpecial(SourceAssembly))
            {
                EdmType cspaceType;
                if (TryGetCSpaceTypeMatch(type, out cspaceType))
                {
                    if (type.IsValueType && !type.IsEnum)
                    {
                        SessionData.LoadMessageLogger.LogLoadMessage(Strings.Validator_OSpace_Convention_Struct(cspaceType.FullName, type.FullName), cspaceType);
                        continue;
                    }

                    EdmType ospaceType;
                    if (TryCreateType(type, cspaceType, out ospaceType))
                    {
                        Debug.Assert(ospaceType is StructuralType || Helper.IsEnumType(ospaceType), "Only StructuralType or EnumType expected.");

                        CacheEntry.TypesInAssembly.Add(ospaceType);
                        // check for duplicates so we don't cause an ArgumentException,
                        // Mapping will do the actual error for the duplicate type later
                        if (!SessionData.CspaceToOspace.ContainsKey(cspaceType))
                        {
                            SessionData.CspaceToOspace.Add(cspaceType, ospaceType);
                        }
                        else
                        {
                            // at this point there is already a Clr Type that is structurally matched to this CSpace type, we throw exception
                            EdmType previousOSpaceType = SessionData.CspaceToOspace[cspaceType];
                            SessionData.EdmItemErrors.Add(
                                new EdmItemError(Strings.Validator_OSpace_Convention_AmbiguousClrType(cspaceType.Name, previousOSpaceType.ClrType.FullName, type.FullName), previousOSpaceType));
                        }
                    }
                }
            }

            if (SessionData.TypesInLoading.Count == 0)
            {
                Debug.Assert(CacheEntry.ClosureAssemblies.Count == 0, "How did we get closure assemblies?");

                // since we didn't find any types, don't lock into convention based
                SessionData.ObjectItemAssemblyLoaderFactory = null;
            }
        }
        /// <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 #4
0
        /// <summary>
        /// Verifies whether enum members of CLR and EDM types match.
        /// </summary>
        /// <param name="enumType">OSpace CLR enum type.</param>
        /// <param name="cspaceEnumType">CSpace EDM enum type.</param>
        /// <returns><c>true</c> if members match. <c>false</c> otherwise.</returns>
        private bool EnumMembersMatch(Type enumType, EnumType cspaceEnumType)
        {
            Debug.Assert(enumType != null, "enumType != null");
            Debug.Assert(enumType.IsEnum, "expected enum OSpace type");
            Debug.Assert(cspaceEnumType != null, "cspaceEnumType != null");
            Debug.Assert(Helper.IsEnumType(cspaceEnumType), "Enum type expected");
            Debug.Assert(cspaceEnumType.UnderlyingType.ClrEquivalentType == enumType.GetEnumUnderlyingType(), "underlying types should have already been checked");

            var enumUnderlyingType = enumType.GetEnumUnderlyingType();

            var cspaceSortedEnumMemberEnumerator      = cspaceEnumType.Members.OrderBy(m => m.Name).GetEnumerator();
            var ospaceSortedEnumMemberNamesEnumerator = enumType.GetEnumNames().OrderBy(n => n).GetEnumerator();

            // no checks required if edm enum type does not have any members
            if (!cspaceSortedEnumMemberEnumerator.MoveNext())
            {
                return(true);
            }

            while (ospaceSortedEnumMemberNamesEnumerator.MoveNext())
            {
                if (cspaceSortedEnumMemberEnumerator.Current.Name == ospaceSortedEnumMemberNamesEnumerator.Current &&
                    cspaceSortedEnumMemberEnumerator.Current.Value.Equals(
                        Convert.ChangeType(
                            Enum.Parse(enumType, ospaceSortedEnumMemberNamesEnumerator.Current), enumUnderlyingType, CultureInfo.InvariantCulture)))
                {
                    if (!cspaceSortedEnumMemberEnumerator.MoveNext())
                    {
                        return(true);
                    }
                }
            }

            SessionData.LoadMessageLogger.LogLoadMessage(
                System.Data.Entity.Strings.Mapping_Enum_OCMapping_MemberMismatch(
                    enumType.FullName,
                    cspaceSortedEnumMemberEnumerator.Current.Name,
                    cspaceSortedEnumMemberEnumerator.Current.Value,
                    cspaceEnumType.FullName), cspaceEnumType);

            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Validates whether cspace and sspace types are compatible.
        /// </summary>
        /// <param name="cspaceType">Type in C-Space. Must be a primitive or enumeration type.</param>
        /// <param name="storeType">C-Space equivalent of S-space Type. Must be a primitive type.</param>
        /// <returns>
        /// <c>true</c> if the types are compatible. <c>false</c> otherwise.
        /// </returns>
        /// <remarks>
        /// This methods validate whether cspace and sspace types are compatible. The types are
        /// compatible if:
        /// both are primitive and the cspace type is a subtype of sspace type
        /// or
        /// cspace type is an enumeration type whose underlying type is a subtype of sspace type.
        /// </remarks>
        private static bool ValidateScalarTypesAreCompatible(TypeUsage cspaceType, TypeUsage storeType)
        {
            Debug.Assert(cspaceType != null, "cspaceType != null");
            Debug.Assert(storeType != null, "storeType != null");
            Debug.Assert(cspaceType.EdmType.DataSpace == DataSpace.CSpace, "cspace property must have a cspace type");
            Debug.Assert(storeType.EdmType.DataSpace == DataSpace.CSpace, "storeType type usage must have a sspace type");
            Debug.Assert(
                Helper.IsScalarType(cspaceType.EdmType),
                "cspace property must be of a primitive or enumeration type");
            Debug.Assert(Helper.IsPrimitiveType(storeType.EdmType), "storeType property must be a primitive type");

            if (Helper.IsEnumType(cspaceType.EdmType))
            {
                // For enum cspace type check whether its underlying type is a subtype of the store type. Note that
                // TypeSemantics.IsSubTypeOf uses only TypeUsage.EdmType for primitive types so there is no need to copy facets
                // from the enum type property to the underlying type TypeUsage created here since they wouldn't be used anyways.
                return(TypeSemantics.IsSubTypeOf(TypeUsage.Create(Helper.GetUnderlyingEdmTypeForEnumType(cspaceType.EdmType)), storeType));
            }

            return(TypeSemantics.IsSubTypeOf(cspaceType, storeType));
        }
Beispiel #6
0
        /// <summary>
        /// Creates new enum OSpace type built based on CLR <paramref name="enumType"/> and <paramref name="cspaceEnumType"/>
        /// </summary>
        /// <param name="enumType">CLR type to create OSpace type from.</param>
        /// <param name="cspaceEnumType">CSpace type used to get namespace and name for the newly created OSpace type.</param>
        /// <param name="newOSpaceType">
        /// New enum OSpace type built based on CLR <paramref name="enumType"/> and <paramref name="cspaceEnumType"/> or null
        /// if the type could not be built.
        /// </param>
        /// <returns><c>true</c> if the type was built successfully.<c>false</c> otherwise.</returns>
        private bool TryCreateEnumType(Type enumType, EnumType cspaceEnumType, out EdmType newOSpaceType)
        {
            Debug.Assert(enumType != null, "enumType != null");
            Debug.Assert(enumType.IsEnum, "enum type expected");
            Debug.Assert(cspaceEnumType != null, "cspaceEnumType != null");
            Debug.Assert(Helper.IsEnumType(cspaceEnumType), "Enum type expected");
            Debug.Assert(TypesMatchByConvention(enumType, cspaceEnumType), "The types passed as parameters don't match by convention.");

            newOSpaceType = null;

            // Check if the OSpace and CSpace enum type match
            if (!UnderlyingEnumTypesMatch(enumType, cspaceEnumType) || !EnumMembersMatch(enumType, cspaceEnumType))
            {
                return(false);
            }

            newOSpaceType = new ClrEnumType(enumType, cspaceEnumType.NamespaceName, cspaceEnumType.Name);
            SessionData.TypesInLoading.Add(enumType.FullName, newOSpaceType);

            return(true);
        }
        /// <summary>
        /// Resolves enum type property.
        /// </summary>
        /// <param name="declaringType">The type to add the declared property to.</param>
        /// <param name="clrProperty">Property to resolve.</param>
        private void ResolveEnumTypeProperty(StructuralType declaringType, PropertyInfo clrProperty)
        {
            Debug.Assert(declaringType != null, "type != null");
            Debug.Assert(clrProperty != null, "clrProperty != null");
            Debug.Assert(
                (Nullable.GetUnderlyingType(clrProperty.PropertyType) ?? clrProperty.PropertyType).IsEnum,
                "This method should be called for enums only");

            EdmType propertyType;

            if (!TryGetLoadedType(clrProperty.PropertyType, out propertyType) || !Helper.IsEnumType(propertyType))
            {
                SessionData.EdmItemErrors.Add(
                    new EdmItemError(
                        System.Data.Entity.Strings.Validator_OSpace_ScalarPropertyNotPrimitive(
                            clrProperty.Name,
                            clrProperty.DeclaringType.FullName,
                            clrProperty.PropertyType.FullName), null));
            }
            else
            {
                var edmScalarPropertyAttribute = (EdmScalarPropertyAttribute)clrProperty.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Single();

                EdmProperty enumProperty = new EdmProperty(
                    clrProperty.Name,
                    TypeUsage.Create(propertyType, new FacetValues()
                {
                    Nullable = edmScalarPropertyAttribute.IsNullable
                }),
                    clrProperty,
                    declaringType.ClrType.TypeHandle);

                declaringType.AddMember(enumProperty);

                if (declaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType && edmScalarPropertyAttribute.EntityKeyProperty)
                {
                    ((EntityType)declaringType).AddKeyMember(enumProperty);
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// determines if <paramref name="type"/> is primitive or enumeration type
        /// </summary>
        /// <param name="type">Type to verify.</param>
        /// <returns><c>true</c> if <paramref name="type"/> is primitive or enumeration type. <c>false</c> otherwise.</returns>
        internal static bool IsScalarType(EdmType type)
        {
            Debug.Assert(type != null, "type != null");

            return(Helper.IsPrimitiveType(type) || Helper.IsEnumType(type));
        }
Beispiel #9
0
        /// <summary>
        /// determines if type is of EnumerationType.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        internal static bool IsEnumerationType(TypeUsage type)
        {
            Debug.Assert(type != null, "type != null");

            return(Helper.IsEnumType(type.EdmType));
        }
Beispiel #10
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>
        /// 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));
        }
        /// <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);
        }
        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 #14
0
        private bool TryFindAndCreateEnumProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List <Action> referenceResolutionListForCurrentType)
        {
            var typeClosureToTrack = new List <KeyValuePair <EdmProperty, PropertyInfo> >();

            foreach (EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers <EdmProperty>().Where(p => Helper.IsEnumType(p.TypeUsage.EdmType)))
            {
                PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty));
                if (clrProperty != null)
                {
                    typeClosureToTrack.Add(new KeyValuePair <EdmProperty, PropertyInfo>(cspaceProperty, clrProperty));
                }
                else
                {
                    string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName);
                    SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
                    return(false);
                }
            }

            foreach (var typeToTrack in typeClosureToTrack)
            {
                TrackClosure(typeToTrack.Value.PropertyType);
                // prevent the lifting of these closure variables
                var ot   = ospaceType;
                var cp   = typeToTrack.Key;
                var clrp = typeToTrack.Value;
                referenceResolutionListForCurrentType.Add(() => CreateAndAddEnumProperty(type, ot, cp, clrp));
            }

            return(true);
        }