/// <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); }
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); }
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; }