/// <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 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); } }
/// <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)); }
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); }
/// <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; }
/// <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); } }
internal static bool IsEntityTypeBase(EdmType edmType) { return(Helper.IsEntityType(edmType) || Helper.IsRelationshipType(edmType)); }