/// <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); }
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); } } } } }
internal EntityProxyTypeInfo(Type proxyType, ClrEntityType ospaceEntityType, DynamicMethod initializeCollections, List<PropertyInfo> baseGetters, List<PropertyInfo> baseSetters) { Debug.Assert(proxyType != null, "proxyType must be non-null"); _proxyType = proxyType; _entityType = ospaceEntityType; _initializeCollections = initializeCollections; _navigationPropertyAssociationTypes = new Dictionary<Tuple<string, string>, AssociationType>(); foreach (NavigationProperty navigationProperty in ospaceEntityType.NavigationProperties) { _navigationPropertyAssociationTypes.Add( new Tuple<string, string>( navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name), (AssociationType)navigationProperty.RelationshipType); if (navigationProperty.RelationshipType.Name != navigationProperty.RelationshipType.FullName) { // Sometimes there isn't enough metadata to have a container name // Default codegen doesn't qualify names _navigationPropertyAssociationTypes.Add( new Tuple<string, string>( navigationProperty.RelationshipType.Name, navigationProperty.ToEndMember.Name), (AssociationType)navigationProperty.RelationshipType); } } FieldInfo entityWrapperField = proxyType.GetField(EntityWrapperFieldName, BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); ParameterExpression Object_Parameter = Expression.Parameter(typeof(object), "proxy"); ParameterExpression Value_Parameter = Expression.Parameter(typeof(object), "value"); Debug.Assert(entityWrapperField != null, "entityWrapperField does not exist"); // Create the Wrapper Getter Expression<Func<object, object>> lambda = Expression.Lambda<Func<object, object>>( Expression.Field( Expression.Convert(Object_Parameter, entityWrapperField.DeclaringType), entityWrapperField), Object_Parameter); Func<object, object> 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. IEntityWrapper wrapper = ((IEntityWrapper)getEntityWrapperDelegate(proxy)); if (wrapper != null && !object.ReferenceEquals(wrapper.Entity, proxy)) { throw new InvalidOperationException(System.Data.Entity.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(); ParameterExpression PropertyName_Parameter = Expression.Parameter(typeof(string), "propertyName"); MethodInfo baseGetterMethod = proxyType.GetMethod("GetBasePropertyValue", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { 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(); } ParameterExpression PropertyValue_Parameter = Expression.Parameter(typeof(object), "propertyName"); MethodInfo baseSetterMethod = proxyType.GetMethod("SetBasePropertyValue", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { 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 = LightweightCodeGenerator.CreateConstructor(proxyType) as Func<object>; }
public void ValidateType(ClrEntityType ospaceEntityType) { if (ospaceEntityType != _entityType && ospaceEntityType.HashedDescription != _entityType.HashedDescription) { Debug.Assert(ospaceEntityType.ClrType == _entityType.ClrType); throw EntityUtil.DuplicateTypeForProxyType(ospaceEntityType.ClrType); } }
/// <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; }
public ProxyTypeBuilder(ClrEntityType ospaceEntityType) { _ospaceEntityType = ospaceEntityType; _baseImplementor = new BaseProxyImplementor(); _ipocoImplementor = new IPOCOImplementor(ospaceEntityType); _lazyLoadImplementor = new LazyLoadImplementor(ospaceEntityType); _dataContractImplementor = new DataContractImplementor(ospaceEntityType); _iserializableImplementor = new ISerializableImplementor(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) { Debug.Assert(s_TypeMapLock.IsUpgradeableReadLockHeld, "EntityProxyTypeInfo.BuildType method was called without first acquiring an upgradeable read lock from s_TypeMapLock."); EntityProxyTypeInfo proxyTypeInfo; ProxyTypeBuilder proxyTypeBuilder = new ProxyTypeBuilder(ospaceEntityType); Type 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. Assembly typeAssembly = proxyType.Assembly; if (!ProxyRuntimeAssemblies.Contains(typeAssembly)) { ProxyRuntimeAssemblies.Add(typeAssembly); AddAssemblyToResolveList(typeAssembly); } proxyTypeInfo = new EntityProxyTypeInfo(proxyType, ospaceEntityType, proxyTypeBuilder.CreateInitalizeCollectionMethod(proxyType), proxyTypeBuilder.BaseGetters, proxyTypeBuilder.BaseSetters); foreach (EdmMember member in proxyTypeBuilder.LazyLoadMembers) { InterceptMember(member, proxyType, proxyTypeInfo); } SetResetFKSetterFlagDelegate(proxyType, proxyTypeInfo); SetCompareByteArraysDelegate(proxyType, proxyTypeInfo); } 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) { Debug.Assert(ospaceEntityType != null, "ospaceEntityType must be non-null"); 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. s_TypeMapLock.EnterUpgradeableReadLock(); try { return TryCreateProxyType(ospaceEntityType); } finally { s_TypeMapLock.ExitUpgradeableReadLock(); } }
/// <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> /// 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; }
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)); } }