Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7333491

Browse files
committedDec 24, 2018
Port Hibernate's BytecodeEnhancementMetadata
1 parent c9c5a64 commit 7333491

18 files changed

+580
-97
lines changed
 

‎src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ protected virtual async Task EntityIsDetachedAsync(MergeEvent @event, IDictionar
389389
await (CopyValuesAsync(persister, entity, target, source, copyCache, cancellationToken)).ConfigureAwait(false);
390390

391391
//copyValues works by reflection, so explicitly mark the entity instance dirty
392-
MarkInterceptorDirty(entity, target);
392+
MarkInterceptorDirty(entity, persister, target);
393393

394394
@event.Result = result;
395395
}

‎src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
using Property=NHibernate.Mapping.Property;
3737
using NHibernate.SqlTypes;
3838
using System.Linq;
39+
using NHibernate.Bytecode;
3940

4041
namespace NHibernate.Persister.Entity
4142
{
@@ -880,7 +881,7 @@ public async Task UpdateAsync(object id, object[] fields, int[] dirtyFields, boo
880881
if ((entityMetamodel.IsDynamicUpdate && dirtyFields != null) ||
881882
// When having a dirty lazy property and the entity is not yet initialized we have to use a dynamic update for it even if
882883
// it is disabled in order to have it updated.
883-
(GetUninitializedLazyProperties(obj).Count > 0 && dirtyFields?.Count(o => PropertyLaziness[o]) > 0))
884+
(InstrumentationMetadata.GetUninitializedLazyProperties(obj).Count > 0 && dirtyFields?.Count(o => PropertyLaziness[o]) > 0))
884885
{
885886
// For the case of dynamic-update="true", we need to generate the UPDATE SQL
886887
propsToUpdate = GetPropertiesToUpdate(dirtyFields, hasDirtyCollection);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using NHibernate.Engine;
7+
using NHibernate.Intercept;
8+
using NHibernate.Tuple.Entity;
9+
10+
namespace NHibernate.Bytecode
11+
{
12+
/// <summary>
13+
/// Encapsulates bytecode enhancement information about a particular entity.
14+
///
15+
/// Author: Steve Ebersole
16+
/// </summary>
17+
public interface IBytecodeEnhancementMetadata
18+
{
19+
/// <summary>
20+
/// The name of the entity to which this metadata applies.
21+
/// </summary>
22+
string EntityName { get; }
23+
24+
/// <summary>
25+
/// Has the entity class been bytecode enhanced for lazy loading?
26+
/// </summary>
27+
bool EnhancedForLazyLoading { get; }
28+
29+
LazyPropertiesMetadata LazyPropertiesMetadata { get; }
30+
31+
/// <summary>
32+
/// Build and inject an interceptor instance into the enhanced entity.
33+
/// </summary>
34+
/// <param name="entity">The entity into which built interceptor should be injected.</param>
35+
/// <param name="lazyPropertiesAreUnfetched">Whether all lazy properties were unfetched or not.</param>
36+
/// <param name="session">The session to which the entity instance belongs.</param>
37+
/// <returns>The built and injected interceptor.</returns>
38+
// TODO: Remove lazyPropertiesAreUnfetched when interceptor will be injected on entity instantiation
39+
IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session);
40+
41+
/// <summary>
42+
/// Extract the field interceptor instance from the enhanced entity.
43+
/// </summary>
44+
/// <param name="entity">The entity from which to extract the interceptor.</param>
45+
/// <returns>The extracted interceptor.</returns>
46+
IFieldInterceptor ExtractInterceptor(object entity);
47+
48+
/// <summary>
49+
/// Retrieve the uninitialized lazy properties from the enhanced entity.
50+
/// </summary>
51+
/// <param name="entity">The entity from which to retrieve the uninitialized lazy properties.</param>
52+
/// <returns></returns>
53+
ISet<string> GetUninitializedLazyProperties(object entity);
54+
55+
/// <summary>
56+
/// Retrieve the uninitialized lazy properties from the entity state.
57+
/// </summary>
58+
/// <param name="entityState">The entity state from which to retrieve the uninitialized lazy properties.</param>
59+
/// <returns></returns>
60+
ISet<string> GetUninitializedLazyProperties(object[] entityState);
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Iesi.Collections.Generic;
7+
using NHibernate.Util;
8+
9+
namespace NHibernate.Bytecode
10+
{
11+
/// <summary>
12+
/// Information about all of the bytecode lazy properties for an entity
13+
///
14+
/// Author: Steve Ebersole
15+
/// </summary>
16+
[Serializable]
17+
public class LazyPropertiesMetadata
18+
{
19+
public static LazyPropertiesMetadata NonEnhanced(string entityName)
20+
{
21+
return new LazyPropertiesMetadata(entityName, null, null);
22+
}
23+
24+
public static LazyPropertiesMetadata From(
25+
string entityName,
26+
IEnumerable<LazyPropertyDescriptor> lazyPropertyDescriptors,
27+
ISet<string> unwrapProxyPropertyNames)
28+
{
29+
// TODO: port lazy fetch groups
30+
return new LazyPropertiesMetadata(
31+
entityName,
32+
lazyPropertyDescriptors.ToDictionary(o => o.Name),
33+
unwrapProxyPropertyNames);
34+
}
35+
36+
private readonly IDictionary<string, LazyPropertyDescriptor> _lazyPropertyDescriptors;
37+
38+
public LazyPropertiesMetadata(
39+
string entityName,
40+
IDictionary<string, LazyPropertyDescriptor> lazyPropertyDescriptors,
41+
ISet<string> unwrapProxyPropertyNames)
42+
{
43+
EntityName = entityName;
44+
_lazyPropertyDescriptors = lazyPropertyDescriptors;
45+
HasLazyProperties = _lazyPropertyDescriptors?.Count > 0;
46+
LazyPropertyNames = HasLazyProperties
47+
? new ReadOnlySet<string>(new HashSet<string>(_lazyPropertyDescriptors.Keys))
48+
: CollectionHelper.EmptySet<string>();
49+
HasUnwrapProxyProperties = unwrapProxyPropertyNames?.Count > 0;
50+
UnwrapProxyPropertyNames = HasUnwrapProxyProperties
51+
? new ReadOnlySet<string>(unwrapProxyPropertyNames)
52+
: CollectionHelper.EmptySet<string>();
53+
// TODO: port lazy fetch groups
54+
}
55+
56+
public string EntityName { get; }
57+
58+
public bool HasLazyProperties { get; }
59+
60+
public bool HasUnwrapProxyProperties { get; }
61+
62+
public ISet<string> LazyPropertyNames { get; }
63+
64+
public ISet<string> UnwrapProxyPropertyNames { get; }
65+
66+
public IEnumerable<LazyPropertyDescriptor> LazyPropertyDescriptors =>
67+
_lazyPropertyDescriptors?.Values ?? Enumerable.Empty<LazyPropertyDescriptor>();
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using NHibernate.Type;
7+
8+
namespace NHibernate.Bytecode
9+
{
10+
/// <summary>
11+
/// Descriptor for a property which is enabled for bytecode lazy fetching
12+
///
13+
/// Author: Steve Ebersole
14+
/// </summary>
15+
public class LazyPropertyDescriptor
16+
{
17+
public static LazyPropertyDescriptor From(
18+
Mapping.Property property,
19+
int attributeIndex,
20+
int lazyIndex)
21+
{
22+
// TODO: port lazy fetch groups
23+
24+
return new LazyPropertyDescriptor(
25+
attributeIndex,
26+
lazyIndex,
27+
property.Name,
28+
property.Type
29+
);
30+
}
31+
32+
private LazyPropertyDescriptor(
33+
int propertyIndex,
34+
int lazyIndex,
35+
string name,
36+
IType type)
37+
{
38+
if (propertyIndex < lazyIndex)
39+
{
40+
throw new InvalidOperationException("Property index is lower than the lazy index.");
41+
}
42+
43+
PropertyIndex = propertyIndex;
44+
LazyIndex = lazyIndex;
45+
Name = name;
46+
Type = type;
47+
}
48+
49+
/// <summary>
50+
/// Access to the index of the property in terms of its position in the entity persister
51+
/// </summary>
52+
public int PropertyIndex { get; }
53+
54+
/// <summary>
55+
/// Access to the index of the property in terms of its position within the lazy properties of the persister
56+
/// </summary>
57+
public int LazyIndex { get; }
58+
59+
/// <summary>
60+
/// Access to the name of the property
61+
/// </summary>
62+
public string Name { get; }
63+
64+
/// <summary>
65+
/// Access to the property's type
66+
/// </summary>
67+
public IType Type { get; set; }
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace NHibernate.Bytecode
8+
{
9+
/// <summary>
10+
/// Indicates a condition where an instrumented/enhanced class was expected, but the class was not
11+
/// instrumented/enhanced.
12+
///
13+
/// Author: Steve Ebersole
14+
/// </summary>
15+
public class NotInstrumentedException : HibernateException
16+
{
17+
/// <summary>
18+
/// Constructs a NotInstrumentedException.
19+
/// </summary>
20+
/// <param name="message">Message explaining the exception condition.</param>
21+
public NotInstrumentedException(string message) : base(message)
22+
{
23+
}
24+
}
25+
}

‎src/NHibernate/Engine/EntityEntry.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ public void PostUpdate(object entity, object[] updatedState, object nextVersion)
233233
version = nextVersion;
234234
Persister.SetPropertyValue(entity, Persister.VersionProperty, nextVersion);
235235
}
236-
FieldInterceptionHelper.ClearDirty(entity);
236+
237+
if (Persister.IsInstrumented)
238+
{
239+
persister.ExtractFieldInterceptor(entity)?.ClearDirty();
240+
}
237241
}
238242

239243
/// <summary>
@@ -265,7 +269,7 @@ public bool RequiresDirtyCheck(object entity)
265269
return
266270
IsModifiableEntity()
267271
&& (Persister.HasMutableProperties || !FieldInterceptionHelper.IsInstrumented(entity)
268-
|| FieldInterceptionHelper.ExtractFieldInterceptor(entity).IsDirty);
272+
|| Persister.ExtractFieldInterceptor(entity).IsDirty);
269273
}
270274

271275
/// <summary>

‎src/NHibernate/Event/Default/AbstractSaveEventListener.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ private void MarkInterceptorDirty(object entity, IEntityPersister persister, IEv
301301
{
302302
if (FieldInterceptionHelper.IsInstrumented(entity))
303303
{
304-
IFieldInterceptor interceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, persister.EntityName, persister.MappedClass, null, null, source);
304+
var interceptor = persister.InjectFieldInterceptor(entity, null, null, source);
305305
interceptor.MarkDirty();
306306
}
307307
}

‎src/NHibernate/Event/Default/DefaultMergeEventListener.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ protected virtual void EntityIsDetached(MergeEvent @event, IDictionary copyCache
380380
CopyValues(persister, entity, target, source, copyCache);
381381

382382
//copyValues works by reflection, so explicitly mark the entity instance dirty
383-
MarkInterceptorDirty(entity, target);
383+
MarkInterceptorDirty(entity, persister, target);
384384

385385
@event.Result = result;
386386
}
@@ -400,11 +400,11 @@ protected virtual bool InvokeUpdateLifecycle(object entity, IEntityPersister per
400400
return false;
401401
}
402402

403-
private void MarkInterceptorDirty(object entity, object target)
403+
private void MarkInterceptorDirty(object entity, IEntityPersister persister, object target)
404404
{
405-
if (FieldInterceptionHelper.IsInstrumented(entity))
405+
if (persister.IsInstrumented)
406406
{
407-
IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(target);
407+
var interceptor = persister.ExtractFieldInterceptor(target);
408408
if (interceptor != null)
409409
{
410410
interceptor.MarkDirty();

‎src/NHibernate/Impl/SessionImpl.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -958,10 +958,11 @@ public override string BestGuessEntityName(object entity)
958958
}
959959
entity = initializer.GetImplementation();
960960
}
961-
if (FieldInterceptionHelper.IsInstrumented(entity))
961+
962+
var interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity);
963+
if (interceptor != null)
962964
{
963965
// NH: support of field-interceptor-proxy
964-
IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity);
965966
return interceptor.EntityName;
966967
}
967968
EntityEntry entry = persistenceContext.GetEntry(entity);

‎src/NHibernate/Intercept/FieldInterceptionHelper.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using NHibernate.Engine;
34

@@ -32,6 +33,7 @@ public static IFieldInterceptor ExtractFieldInterceptor(object entity)
3233
return fieldInterceptorAccessor == null ? null : fieldInterceptorAccessor.FieldInterceptor;
3334
}
3435

36+
[Obsolete("Use IBytecodeEnhancementMetadata.InjectInterceptor method instead")]
3537
public static IFieldInterceptor InjectFieldInterceptor(object entity, string entityName,
3638
System.Type mappedClass,
3739
ISet<string> uninitializedFieldNames,
@@ -48,6 +50,7 @@ public static IFieldInterceptor InjectFieldInterceptor(object entity, string ent
4850
return null;
4951
}
5052

53+
[Obsolete("This method has no more usages and will be removed in a future version")]
5154
public static void ClearDirty(object entity)
5255
{
5356
IFieldInterceptor interceptor = ExtractFieldInterceptor(entity);
@@ -57,6 +60,7 @@ public static void ClearDirty(object entity)
5760
}
5861
}
5962

63+
[Obsolete("This method has no more usages and will be removed in a future version")]
6064
public static void MarkDirty(object entity)
6165
{
6266
IFieldInterceptor interceptor = ExtractFieldInterceptor(entity);
@@ -66,4 +70,4 @@ public static void MarkDirty(object entity)
6670
}
6771
}
6872
}
69-
}
73+
}

0 commit comments

Comments
 (0)
Please sign in to comment.