From 1302415d9e14502047a6b66286e053f0af3da916 Mon Sep 17 00:00:00 2001 From: maca88 Date: Mon, 24 Dec 2018 02:37:27 +0100 Subject: [PATCH 1/7] Port Hibernate's BytecodeEnhancementMetadata --- .../Default/DefaultMergeEventListener.cs | 2 +- .../Entity/AbstractEntityPersister.cs | 1 + .../Bytecode/IBytecodeEnhancementMetadata.cs | 62 ++++++ .../Bytecode/LazyPropertiesMetadata.cs | 69 ++++++ .../Bytecode/LazyPropertyDescriptor.cs | 69 ++++++ .../Bytecode/NotInstrumentedException.cs | 25 +++ src/NHibernate/Engine/EntityEntry.cs | 8 +- .../Default/AbstractSaveEventListener.cs | 2 +- .../Default/DefaultMergeEventListener.cs | 8 +- src/NHibernate/Impl/SessionImpl.cs | 5 +- .../Intercept/FieldInterceptionHelper.cs | 6 +- .../Entity/AbstractEntityPersister.cs | 36 +--- .../Persister/Entity/IEntityPersister.cs | 47 ++++- .../BytecodeEnhancementMetadataNonPocoImpl.cs | 60 ++++++ .../BytecodeEnhancementMetadataPocoImpl.cs | 199 ++++++++++++++++++ .../Tuple/Entity/EntityMetamodel.cs | 18 +- .../Tuple/Entity/IEntityTuplizer.cs | 19 -- .../Tuple/Entity/PocoEntityTuplizer.cs | 39 +--- 18 files changed, 579 insertions(+), 96 deletions(-) create mode 100644 src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs create mode 100644 src/NHibernate/Bytecode/LazyPropertiesMetadata.cs create mode 100644 src/NHibernate/Bytecode/LazyPropertyDescriptor.cs create mode 100644 src/NHibernate/Bytecode/NotInstrumentedException.cs create mode 100644 src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs create mode 100644 src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs diff --git a/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs index 40848b4f356..9384b786b79 100644 --- a/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs @@ -389,7 +389,7 @@ protected virtual async Task EntityIsDetachedAsync(MergeEvent @event, IDictionar await (CopyValuesAsync(persister, entity, target, source, copyCache, cancellationToken)).ConfigureAwait(false); //copyValues works by reflection, so explicitly mark the entity instance dirty - MarkInterceptorDirty(entity, target); + MarkInterceptorDirty(entity, persister, target); @event.Result = result; } diff --git a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs index d2d0a5e3361..ae54caf3fcb 100644 --- a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs @@ -36,6 +36,7 @@ using Property=NHibernate.Mapping.Property; using NHibernate.SqlTypes; using System.Linq; +using NHibernate.Bytecode; namespace NHibernate.Persister.Entity { diff --git a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs new file mode 100644 index 00000000000..b86cdc3a8e7 --- /dev/null +++ b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NHibernate.Engine; +using NHibernate.Intercept; +using NHibernate.Tuple.Entity; + +namespace NHibernate.Bytecode +{ + /// + /// Encapsulates bytecode enhancement information about a particular entity. + /// + /// Author: Steve Ebersole + /// + public interface IBytecodeEnhancementMetadata + { + /// + /// The name of the entity to which this metadata applies. + /// + string EntityName { get; } + + /// + /// Has the entity class been bytecode enhanced for lazy loading? + /// + bool EnhancedForLazyLoading { get; } + + LazyPropertiesMetadata LazyPropertiesMetadata { get; } + + /// + /// Build and inject an interceptor instance into the enhanced entity. + /// + /// The entity into which built interceptor should be injected. + /// Whether all lazy properties were unfetched or not. + /// The session to which the entity instance belongs. + /// The built and injected interceptor. + // TODO: Remove lazyPropertiesAreUnfetched when interceptor will be injected on entity instantiation + IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session); + + /// + /// Extract the field interceptor instance from the enhanced entity. + /// + /// The entity from which to extract the interceptor. + /// The extracted interceptor. + IFieldInterceptor ExtractInterceptor(object entity); + + /// + /// Retrieve the uninitialized lazy properties from the enhanced entity. + /// + /// The entity from which to retrieve the uninitialized lazy properties. + /// + ISet GetUninitializedLazyProperties(object entity); + + /// + /// Retrieve the uninitialized lazy properties from the entity state. + /// + /// The entity state from which to retrieve the uninitialized lazy properties. + /// + ISet GetUninitializedLazyProperties(object[] entityState); + } +} diff --git a/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs b/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs new file mode 100644 index 00000000000..c1d42b7213d --- /dev/null +++ b/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Iesi.Collections.Generic; +using NHibernate.Util; + +namespace NHibernate.Bytecode +{ + /// + /// Information about all of the bytecode lazy properties for an entity + /// + /// Author: Steve Ebersole + /// + [Serializable] + public class LazyPropertiesMetadata + { + public static LazyPropertiesMetadata NonEnhanced(string entityName) + { + return new LazyPropertiesMetadata(entityName, null, null); + } + + public static LazyPropertiesMetadata From( + string entityName, + IEnumerable lazyPropertyDescriptors, + ISet unwrapProxyPropertyNames) + { + // TODO: port lazy fetch groups + return new LazyPropertiesMetadata( + entityName, + lazyPropertyDescriptors.ToDictionary(o => o.Name), + unwrapProxyPropertyNames); + } + + private readonly IDictionary _lazyPropertyDescriptors; + + public LazyPropertiesMetadata( + string entityName, + IDictionary lazyPropertyDescriptors, + ISet unwrapProxyPropertyNames) + { + EntityName = entityName; + _lazyPropertyDescriptors = lazyPropertyDescriptors; + HasLazyProperties = _lazyPropertyDescriptors?.Count > 0; + LazyPropertyNames = HasLazyProperties + ? new ReadOnlySet(new HashSet(_lazyPropertyDescriptors.Keys)) + : CollectionHelper.EmptySet(); + HasUnwrapProxyProperties = unwrapProxyPropertyNames?.Count > 0; + UnwrapProxyPropertyNames = HasUnwrapProxyProperties + ? new ReadOnlySet(unwrapProxyPropertyNames) + : CollectionHelper.EmptySet(); + // TODO: port lazy fetch groups + } + + public string EntityName { get; } + + public bool HasLazyProperties { get; } + + public bool HasUnwrapProxyProperties { get; } + + public ISet LazyPropertyNames { get; } + + public ISet UnwrapProxyPropertyNames { get; } + + public IEnumerable LazyPropertyDescriptors => + _lazyPropertyDescriptors?.Values ?? Enumerable.Empty(); + } +} diff --git a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs new file mode 100644 index 00000000000..a7d657809f9 --- /dev/null +++ b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NHibernate.Type; + +namespace NHibernate.Bytecode +{ + /// + /// Descriptor for a property which is enabled for bytecode lazy fetching + /// + /// Author: Steve Ebersole + /// + public class LazyPropertyDescriptor + { + public static LazyPropertyDescriptor From( + Mapping.Property property, + int attributeIndex, + int lazyIndex) + { + // TODO: port lazy fetch groups + + return new LazyPropertyDescriptor( + attributeIndex, + lazyIndex, + property.Name, + property.Type + ); + } + + private LazyPropertyDescriptor( + int propertyIndex, + int lazyIndex, + string name, + IType type) + { + if (propertyIndex < lazyIndex) + { + throw new InvalidOperationException("Property index is lower than the lazy index."); + } + + PropertyIndex = propertyIndex; + LazyIndex = lazyIndex; + Name = name; + Type = type; + } + + /// + /// Access to the index of the property in terms of its position in the entity persister + /// + public int PropertyIndex { get; } + + /// + /// Access to the index of the property in terms of its position within the lazy properties of the persister + /// + public int LazyIndex { get; } + + /// + /// Access to the name of the property + /// + public string Name { get; } + + /// + /// Access to the property's type + /// + public IType Type { get; set; } + } +} diff --git a/src/NHibernate/Bytecode/NotInstrumentedException.cs b/src/NHibernate/Bytecode/NotInstrumentedException.cs new file mode 100644 index 00000000000..d946d20b58b --- /dev/null +++ b/src/NHibernate/Bytecode/NotInstrumentedException.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHibernate.Bytecode +{ + /// + /// Indicates a condition where an instrumented/enhanced class was expected, but the class was not + /// instrumented/enhanced. + /// + /// Author: Steve Ebersole + /// + public class NotInstrumentedException : HibernateException + { + /// + /// Constructs a NotInstrumentedException. + /// + /// Message explaining the exception condition. + public NotInstrumentedException(string message) : base(message) + { + } + } +} diff --git a/src/NHibernate/Engine/EntityEntry.cs b/src/NHibernate/Engine/EntityEntry.cs index aceb9894457..ec7f93523cb 100644 --- a/src/NHibernate/Engine/EntityEntry.cs +++ b/src/NHibernate/Engine/EntityEntry.cs @@ -233,7 +233,11 @@ public void PostUpdate(object entity, object[] updatedState, object nextVersion) version = nextVersion; Persister.SetPropertyValue(entity, Persister.VersionProperty, nextVersion); } - FieldInterceptionHelper.ClearDirty(entity); + + if (Persister.IsInstrumented) + { + persister.ExtractFieldInterceptor(entity)?.ClearDirty(); + } } /// @@ -265,7 +269,7 @@ public bool RequiresDirtyCheck(object entity) return IsModifiableEntity() && (Persister.HasMutableProperties || !FieldInterceptionHelper.IsInstrumented(entity) - || FieldInterceptionHelper.ExtractFieldInterceptor(entity).IsDirty); + || Persister.ExtractFieldInterceptor(entity).IsDirty); } /// diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index 63e94980222..cc8cf1183b3 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -301,7 +301,7 @@ private void MarkInterceptorDirty(object entity, IEntityPersister persister, IEv { if (FieldInterceptionHelper.IsInstrumented(entity)) { - IFieldInterceptor interceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, persister.EntityName, persister.MappedClass, null, null, source); + var interceptor = persister.InjectFieldInterceptor(entity, null, null, source); interceptor.MarkDirty(); } } diff --git a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs index b304bd16512..af57acfd44b 100644 --- a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs @@ -380,7 +380,7 @@ protected virtual void EntityIsDetached(MergeEvent @event, IDictionary copyCache CopyValues(persister, entity, target, source, copyCache); //copyValues works by reflection, so explicitly mark the entity instance dirty - MarkInterceptorDirty(entity, target); + MarkInterceptorDirty(entity, persister, target); @event.Result = result; } @@ -400,11 +400,11 @@ protected virtual bool InvokeUpdateLifecycle(object entity, IEntityPersister per return false; } - private void MarkInterceptorDirty(object entity, object target) + private void MarkInterceptorDirty(object entity, IEntityPersister persister, object target) { - if (FieldInterceptionHelper.IsInstrumented(entity)) + if (persister.IsInstrumented) { - IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(target); + var interceptor = persister.ExtractFieldInterceptor(target); if (interceptor != null) { interceptor.MarkDirty(); diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index 3e999ddd9df..a94ef0c20f8 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -958,10 +958,11 @@ public override string BestGuessEntityName(object entity) } entity = initializer.GetImplementation(); } - if (FieldInterceptionHelper.IsInstrumented(entity)) + + var interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); + if (interceptor != null) { // NH: support of field-interceptor-proxy - IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); return interceptor.EntityName; } EntityEntry entry = persistenceContext.GetEntry(entity); diff --git a/src/NHibernate/Intercept/FieldInterceptionHelper.cs b/src/NHibernate/Intercept/FieldInterceptionHelper.cs index a1ad727b9d9..33a65db1744 100644 --- a/src/NHibernate/Intercept/FieldInterceptionHelper.cs +++ b/src/NHibernate/Intercept/FieldInterceptionHelper.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NHibernate.Engine; @@ -32,6 +33,7 @@ public static IFieldInterceptor ExtractFieldInterceptor(object entity) return fieldInterceptorAccessor == null ? null : fieldInterceptorAccessor.FieldInterceptor; } + [Obsolete("Use IBytecodeEnhancementMetadata.InjectInterceptor method instead")] public static IFieldInterceptor InjectFieldInterceptor(object entity, string entityName, System.Type mappedClass, ISet uninitializedFieldNames, @@ -48,6 +50,7 @@ public static IFieldInterceptor InjectFieldInterceptor(object entity, string ent return null; } + [Obsolete("This method has no more usages and will be removed in a future version")] public static void ClearDirty(object entity) { IFieldInterceptor interceptor = ExtractFieldInterceptor(entity); @@ -57,6 +60,7 @@ public static void ClearDirty(object entity) } } + [Obsolete("This method has no more usages and will be removed in a future version")] public static void MarkDirty(object entity) { IFieldInterceptor interceptor = ExtractFieldInterceptor(entity); @@ -66,4 +70,4 @@ public static void MarkDirty(object entity) } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index bb5d959f453..a9036da2152 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -26,6 +26,7 @@ using Property=NHibernate.Mapping.Property; using NHibernate.SqlTypes; using System.Linq; +using NHibernate.Bytecode; namespace NHibernate.Persister.Entity { @@ -683,6 +684,9 @@ public virtual string VersionColumnName get { return versionColumnName; } } + // 6.0 TODO: Add into IEntityPersister + public IBytecodeEnhancementMetadata InstrumentationMetadata => EntityMetamodel.BytecodeEnhancementMetadata; + [Obsolete("Please use RootTableName instead.")] protected internal string VersionedTableName { @@ -1281,7 +1285,7 @@ public virtual object InitializeLazyProperty(string fieldName, object entity, IS fieldName); } - var uninitializedLazyProperties = GetUninitializedLazyProperties(entity); + var uninitializedLazyProperties = InstrumentationMetadata.GetUninitializedLazyProperties(entity); if (HasCache && session.CacheMode.HasFlag(CacheMode.Get)) { CacheKey cacheKey = session.GenerateCacheKey(id, IdentifierType, EntityName); @@ -3220,7 +3224,7 @@ private bool HasDirtyLazyProperties(int[] dirtyFields, object obj) { // When having a dirty lazy property and the entity is not yet initialized we have to use a dynamic update for // it even if it is disabled in order to have it updated. - return GetUninitializedLazyProperties(obj).Count > 0 && dirtyFields.Any(i => PropertyLaziness[i]); + return InstrumentationMetadata.GetUninitializedLazyProperties(obj).Count > 0 && dirtyFields.Any(i => PropertyLaziness[i]); } public object Insert(object[] fields, object obj, ISessionImplementor session) @@ -3930,14 +3934,14 @@ public virtual void AfterReassociate(object entity, ISessionImplementor session) { if (FieldInterceptionHelper.IsInstrumented(entity)) { - IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); + var interceptor = EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(entity); if (interceptor != null) { interceptor.Session = session; } else { - IFieldInterceptor fieldInterceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, MappedClass, null, null, session); + var fieldInterceptor = EntityMetamodel.BytecodeEnhancementMetadata.InjectInterceptor(entity, false, session); fieldInterceptor.MarkDirty(); } } @@ -4107,30 +4111,6 @@ public void AfterInitialize(object entity, bool lazyPropertiesAreUnfetched, ISes EntityTuplizer.AfterInitialize(entity, lazyPropertiesAreUnfetched, session); } - internal ISet GetUninitializedLazyProperties(object entity) - { - return EntityTuplizer.GetUninitializedLazyProperties(entity) ?? new HashSet(lazyPropertyNames); - } - - internal ISet GetUninitializedLazyProperties(object[] state) - { - if (!HasLazyProperties) - { - return CollectionHelper.EmptySet(); - } - - var uninitializedProperties = new HashSet(); - for (var j = 0; j < lazyPropertyNames.Length; j++) - { - if (state[lazyPropertyNumbers[j]] == LazyPropertyInitializer.UnfetchedProperty) - { - uninitializedProperties.Add(lazyPropertyNames[j]); - } - } - - return uninitializedProperties; - } - public virtual bool[] PropertyUpdateability { get { return entityMetamodel.PropertyUpdateability; } diff --git a/src/NHibernate/Persister/Entity/IEntityPersister.cs b/src/NHibernate/Persister/Entity/IEntityPersister.cs index b757d8a7cf8..f93c8fa81b3 100644 --- a/src/NHibernate/Persister/Entity/IEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/IEntityPersister.cs @@ -624,12 +624,12 @@ public static int GetBatchSize(this IEntityPersister persister) return 1; } - //6.0 TODO: Merge into IEntityPersister + //6.0 TODO: Remove and replace usages with InstrumentationMetadata.GetUninitializedLazyProperties instead internal static ISet GetUninitializedLazyProperties(this IEntityPersister persister, object entity) { if (persister is AbstractEntityPersister abstractEntityPersister) { - return abstractEntityPersister.GetUninitializedLazyProperties(entity); + return abstractEntityPersister.InstrumentationMetadata.GetUninitializedLazyProperties(entity); } if (!persister.HasUninitializedLazyProperties(entity)) @@ -653,12 +653,12 @@ internal static ISet GetUninitializedLazyProperties(this IEntityPersiste /// /// Get uninitialized lazy properties from entity state /// - //6.0 TODO: Merge into IEntityPersister - public static ISet GetUninitializedLazyProperties(this IEntityPersister persister, object[] state) + //6.0 TODO: Remove and replace usages with InstrumentationMetadata.GetUninitializedLazyProperties instead + internal static ISet GetUninitializedLazyProperties(this IEntityPersister persister, object[] state) { if (persister is AbstractEntityPersister abstractEntityPersister) { - return abstractEntityPersister.GetUninitializedLazyProperties(state); + return abstractEntityPersister.InstrumentationMetadata.GetUninitializedLazyProperties(state); } if (!persister.HasLazyProperties) @@ -677,5 +677,42 @@ public static ISet GetUninitializedLazyProperties(this IEntityPersister return result; } + + //6.0 TODO: Remove and replace usages with InstrumentationMetadata.InjectInterceptor instead + internal static IFieldInterceptor InjectFieldInterceptor( + this IEntityPersister persister, + object entity, + ISet uninitializedFieldNames, + ISet unwrapProxyFieldNames, + ISessionImplementor session) + { + if (persister is AbstractEntityPersister abstractEntityPersister) + { + return abstractEntityPersister.InstrumentationMetadata.InjectInterceptor(entity, uninitializedFieldNames?.Count > 0, session); + } + +#pragma warning disable CS0618 + return FieldInterceptionHelper.InjectFieldInterceptor( + entity, + persister.EntityName, + persister.MappedClass, + uninitializedFieldNames, + unwrapProxyFieldNames, + session); +#pragma warning restore CS0618 + } + + //6.0 TODO: Remove and replace usages with InstrumentationMetadata.ExtractInterceptor instead + internal static IFieldInterceptor ExtractFieldInterceptor(this IEntityPersister persister, object entity) + { + if (persister is AbstractEntityPersister abstractEntityPersister) + { + return abstractEntityPersister.InstrumentationMetadata.ExtractInterceptor(entity); + } + +#pragma warning disable CS0618 + return FieldInterceptionHelper.ExtractFieldInterceptor(entity); +#pragma warning restore CS0618 + } } } diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs new file mode 100644 index 00000000000..88cdb0154c8 --- /dev/null +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NHibernate.Bytecode; +using NHibernate.Engine; +using NHibernate.Intercept; +using NHibernate.Util; + +namespace NHibernate.Tuple.Entity +{ + /// + /// Author: Steve Ebersole + /// + public class BytecodeEnhancementMetadataNonPocoImpl : IBytecodeEnhancementMetadata + { + private readonly string _errorMessage; + + public BytecodeEnhancementMetadataNonPocoImpl(string entityName) + { + EntityName = entityName; + LazyPropertiesMetadata = LazyPropertiesMetadata.NonEnhanced(entityName); + _errorMessage= $"Entity [{entityName}] is non-poco, and therefore not instrumented"; + } + + /// + public string EntityName { get; } + + /// + public bool EnhancedForLazyLoading => false; + + /// + public LazyPropertiesMetadata LazyPropertiesMetadata { get; } + + /// + public IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session) + { + throw new NotInstrumentedException(_errorMessage); + } + + /// + public IFieldInterceptor ExtractInterceptor(object entity) + { + throw new NotInstrumentedException(_errorMessage); + } + + /// + public ISet GetUninitializedLazyProperties(object entity) + { + return CollectionHelper.EmptySet(); + } + + /// + public ISet GetUninitializedLazyProperties(object[] entityState) + { + return CollectionHelper.EmptySet(); + } + } +} diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs new file mode 100644 index 00000000000..28a093b2afb --- /dev/null +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using NHibernate.Bytecode; +using NHibernate.Engine; +using NHibernate.Intercept; +using NHibernate.Mapping; +using NHibernate.Util; + +namespace NHibernate.Tuple.Entity +{ + /// + /// Author: Steve Ebersole + /// + public class BytecodeEnhancementMetadataPocoImpl : IBytecodeEnhancementMetadata + { + private readonly System.Type _entityType; + + public static IBytecodeEnhancementMetadata From( + PersistentClass persistentClass, + ICollection lazyPropertyDescriptors, + ISet unwrapProxyPropertyNames) + { + var mappedClass = persistentClass.MappedClass; + var enhancedForLazyLoading = lazyPropertyDescriptors?.Count > 0 || unwrapProxyPropertyNames?.Count > 0; + + // We have to check all subclasses if any of them is enhanced for lazy loading as the + // root class will be enhanced when any of the subclasses is enhanced, even if it + // does not have any lazy properties. + // If we do not check the subclasses, where the root-entity has no lazy properties + // we will eager-load/double-load those properties (NH2488). + if (!enhancedForLazyLoading) + { + foreach (var persistentSubclass in persistentClass.SubclassClosureIterator) + { + enhancedForLazyLoading |= IsEnhancedForLazyLoading(persistentSubclass); + if (enhancedForLazyLoading) + { + break; + } + } + } + + var lazyAttributesMetadata = enhancedForLazyLoading + ? LazyPropertiesMetadata.From(persistentClass.EntityName, lazyPropertyDescriptors, unwrapProxyPropertyNames) + : LazyPropertiesMetadata.NonEnhanced(persistentClass.EntityName); + + return new BytecodeEnhancementMetadataPocoImpl( + persistentClass.EntityName, + mappedClass, + enhancedForLazyLoading, + lazyAttributesMetadata + ); + } + + /// + /// Check for a if is enhanced for lazy loading. + /// NOTE: The logic was taken from . + /// + /// The persistent class to check. + /// Whether the persistent class is enhanced for lazy loading or not. + private static bool IsEnhancedForLazyLoading(PersistentClass persistentClass) + { + var lazyAvailable = persistentClass.HasPocoRepresentation + && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); + + // NH: WARNING if we have to disable lazy/unproxy properties we have to do it in the whole process. + var lazy = persistentClass.IsLazy && (!persistentClass.HasPocoRepresentation || + !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); + lazyAvailable &= lazy; // <== Disable lazy properties if the class is marked with lazy=false + if (!lazyAvailable) + { + return false; + } + + foreach (var prop in persistentClass.PropertyIterator) + { + // NH: A lazy property is a simple property marked with lazy=true + var islazyProperty = prop.IsLazy && (!prop.IsEntityRelation || prop.UnwrapProxy); + // NH: A Relation (in this case many-to-one or one-to-one) marked as "no-proxy" + var isUnwrapProxy = prop.UnwrapProxy; + + if (islazyProperty || isUnwrapProxy) + { + return true; + } + } + + return false; + } + + public BytecodeEnhancementMetadataPocoImpl( + string entityName, + System.Type entityType, + bool enhancedForLazyLoading, + LazyPropertiesMetadata lazyPropertiesMetadata) + { + EntityName = entityName; + _entityType = entityType; + EnhancedForLazyLoading = enhancedForLazyLoading; + LazyPropertiesMetadata = lazyPropertiesMetadata; + } + + /// + public string EntityName { get; } + + /// + public bool EnhancedForLazyLoading { get; } + + /// + public LazyPropertiesMetadata LazyPropertiesMetadata { get; } + + /// + public IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session) + { + if (!EnhancedForLazyLoading) + { + throw new NotInstrumentedException($"Entity class [{_entityType}] is not enhanced for lazy loading"); + } + + if (!(entity is IFieldInterceptorAccessor fieldInterceptorAccessor)) + { + return null; // Can happen when a saved entity is refreshed within the same session NH2860 + } + + if (entity.GetType().BaseType != _entityType) + { + throw new ArgumentException( + $"Passed entity instance [{entity}] is not of expected type [{EntityName}]"); + } + + var fieldInterceptorImpl = new DefaultFieldInterceptor( + session, + LazyPropertiesMetadata.HasLazyProperties && lazyPropertiesAreUnfetched + ? new HashSet(LazyPropertiesMetadata.LazyPropertyNames) + : null, + LazyPropertiesMetadata.UnwrapProxyPropertyNames, + EntityName, + _entityType); + fieldInterceptorAccessor.FieldInterceptor = fieldInterceptorImpl; + + return fieldInterceptorImpl; + } + + /// + public IFieldInterceptor ExtractInterceptor(object entity) + { + if (!EnhancedForLazyLoading) + { + throw new NotInstrumentedException($"Entity class [{_entityType}] is not enhanced for lazy loading"); + } + + if (!(entity is IFieldInterceptorAccessor fieldInterceptorAccessor)) + { + return null; + } + + var interceptor = fieldInterceptorAccessor.FieldInterceptor; + if (interceptor == null) + { + return null; + } + + if (_entityType != interceptor.MappedClass) + { + throw new ArgumentException( + $"Passed entity instance [{entity}] is not of expected type [{EntityName}]"); + } + + return fieldInterceptorAccessor.FieldInterceptor; + } + + /// + public ISet GetUninitializedLazyProperties(object entity) + { + var interceptor = LazyPropertiesMetadata.HasLazyProperties ? ExtractInterceptor(entity) : null; + return interceptor?.GetUninitializedFields() ?? CollectionHelper.EmptySet(); + } + + /// + public ISet GetUninitializedLazyProperties(object[] entityState) + { + if (LazyPropertiesMetadata.HasLazyProperties) + { + return CollectionHelper.EmptySet(); + } + + var uninitializedProperties = new HashSet(); + foreach (var propertyDescriptor in LazyPropertiesMetadata.LazyPropertyDescriptors) + { + if (entityState[propertyDescriptor.PropertyIndex] == LazyPropertyInitializer.UnfetchedProperty) + { + uninitializedProperties.Add(propertyDescriptor.Name); + } + } + + return uninitializedProperties; + } + } +} diff --git a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs index 9f81571059b..da1a5f6cf37 100644 --- a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs +++ b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; - +using NHibernate.Bytecode; using NHibernate.Engine; using NHibernate.Intercept; using NHibernate.Mapping; @@ -103,6 +103,8 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement propertySpan = persistentClass.PropertyClosureSpan; properties = new StandardProperty[propertySpan]; List naturalIdNumbers = new List(); + var lazyPropertyDescriptors = new List(); + var unwrapProxyPropertyNames = new HashSet(); propertyNames = new string[propertySpan]; propertyTypes = new IType[propertySpan]; @@ -182,10 +184,12 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement if (islazyProperty) { hasLazy = true; + lazyPropertyDescriptors.Add(LazyPropertyDescriptor.From(prop, i, lazyPropertyDescriptors.Count)); } if (isUnwrapProxy) { hasUnwrapProxyForProperties = true; + unwrapProxyPropertyNames.Add(prop.Name); } propertyLaziness[i] = islazyProperty; @@ -316,6 +320,16 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement EntityMode = persistentClass.HasPocoRepresentation ? EntityMode.Poco : EntityMode.Map; + if (persistentClass.HasPocoRepresentation) + { + BytecodeEnhancementMetadata = BytecodeEnhancementMetadataPocoImpl + .From(persistentClass, lazyPropertyDescriptors, unwrapProxyPropertyNames); + } + else + { + BytecodeEnhancementMetadata = new BytecodeEnhancementMetadataNonPocoImpl(persistentClass.EntityName); + } + var entityTuplizerFactory = new EntityTuplizerFactory(); var tuplizerClassName = persistentClass.GetTuplizerImplClassName(EntityMode); Tuplizer = tuplizerClassName == null @@ -716,5 +730,7 @@ public int[] NaturalIdentifierProperties { get { return naturalIdPropertyNumbers; } } + + public IBytecodeEnhancementMetadata BytecodeEnhancementMetadata { get; } } } diff --git a/src/NHibernate/Tuple/Entity/IEntityTuplizer.cs b/src/NHibernate/Tuple/Entity/IEntityTuplizer.cs index 6f697e2c04d..397bdd595d6 100644 --- a/src/NHibernate/Tuple/Entity/IEntityTuplizer.cs +++ b/src/NHibernate/Tuple/Entity/IEntityTuplizer.cs @@ -119,23 +119,4 @@ public interface IEntityTuplizer : ITuplizer /// True if uninitialized lazy properties were found; false otherwise. bool HasUninitializedLazyProperties(object entity); } - - internal static class EntityTuplizerExtensions - { - //6.0 TODO: Merge into IEntityTuplizer - internal static ISet GetUninitializedLazyProperties(this IEntityTuplizer entityTuplizer, object entity) - { - if (entityTuplizer is AbstractEntityTuplizer abstractEntityTuplizer) - { - return abstractEntityTuplizer.GetUninitializedLazyProperties(entity); - } - - if (!entityTuplizer.HasUninitializedLazyProperties(entity)) - { - return CollectionHelper.EmptySet(); - } - - return null; // The caller should use all lazy properties as the result - } - } } diff --git a/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs b/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs index 2deb5f607ab..5dd46ce470a 100644 --- a/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs +++ b/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs @@ -24,8 +24,6 @@ public class PocoEntityTuplizer : AbstractEntityTuplizer private readonly System.Type proxyInterface; private readonly bool islifecycleImplementor; private readonly bool isValidatableImplementor; - private readonly HashSet lazyPropertyNames = new HashSet(); - private readonly HashSet unwrapProxyPropertyNames = new HashSet(); [NonSerialized] private IReflectionOptimizer optimizer; private readonly IProxyValidator proxyValidator; @@ -59,13 +57,6 @@ public PocoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappe islifecycleImplementor = typeof(ILifecycle).IsAssignableFrom(mappedClass); isValidatableImplementor = typeof(IValidatable).IsAssignableFrom(mappedClass); - foreach (Mapping.Property property in mappedEntity.PropertyClosureIterator) - { - if (property.IsLazy) - lazyPropertyNames.Add(property.Name); - if (property.UnwrapProxy) - unwrapProxyPropertyNames.Add(property.Name); - } SetReflectionOptimizer(); Instantiator = BuildInstantiator(mappedEntity); @@ -80,16 +71,7 @@ public override System.Type ConcreteProxyClass get { return proxyInterface; } } - public override bool IsInstrumented - { - get - { - // NH: we can't really check for EntityMetamodel.HasLazyProperties and/or EntityMetamodel.HasUnwrapProxyForProperties here - // because this property is used even where subclasses has lazy-properties. - // Checking it here, where the root-entity has no lazy properties we will eager-load/double-load those properties. - return FieldInterceptionHelper.IsInstrumented(MappedClass); - } - } + public override bool IsInstrumented => EntityMetamodel.BytecodeEnhancementMetadata.EnhancedForLazyLoading; public override System.Type MappedClass { @@ -111,12 +93,12 @@ protected override IInstantiator BuildInstantiator(PersistentClass persistentCla if (optimizer == null) { log.Debug("Create Instantiator without optimizer for:{0}", persistentClass.MappedClass.FullName); - return new PocoInstantiator(persistentClass, null, ProxyFactory, EntityMetamodel.HasLazyProperties || EntityMetamodel.HasUnwrapProxyForProperties); + return new PocoInstantiator(persistentClass, null, ProxyFactory, IsInstrumented); } else { log.Debug("Create Instantiator using optimizer for:{0}", persistentClass.MappedClass.FullName); - return new PocoInstantiator(persistentClass, optimizer.InstantiationOptimizer, ProxyFactory, EntityMetamodel.HasLazyProperties || EntityMetamodel.HasUnwrapProxyForProperties); + return new PocoInstantiator(persistentClass, optimizer.InstantiationOptimizer, ProxyFactory, IsInstrumented); } } @@ -229,10 +211,9 @@ protected virtual IProxyFactory BuildProxyFactoryInternal(PersistentClass @class public override void AfterInitialize(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session) { - if (IsInstrumented && (EntityMetamodel.HasLazyProperties || EntityMetamodel.HasUnwrapProxyForProperties)) + if (IsInstrumented) { - HashSet lazyProps = lazyPropertiesAreUnfetched && EntityMetamodel.HasLazyProperties ? new HashSet(lazyPropertyNames) : null; - FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, this.MappedClass ,lazyProps, unwrapProxyPropertyNames, session); + EntityMetamodel.BytecodeEnhancementMetadata.InjectInterceptor(entity, lazyPropertiesAreUnfetched, session); } } @@ -269,7 +250,7 @@ public override bool HasUninitializedLazyProperties(object entity) { if (EntityMetamodel.HasLazyProperties) { - IFieldInterceptor callback = FieldInterceptionHelper.ExtractFieldInterceptor(entity); + var callback = EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(entity); return callback != null && !callback.IsInitialized; } else @@ -285,13 +266,7 @@ internal override ISet GetUninitializedLazyProperties(object entity) return CollectionHelper.EmptySet(); } - var interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); - if (interceptor == null) - { - return CollectionHelper.EmptySet(); - } - - return interceptor.GetUninitializedFields() ?? lazyPropertyNames; + return EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(entity); } public override bool IsLifecycleImplementor From dfae76d739a60d00ad1978db80c5794acf3515b7 Mon Sep 17 00:00:00 2001 From: maca88 Date: Wed, 26 Dec 2018 18:28:30 +0100 Subject: [PATCH 2/7] Moved UnwrapProxyProperties into UnwrapProxyPropertiesMetadata --- .../Bytecode/IBytecodeEnhancementMetadata.cs | 8 +++ .../Bytecode/LazyPropertiesMetadata.cs | 19 ++---- .../Bytecode/LazyPropertyDescriptor.cs | 4 +- .../Bytecode/UnwrapProxyPropertiesMetadata.cs | 62 +++++++++++++++++++ .../Bytecode/UnwrapProxyPropertyDescriptor.cs | 51 +++++++++++++++ .../BytecodeEnhancementMetadataNonPocoImpl.cs | 6 +- .../BytecodeEnhancementMetadataPocoImpl.cs | 24 ++++--- .../Tuple/Entity/EntityMetamodel.cs | 6 +- 8 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs create mode 100644 src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs diff --git a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs index b86cdc3a8e7..d329ae613b7 100644 --- a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs +++ b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs @@ -26,8 +26,16 @@ public interface IBytecodeEnhancementMetadata /// bool EnhancedForLazyLoading { get; } + /// + /// Has the information about all lazy properties + /// LazyPropertiesMetadata LazyPropertiesMetadata { get; } + /// + /// Has the information about all properties mapped as proxy="no-proxy" + /// + UnwrapProxyPropertiesMetadata UnwrapProxyPropertiesMetadata { get; } + /// /// Build and inject an interceptor instance into the enhanced entity. /// diff --git a/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs b/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs index c1d42b7213d..ee70714e9b1 100644 --- a/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs +++ b/src/NHibernate/Bytecode/LazyPropertiesMetadata.cs @@ -18,27 +18,24 @@ public class LazyPropertiesMetadata { public static LazyPropertiesMetadata NonEnhanced(string entityName) { - return new LazyPropertiesMetadata(entityName, null, null); + return new LazyPropertiesMetadata(entityName, null); } public static LazyPropertiesMetadata From( string entityName, - IEnumerable lazyPropertyDescriptors, - ISet unwrapProxyPropertyNames) + IEnumerable lazyPropertyDescriptors) { // TODO: port lazy fetch groups return new LazyPropertiesMetadata( entityName, - lazyPropertyDescriptors.ToDictionary(o => o.Name), - unwrapProxyPropertyNames); + lazyPropertyDescriptors.ToDictionary(o => o.Name)); } private readonly IDictionary _lazyPropertyDescriptors; public LazyPropertiesMetadata( string entityName, - IDictionary lazyPropertyDescriptors, - ISet unwrapProxyPropertyNames) + IDictionary lazyPropertyDescriptors) { EntityName = entityName; _lazyPropertyDescriptors = lazyPropertyDescriptors; @@ -46,10 +43,6 @@ public LazyPropertiesMetadata( LazyPropertyNames = HasLazyProperties ? new ReadOnlySet(new HashSet(_lazyPropertyDescriptors.Keys)) : CollectionHelper.EmptySet(); - HasUnwrapProxyProperties = unwrapProxyPropertyNames?.Count > 0; - UnwrapProxyPropertyNames = HasUnwrapProxyProperties - ? new ReadOnlySet(unwrapProxyPropertyNames) - : CollectionHelper.EmptySet(); // TODO: port lazy fetch groups } @@ -57,12 +50,8 @@ public LazyPropertiesMetadata( public bool HasLazyProperties { get; } - public bool HasUnwrapProxyProperties { get; } - public ISet LazyPropertyNames { get; } - public ISet UnwrapProxyPropertyNames { get; } - public IEnumerable LazyPropertyDescriptors => _lazyPropertyDescriptors?.Values ?? Enumerable.Empty(); } diff --git a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs index a7d657809f9..23426c2aa1c 100644 --- a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs @@ -16,13 +16,13 @@ public class LazyPropertyDescriptor { public static LazyPropertyDescriptor From( Mapping.Property property, - int attributeIndex, + int propertyIndex, int lazyIndex) { // TODO: port lazy fetch groups return new LazyPropertyDescriptor( - attributeIndex, + propertyIndex, lazyIndex, property.Name, property.Type diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs new file mode 100644 index 00000000000..5d222ddeb21 --- /dev/null +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Iesi.Collections.Generic; +using NHibernate.Util; + +namespace NHibernate.Bytecode +{ + /// + /// Information about all properties mapped as proxy="no-proxy" for an entity + /// + public class UnwrapProxyPropertiesMetadata + { + public static UnwrapProxyPropertiesMetadata NonEnhanced(string entityName) + { + return new UnwrapProxyPropertiesMetadata(entityName, null); + } + + public static UnwrapProxyPropertiesMetadata From( + string entityName, + IEnumerable unwrapProxyPropertyDescriptors) + { + return new UnwrapProxyPropertiesMetadata( + entityName, + unwrapProxyPropertyDescriptors.ToDictionary(o => o.Name)); + } + + private readonly IDictionary _unwrapProxyPropertyDescriptors; + + public UnwrapProxyPropertiesMetadata( + string entityName, + IDictionary unwrapProxyPropertyDescriptors) + { + EntityName = entityName; + _unwrapProxyPropertyDescriptors = unwrapProxyPropertyDescriptors; + HasUnwrapProxyProperties = unwrapProxyPropertyDescriptors?.Count > 0; + UnwrapProxyPropertyNames = HasUnwrapProxyProperties + ? new ReadOnlySet(new HashSet(unwrapProxyPropertyDescriptors.Keys)) + : CollectionHelper.EmptySet(); + } + + public string EntityName { get; } + + public bool HasUnwrapProxyProperties { get; } + + public ISet UnwrapProxyPropertyNames { get; } + + public IEnumerable UnwrapProxyPropertyDescriptors => + _unwrapProxyPropertyDescriptors?.Values ?? Enumerable.Empty(); + + public int GetUnwrapProxyPropertyIndex(string propertyName) + { + if (!_unwrapProxyPropertyDescriptors.TryGetValue(propertyName, out var descriptor)) + { + throw new InvalidOperationException( + $"Property {propertyName} is not mapped as proxy=\"no-proxy\" on entity {EntityName}"); + } + + return descriptor.PropertyIndex; + } + } +} diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs new file mode 100644 index 00000000000..5058bf97e36 --- /dev/null +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NHibernate.Type; + +namespace NHibernate.Bytecode +{ + /// + /// Descriptor for a property which is mapped as proxy="no-proxy" + /// + public class UnwrapProxyPropertyDescriptor + { + public static UnwrapProxyPropertyDescriptor From( + Mapping.Property property, + int propertyIndex) + { + return new UnwrapProxyPropertyDescriptor( + propertyIndex, + property.Name, + property.Type + ); + } + + private UnwrapProxyPropertyDescriptor( + int propertyIndex, + string name, + IType type) + { + PropertyIndex = propertyIndex; + Name = name; + Type = type; + } + + /// + /// Access to the index of the property in terms of its position in the entity persister + /// + public int PropertyIndex { get; } + + /// + /// Access to the name of the property + /// + public string Name { get; } + + /// + /// Access to the property's type + /// + public IType Type { get; set; } + } +} diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs index 88cdb0154c8..0800f944180 100644 --- a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs @@ -21,7 +21,8 @@ public BytecodeEnhancementMetadataNonPocoImpl(string entityName) { EntityName = entityName; LazyPropertiesMetadata = LazyPropertiesMetadata.NonEnhanced(entityName); - _errorMessage= $"Entity [{entityName}] is non-poco, and therefore not instrumented"; + UnwrapProxyPropertiesMetadata = UnwrapProxyPropertiesMetadata.NonEnhanced(entityName); + _errorMessage = $"Entity [{entityName}] is non-poco, and therefore not instrumented"; } /// @@ -33,6 +34,9 @@ public BytecodeEnhancementMetadataNonPocoImpl(string entityName) /// public LazyPropertiesMetadata LazyPropertiesMetadata { get; } + /// + public UnwrapProxyPropertiesMetadata UnwrapProxyPropertiesMetadata { get; } + /// public IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session) { diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs index 28a093b2afb..651d729431d 100644 --- a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs @@ -18,10 +18,10 @@ public class BytecodeEnhancementMetadataPocoImpl : IBytecodeEnhancementMetadata public static IBytecodeEnhancementMetadata From( PersistentClass persistentClass, ICollection lazyPropertyDescriptors, - ISet unwrapProxyPropertyNames) + ICollection unwrapProxyPropertyDescriptors) { var mappedClass = persistentClass.MappedClass; - var enhancedForLazyLoading = lazyPropertyDescriptors?.Count > 0 || unwrapProxyPropertyNames?.Count > 0; + var enhancedForLazyLoading = lazyPropertyDescriptors?.Count > 0 || unwrapProxyPropertyDescriptors?.Count > 0; // We have to check all subclasses if any of them is enhanced for lazy loading as the // root class will be enhanced when any of the subclasses is enhanced, even if it @@ -40,15 +40,20 @@ public static IBytecodeEnhancementMetadata From( } } - var lazyAttributesMetadata = enhancedForLazyLoading - ? LazyPropertiesMetadata.From(persistentClass.EntityName, lazyPropertyDescriptors, unwrapProxyPropertyNames) + var lazyPropertiesMetadata = enhancedForLazyLoading + ? LazyPropertiesMetadata.From(persistentClass.EntityName, lazyPropertyDescriptors) : LazyPropertiesMetadata.NonEnhanced(persistentClass.EntityName); + var unwrapProxyPropertiesMetadata = enhancedForLazyLoading + ? UnwrapProxyPropertiesMetadata.From(persistentClass.EntityName, unwrapProxyPropertyDescriptors) + : UnwrapProxyPropertiesMetadata.NonEnhanced(persistentClass.EntityName); + return new BytecodeEnhancementMetadataPocoImpl( persistentClass.EntityName, mappedClass, enhancedForLazyLoading, - lazyAttributesMetadata + lazyPropertiesMetadata, + unwrapProxyPropertiesMetadata ); } @@ -92,12 +97,14 @@ public BytecodeEnhancementMetadataPocoImpl( string entityName, System.Type entityType, bool enhancedForLazyLoading, - LazyPropertiesMetadata lazyPropertiesMetadata) + LazyPropertiesMetadata lazyPropertiesMetadata, + UnwrapProxyPropertiesMetadata unwrapProxyPropertiesMetadata) { EntityName = entityName; _entityType = entityType; EnhancedForLazyLoading = enhancedForLazyLoading; LazyPropertiesMetadata = lazyPropertiesMetadata; + UnwrapProxyPropertiesMetadata = unwrapProxyPropertiesMetadata; } /// @@ -109,6 +116,9 @@ public BytecodeEnhancementMetadataPocoImpl( /// public LazyPropertiesMetadata LazyPropertiesMetadata { get; } + /// + public UnwrapProxyPropertiesMetadata UnwrapProxyPropertiesMetadata { get; } + /// public IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session) { @@ -133,7 +143,7 @@ public IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAre LazyPropertiesMetadata.HasLazyProperties && lazyPropertiesAreUnfetched ? new HashSet(LazyPropertiesMetadata.LazyPropertyNames) : null, - LazyPropertiesMetadata.UnwrapProxyPropertyNames, + UnwrapProxyPropertiesMetadata.UnwrapProxyPropertyNames, EntityName, _entityType); fieldInterceptorAccessor.FieldInterceptor = fieldInterceptorImpl; diff --git a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs index da1a5f6cf37..7fb104dac86 100644 --- a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs +++ b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs @@ -104,7 +104,7 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement properties = new StandardProperty[propertySpan]; List naturalIdNumbers = new List(); var lazyPropertyDescriptors = new List(); - var unwrapProxyPropertyNames = new HashSet(); + var unwrapProxyPropertyDescriptors = new List(); propertyNames = new string[propertySpan]; propertyTypes = new IType[propertySpan]; @@ -189,7 +189,7 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement if (isUnwrapProxy) { hasUnwrapProxyForProperties = true; - unwrapProxyPropertyNames.Add(prop.Name); + unwrapProxyPropertyDescriptors.Add(UnwrapProxyPropertyDescriptor.From(prop, i)); } propertyLaziness[i] = islazyProperty; @@ -323,7 +323,7 @@ public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplement if (persistentClass.HasPocoRepresentation) { BytecodeEnhancementMetadata = BytecodeEnhancementMetadataPocoImpl - .From(persistentClass, lazyPropertyDescriptors, unwrapProxyPropertyNames); + .From(persistentClass, lazyPropertyDescriptors, unwrapProxyPropertyDescriptors); } else { From 503f6d22e9f79e5dea400174083968bd5a4b1665 Mon Sep 17 00:00:00 2001 From: maca88 Date: Wed, 26 Dec 2018 22:50:07 +0100 Subject: [PATCH 3/7] Fixed proxy comments --- src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs | 2 +- src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs | 4 ++-- src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs index d329ae613b7..7ad434bff66 100644 --- a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs +++ b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs @@ -32,7 +32,7 @@ public interface IBytecodeEnhancementMetadata LazyPropertiesMetadata LazyPropertiesMetadata { get; } /// - /// Has the information about all properties mapped as proxy="no-proxy" + /// Has the information about all properties mapped as lazy="no-proxy" /// UnwrapProxyPropertiesMetadata UnwrapProxyPropertiesMetadata { get; } diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs index 5d222ddeb21..8c969b9a8ef 100644 --- a/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs @@ -7,7 +7,7 @@ namespace NHibernate.Bytecode { /// - /// Information about all properties mapped as proxy="no-proxy" for an entity + /// Information about all properties mapped as lazy="no-proxy" for an entity /// public class UnwrapProxyPropertiesMetadata { @@ -53,7 +53,7 @@ public int GetUnwrapProxyPropertyIndex(string propertyName) if (!_unwrapProxyPropertyDescriptors.TryGetValue(propertyName, out var descriptor)) { throw new InvalidOperationException( - $"Property {propertyName} is not mapped as proxy=\"no-proxy\" on entity {EntityName}"); + $"Property {propertyName} is not mapped as lazy=\"no-proxy\" on entity {EntityName}"); } return descriptor.PropertyIndex; diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs index 5058bf97e36..72c09393b7f 100644 --- a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs @@ -8,7 +8,7 @@ namespace NHibernate.Bytecode { /// - /// Descriptor for a property which is mapped as proxy="no-proxy" + /// Descriptor for a property which is mapped as lazy="no-proxy" /// public class UnwrapProxyPropertyDescriptor { From 502c54f9852ca185f88c6f03a94492a8fa1c4a4f Mon Sep 17 00:00:00 2001 From: maca88 Date: Thu, 27 Dec 2018 12:52:55 +0100 Subject: [PATCH 4/7] fixed GetUninitializedLazyProperties precondition --- .../Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs index 651d729431d..31f0f2ef99a 100644 --- a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs @@ -189,7 +189,7 @@ public ISet GetUninitializedLazyProperties(object entity) /// public ISet GetUninitializedLazyProperties(object[] entityState) { - if (LazyPropertiesMetadata.HasLazyProperties) + if (!LazyPropertiesMetadata.HasLazyProperties) { return CollectionHelper.EmptySet(); } From f7e5a0fbb9b4da8d22d55ec011922f2221761255 Mon Sep 17 00:00:00 2001 From: maca88 Date: Fri, 28 Dec 2018 03:25:32 +0100 Subject: [PATCH 5/7] Removed descriptors setters. --- src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs | 4 ++-- src/NHibernate/Bytecode/LazyPropertyDescriptor.cs | 2 +- src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs index 7ad434bff66..df7f58e4fd5 100644 --- a/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs +++ b/src/NHibernate/Bytecode/IBytecodeEnhancementMetadata.cs @@ -57,14 +57,14 @@ public interface IBytecodeEnhancementMetadata /// Retrieve the uninitialized lazy properties from the enhanced entity. /// /// The entity from which to retrieve the uninitialized lazy properties. - /// + /// The uninitialized property names. ISet GetUninitializedLazyProperties(object entity); /// /// Retrieve the uninitialized lazy properties from the entity state. /// /// The entity state from which to retrieve the uninitialized lazy properties. - /// + /// The uninitialized property names. ISet GetUninitializedLazyProperties(object[] entityState); } } diff --git a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs index 23426c2aa1c..9859ca64ae6 100644 --- a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs @@ -64,6 +64,6 @@ private LazyPropertyDescriptor( /// /// Access to the property's type /// - public IType Type { get; set; } + public IType Type { get; } } } diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs index 72c09393b7f..d83e64828cd 100644 --- a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs @@ -46,6 +46,6 @@ private UnwrapProxyPropertyDescriptor( /// /// Access to the property's type /// - public IType Type { get; set; } + public IType Type { get; } } } From 6c2f6eab775fc9ce8d63b276a8eda041c09350c6 Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 30 Dec 2018 20:26:06 +0100 Subject: [PATCH 6/7] Fix issues from the review comments and obsolete FieldInterceptionHelper.ExtractFieldInterceptor method. --- .../Async/NHSpecificTest/GH1439/Fixture.cs | 4 +- .../NHSpecificTest/GH1439/Fixture.cs | 4 +- src/NHibernate/Async/Engine/Cascade.cs | 2 +- .../Bytecode/LazyPropertyDescriptor.cs | 1 + .../Bytecode/NotInstrumentedException.cs | 6 ++ .../Bytecode/UnwrapProxyPropertiesMetadata.cs | 1 + .../Bytecode/UnwrapProxyPropertyDescriptor.cs | 1 + src/NHibernate/Engine/Cascade.cs | 2 +- src/NHibernate/Engine/EntityEntry.cs | 6 +- .../Default/AbstractSaveEventListener.cs | 7 +- .../Default/DefaultMergeEventListener.cs | 7 +- src/NHibernate/Impl/SessionImpl.cs | 5 +- .../Intercept/FieldInterceptionHelper.cs | 2 + src/NHibernate/NHibernateUtil.cs | 4 +- .../Entity/AbstractEntityPersister.cs | 12 +-- .../Persister/Entity/IEntityPersister.cs | 91 ------------------- .../BytecodeEnhancementMetadataNonPocoImpl.cs | 1 + .../BytecodeEnhancementMetadataPocoImpl.cs | 11 ++- 18 files changed, 45 insertions(+), 122 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1439/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1439/Fixture.cs index 0962d06c353..cf61e951e2d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1439/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1439/Fixture.cs @@ -91,7 +91,7 @@ public async Task LazyPropertyShouldBeUninitializedAndLoadableAsync() Is.False, "Lazy property initialization status"); Assert.That( - FieldInterceptionHelper.IsInstrumented(e1), + e1 is IFieldInterceptorAccessor, Is.True, "Entity IsInstrumented"); Assert.That( @@ -117,7 +117,7 @@ public async Task LazyPropertyShouldBeUninitializedAndLoadableWithComponentIdAsy Is.False, "Lazy property initialization status"); Assert.That( - FieldInterceptionHelper.IsInstrumented(e2), + e2 is IFieldInterceptorAccessor, Is.True, "Entity IsInstrumented"); Assert.That( diff --git a/src/NHibernate.Test/NHSpecificTest/GH1439/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1439/Fixture.cs index 5a12bfe77fe..d77e02a0fae 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1439/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1439/Fixture.cs @@ -79,7 +79,7 @@ public void LazyPropertyShouldBeUninitializedAndLoadable() Is.False, "Lazy property initialization status"); Assert.That( - FieldInterceptionHelper.IsInstrumented(e1), + e1 is IFieldInterceptorAccessor, Is.True, "Entity IsInstrumented"); Assert.That( @@ -105,7 +105,7 @@ public void LazyPropertyShouldBeUninitializedAndLoadableWithComponentId() Is.False, "Lazy property initialization status"); Assert.That( - FieldInterceptionHelper.IsInstrumented(e2), + e2 is IFieldInterceptorAccessor, Is.True, "Entity IsInstrumented"); Assert.That( diff --git a/src/NHibernate/Async/Engine/Cascade.cs b/src/NHibernate/Async/Engine/Cascade.cs index e33a941ba1e..77e8b93bfb1 100644 --- a/src/NHibernate/Async/Engine/Cascade.cs +++ b/src/NHibernate/Async/Engine/Cascade.cs @@ -60,7 +60,7 @@ public async Task CascadeOnAsync(IEntityPersister persister, object parent, obje IType[] types = persister.PropertyTypes; CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles; - var uninitializedLazyProperties = persister.GetUninitializedLazyProperties(parent); + var uninitializedLazyProperties = persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(parent); for (int i = 0; i < types.Length; i++) { CascadeStyle style = cascadeStyles[i]; diff --git a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs index 9859ca64ae6..a0640ef9470 100644 --- a/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/LazyPropertyDescriptor.cs @@ -12,6 +12,7 @@ namespace NHibernate.Bytecode /// /// Author: Steve Ebersole /// + [Serializable] public class LazyPropertyDescriptor { public static LazyPropertyDescriptor From( diff --git a/src/NHibernate/Bytecode/NotInstrumentedException.cs b/src/NHibernate/Bytecode/NotInstrumentedException.cs index d946d20b58b..71a392b9b0a 100644 --- a/src/NHibernate/Bytecode/NotInstrumentedException.cs +++ b/src/NHibernate/Bytecode/NotInstrumentedException.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; @@ -12,6 +13,7 @@ namespace NHibernate.Bytecode /// /// Author: Steve Ebersole /// + [Serializable] public class NotInstrumentedException : HibernateException { /// @@ -21,5 +23,9 @@ public class NotInstrumentedException : HibernateException public NotInstrumentedException(string message) : base(message) { } + + /// + protected NotInstrumentedException(SerializationInfo info, StreamingContext context) + : base(info, context) {} } } diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs index 8c969b9a8ef..9c2b6f6111e 100644 --- a/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertiesMetadata.cs @@ -9,6 +9,7 @@ namespace NHibernate.Bytecode /// /// Information about all properties mapped as lazy="no-proxy" for an entity /// + [Serializable] public class UnwrapProxyPropertiesMetadata { public static UnwrapProxyPropertiesMetadata NonEnhanced(string entityName) diff --git a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs index d83e64828cd..b4012e1778f 100644 --- a/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs +++ b/src/NHibernate/Bytecode/UnwrapProxyPropertyDescriptor.cs @@ -10,6 +10,7 @@ namespace NHibernate.Bytecode /// /// Descriptor for a property which is mapped as lazy="no-proxy" /// + [Serializable] public class UnwrapProxyPropertyDescriptor { public static UnwrapProxyPropertyDescriptor From( diff --git a/src/NHibernate/Engine/Cascade.cs b/src/NHibernate/Engine/Cascade.cs index 85500f7c9f2..a9ba97a214d 100644 --- a/src/NHibernate/Engine/Cascade.cs +++ b/src/NHibernate/Engine/Cascade.cs @@ -113,7 +113,7 @@ public void CascadeOn(IEntityPersister persister, object parent, object anything IType[] types = persister.PropertyTypes; CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles; - var uninitializedLazyProperties = persister.GetUninitializedLazyProperties(parent); + var uninitializedLazyProperties = persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(parent); for (int i = 0; i < types.Length; i++) { CascadeStyle style = cascadeStyles[i]; diff --git a/src/NHibernate/Engine/EntityEntry.cs b/src/NHibernate/Engine/EntityEntry.cs index ec7f93523cb..0dbb073326a 100644 --- a/src/NHibernate/Engine/EntityEntry.cs +++ b/src/NHibernate/Engine/EntityEntry.cs @@ -236,7 +236,7 @@ public void PostUpdate(object entity, object[] updatedState, object nextVersion) if (Persister.IsInstrumented) { - persister.ExtractFieldInterceptor(entity)?.ClearDirty(); + persister.EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(entity)?.ClearDirty(); } } @@ -268,8 +268,8 @@ public bool RequiresDirtyCheck(object entity) { return IsModifiableEntity() - && (Persister.HasMutableProperties || !FieldInterceptionHelper.IsInstrumented(entity) - || Persister.ExtractFieldInterceptor(entity).IsDirty); + && (Persister.HasMutableProperties || !(entity is IFieldInterceptorAccessor interceptorAccessor) + || interceptorAccessor.FieldInterceptor.IsDirty); } /// diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index cc8cf1183b3..530aed15d26 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -299,10 +299,11 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE private void MarkInterceptorDirty(object entity, IEntityPersister persister, IEventSource source) { - if (FieldInterceptionHelper.IsInstrumented(entity)) + if (persister.IsInstrumented) { - var interceptor = persister.InjectFieldInterceptor(entity, null, null, source); - interceptor.MarkDirty(); + var interceptor = persister.EntityMetamodel.BytecodeEnhancementMetadata + .InjectInterceptor(entity, false, source); + interceptor?.MarkDirty(); } } diff --git a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs index af57acfd44b..31781db0df4 100644 --- a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs @@ -404,11 +404,8 @@ private void MarkInterceptorDirty(object entity, IEntityPersister persister, obj { if (persister.IsInstrumented) { - var interceptor = persister.ExtractFieldInterceptor(target); - if (interceptor != null) - { - interceptor.MarkDirty(); - } + var interceptor = persister.EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(target); + interceptor?.MarkDirty(); } } diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index a94ef0c20f8..fa980fa038a 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -959,11 +959,10 @@ public override string BestGuessEntityName(object entity) entity = initializer.GetImplementation(); } - var interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); - if (interceptor != null) + if (entity is IFieldInterceptorAccessor interceptorAccessor && interceptorAccessor.FieldInterceptor != null) { // NH: support of field-interceptor-proxy - return interceptor.EntityName; + return interceptorAccessor.FieldInterceptor.EntityName; } EntityEntry entry = persistenceContext.GetEntry(entity); if (entry == null) diff --git a/src/NHibernate/Intercept/FieldInterceptionHelper.cs b/src/NHibernate/Intercept/FieldInterceptionHelper.cs index 33a65db1744..84c07b21077 100644 --- a/src/NHibernate/Intercept/FieldInterceptionHelper.cs +++ b/src/NHibernate/Intercept/FieldInterceptionHelper.cs @@ -22,11 +22,13 @@ public static bool IsInstrumented(System.Type entityClass) return Cfg.Environment.BytecodeProvider.ProxyFactoryFactory.IsInstrumented(entityClass); } + [Obsolete("This method has no more usages and will be removed in a future version")] public static bool IsInstrumented(object entity) { return entity is IFieldInterceptorAccessor; } + [Obsolete("This method has no more usages and will be removed in a future version")] public static IFieldInterceptor ExtractFieldInterceptor(object entity) { var fieldInterceptorAccessor = entity as IFieldInterceptorAccessor; diff --git a/src/NHibernate/NHibernateUtil.cs b/src/NHibernate/NHibernateUtil.cs index 2831f3d6298..fcc7a894e94 100644 --- a/src/NHibernate/NHibernateUtil.cs +++ b/src/NHibernate/NHibernateUtil.cs @@ -588,9 +588,9 @@ public static bool IsPropertyInitialized(object proxy, string propertyName) entity = proxy; } - if (FieldInterceptionHelper.IsInstrumented(entity)) + if (entity is IFieldInterceptorAccessor interceptorAccessor) { - IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity); + var interceptor = interceptorAccessor.FieldInterceptor; return interceptor == null || interceptor.IsInitializedField(propertyName); } else diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index a9036da2152..85d98154acd 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -684,7 +684,7 @@ public virtual string VersionColumnName get { return versionColumnName; } } - // 6.0 TODO: Add into IEntityPersister + // 6.0 TODO: Add into IEntityPersister and simplify .EntityMetamodel.BytecodeEnhancementMetadata external calls public IBytecodeEnhancementMetadata InstrumentationMetadata => EntityMetamodel.BytecodeEnhancementMetadata; [Obsolete("Please use RootTableName instead.")] @@ -3932,17 +3932,17 @@ public virtual bool HasLazyProperties public virtual void AfterReassociate(object entity, ISessionImplementor session) { - if (FieldInterceptionHelper.IsInstrumented(entity)) + if (IsInstrumented) { - var interceptor = EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(entity); + var interceptor = InstrumentationMetadata.ExtractInterceptor(entity); if (interceptor != null) { interceptor.Session = session; } else { - var fieldInterceptor = EntityMetamodel.BytecodeEnhancementMetadata.InjectInterceptor(entity, false, session); - fieldInterceptor.MarkDirty(); + var fieldInterceptor = InstrumentationMetadata.InjectInterceptor(entity, false, session); + fieldInterceptor?.MarkDirty(); } } } @@ -4093,7 +4093,7 @@ public string SelectFragment( public bool IsInstrumented { - get { return EntityTuplizer.IsInstrumented; } + get { return InstrumentationMetadata.EnhancedForLazyLoading; } } public bool HasInsertGeneratedProperties diff --git a/src/NHibernate/Persister/Entity/IEntityPersister.cs b/src/NHibernate/Persister/Entity/IEntityPersister.cs index f93c8fa81b3..7ba82488bb9 100644 --- a/src/NHibernate/Persister/Entity/IEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/IEntityPersister.cs @@ -623,96 +623,5 @@ public static int GetBatchSize(this IEntityPersister persister) return 1; } - - //6.0 TODO: Remove and replace usages with InstrumentationMetadata.GetUninitializedLazyProperties instead - internal static ISet GetUninitializedLazyProperties(this IEntityPersister persister, object entity) - { - if (persister is AbstractEntityPersister abstractEntityPersister) - { - return abstractEntityPersister.InstrumentationMetadata.GetUninitializedLazyProperties(entity); - } - - if (!persister.HasUninitializedLazyProperties(entity)) - { - return CollectionHelper.EmptySet(); - } - - // Assume they are all uninitialized. - var result = new HashSet(); - for (var i = 0; i < persister.PropertyLaziness.Length; i++) - { - if (persister.PropertyLaziness[i]) - { - result.Add(persister.PropertyNames[i]); - } - } - - return result; - } - - /// - /// Get uninitialized lazy properties from entity state - /// - //6.0 TODO: Remove and replace usages with InstrumentationMetadata.GetUninitializedLazyProperties instead - internal static ISet GetUninitializedLazyProperties(this IEntityPersister persister, object[] state) - { - if (persister is AbstractEntityPersister abstractEntityPersister) - { - return abstractEntityPersister.InstrumentationMetadata.GetUninitializedLazyProperties(state); - } - - if (!persister.HasLazyProperties) - { - return CollectionHelper.EmptySet(); - } - - var result = new HashSet(); - for (var i = 0; i < persister.PropertyLaziness.Length; i++) - { - if (persister.PropertyLaziness[i] && state[i] == LazyPropertyInitializer.UnfetchedProperty) - { - result.Add(persister.PropertyNames[i]); - } - } - - return result; - } - - //6.0 TODO: Remove and replace usages with InstrumentationMetadata.InjectInterceptor instead - internal static IFieldInterceptor InjectFieldInterceptor( - this IEntityPersister persister, - object entity, - ISet uninitializedFieldNames, - ISet unwrapProxyFieldNames, - ISessionImplementor session) - { - if (persister is AbstractEntityPersister abstractEntityPersister) - { - return abstractEntityPersister.InstrumentationMetadata.InjectInterceptor(entity, uninitializedFieldNames?.Count > 0, session); - } - -#pragma warning disable CS0618 - return FieldInterceptionHelper.InjectFieldInterceptor( - entity, - persister.EntityName, - persister.MappedClass, - uninitializedFieldNames, - unwrapProxyFieldNames, - session); -#pragma warning restore CS0618 - } - - //6.0 TODO: Remove and replace usages with InstrumentationMetadata.ExtractInterceptor instead - internal static IFieldInterceptor ExtractFieldInterceptor(this IEntityPersister persister, object entity) - { - if (persister is AbstractEntityPersister abstractEntityPersister) - { - return abstractEntityPersister.InstrumentationMetadata.ExtractInterceptor(entity); - } - -#pragma warning disable CS0618 - return FieldInterceptionHelper.ExtractFieldInterceptor(entity); -#pragma warning restore CS0618 - } } } diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs index 0800f944180..cd4dc440fa3 100644 --- a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataNonPocoImpl.cs @@ -13,6 +13,7 @@ namespace NHibernate.Tuple.Entity /// /// Author: Steve Ebersole /// + [Serializable] public class BytecodeEnhancementMetadataNonPocoImpl : IBytecodeEnhancementMetadata { private readonly string _errorMessage; diff --git a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs index 31f0f2ef99a..2f1ef4007d3 100644 --- a/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs +++ b/src/NHibernate/Tuple/Entity/BytecodeEnhancementMetadataPocoImpl.cs @@ -11,6 +11,7 @@ namespace NHibernate.Tuple.Entity /// /// Author: Steve Ebersole /// + [Serializable] public class BytecodeEnhancementMetadataPocoImpl : IBytecodeEnhancementMetadata { private readonly System.Type _entityType; @@ -68,10 +69,9 @@ private static bool IsEnhancedForLazyLoading(PersistentClass persistentClass) var lazyAvailable = persistentClass.HasPocoRepresentation && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); - // NH: WARNING if we have to disable lazy/unproxy properties we have to do it in the whole process. var lazy = persistentClass.IsLazy && (!persistentClass.HasPocoRepresentation || !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); - lazyAvailable &= lazy; // <== Disable lazy properties if the class is marked with lazy=false + lazyAvailable &= lazy; if (!lazyAvailable) { return false; @@ -183,7 +183,12 @@ public IFieldInterceptor ExtractInterceptor(object entity) public ISet GetUninitializedLazyProperties(object entity) { var interceptor = LazyPropertiesMetadata.HasLazyProperties ? ExtractInterceptor(entity) : null; - return interceptor?.GetUninitializedFields() ?? CollectionHelper.EmptySet(); + if (interceptor == null) + { + return CollectionHelper.EmptySet(); + } + + return interceptor.GetUninitializedFields() ?? LazyPropertiesMetadata.LazyPropertyNames; } /// From 7c91a4c3d9dcc33e6a275eae3cd6c868f4e4522f Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 30 Dec 2018 22:20:11 +0100 Subject: [PATCH 7/7] Modified condition --- src/NHibernate/Engine/EntityEntry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Engine/EntityEntry.cs b/src/NHibernate/Engine/EntityEntry.cs index 0dbb073326a..1ae1daaa16d 100644 --- a/src/NHibernate/Engine/EntityEntry.cs +++ b/src/NHibernate/Engine/EntityEntry.cs @@ -268,8 +268,8 @@ public bool RequiresDirtyCheck(object entity) { return IsModifiableEntity() - && (Persister.HasMutableProperties || !(entity is IFieldInterceptorAccessor interceptorAccessor) - || interceptorAccessor.FieldInterceptor.IsDirty); + && (Persister.HasMutableProperties || !Persister.IsInstrumented + || (Persister.EntityMetamodel.BytecodeEnhancementMetadata.ExtractInterceptor(entity)?.IsDirty ?? true)); } ///