Skip to content

Commit dfd9c3b

Browse files
maca88fredericDelaporte
authored andcommitted
Port Hibernate's BytecodeEnhancementMetadata (nhibernate#1946)
1 parent cbc2527 commit dfd9c3b

25 files changed

+694
-164
lines changed

src/NHibernate.Test/Async/NHSpecificTest/GH1439/Fixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public async Task LazyPropertyShouldBeUninitializedAndLoadableAsync()
9191
Is.False,
9292
"Lazy property initialization status");
9393
Assert.That(
94-
FieldInterceptionHelper.IsInstrumented(e1),
94+
e1 is IFieldInterceptorAccessor,
9595
Is.True,
9696
"Entity IsInstrumented");
9797
Assert.That(
@@ -117,7 +117,7 @@ public async Task LazyPropertyShouldBeUninitializedAndLoadableWithComponentIdAsy
117117
Is.False,
118118
"Lazy property initialization status");
119119
Assert.That(
120-
FieldInterceptionHelper.IsInstrumented(e2),
120+
e2 is IFieldInterceptorAccessor,
121121
Is.True,
122122
"Entity IsInstrumented");
123123
Assert.That(

src/NHibernate.Test/NHSpecificTest/GH1439/Fixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void LazyPropertyShouldBeUninitializedAndLoadable()
7979
Is.False,
8080
"Lazy property initialization status");
8181
Assert.That(
82-
FieldInterceptionHelper.IsInstrumented(e1),
82+
e1 is IFieldInterceptorAccessor,
8383
Is.True,
8484
"Entity IsInstrumented");
8585
Assert.That(
@@ -105,7 +105,7 @@ public void LazyPropertyShouldBeUninitializedAndLoadableWithComponentId()
105105
Is.False,
106106
"Lazy property initialization status");
107107
Assert.That(
108-
FieldInterceptionHelper.IsInstrumented(e2),
108+
e2 is IFieldInterceptorAccessor,
109109
Is.True,
110110
"Entity IsInstrumented");
111111
Assert.That(

src/NHibernate/Async/Engine/Cascade.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public async Task CascadeOnAsync(IEntityPersister persister, object parent, obje
6060

6161
IType[] types = persister.PropertyTypes;
6262
CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles;
63-
var uninitializedLazyProperties = persister.GetUninitializedLazyProperties(parent);
63+
var uninitializedLazyProperties = persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(parent);
6464
for (int i = 0; i < types.Length; i++)
6565
{
6666
CascadeStyle style = cascadeStyles[i];

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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
{
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
/// <summary>
30+
/// Has the information about all lazy properties
31+
/// </summary>
32+
LazyPropertiesMetadata LazyPropertiesMetadata { get; }
33+
34+
/// <summary>
35+
/// Has the information about all properties mapped as lazy="no-proxy"
36+
/// </summary>
37+
UnwrapProxyPropertiesMetadata UnwrapProxyPropertiesMetadata { get; }
38+
39+
/// <summary>
40+
/// Build and inject an interceptor instance into the enhanced entity.
41+
/// </summary>
42+
/// <param name="entity">The entity into which built interceptor should be injected.</param>
43+
/// <param name="lazyPropertiesAreUnfetched">Whether all lazy properties were unfetched or not.</param>
44+
/// <param name="session">The session to which the entity instance belongs.</param>
45+
/// <returns>The built and injected interceptor.</returns>
46+
// TODO: Remove lazyPropertiesAreUnfetched when interceptor will be injected on entity instantiation
47+
IFieldInterceptor InjectInterceptor(object entity, bool lazyPropertiesAreUnfetched, ISessionImplementor session);
48+
49+
/// <summary>
50+
/// Extract the field interceptor instance from the enhanced entity.
51+
/// </summary>
52+
/// <param name="entity">The entity from which to extract the interceptor.</param>
53+
/// <returns>The extracted interceptor.</returns>
54+
IFieldInterceptor ExtractInterceptor(object entity);
55+
56+
/// <summary>
57+
/// Retrieve the uninitialized lazy properties from the enhanced entity.
58+
/// </summary>
59+
/// <param name="entity">The entity from which to retrieve the uninitialized lazy properties.</param>
60+
/// <returns>The uninitialized property names.</returns>
61+
ISet<string> GetUninitializedLazyProperties(object entity);
62+
63+
/// <summary>
64+
/// Retrieve the uninitialized lazy properties from the entity state.
65+
/// </summary>
66+
/// <param name="entityState">The entity state from which to retrieve the uninitialized lazy properties.</param>
67+
/// <returns>The uninitialized property names.</returns>
68+
ISet<string> GetUninitializedLazyProperties(object[] entityState);
69+
}
70+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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);
22+
}
23+
24+
public static LazyPropertiesMetadata From(
25+
string entityName,
26+
IEnumerable<LazyPropertyDescriptor> lazyPropertyDescriptors)
27+
{
28+
// TODO: port lazy fetch groups
29+
return new LazyPropertiesMetadata(
30+
entityName,
31+
lazyPropertyDescriptors.ToDictionary(o => o.Name));
32+
}
33+
34+
private readonly IDictionary<string, LazyPropertyDescriptor> _lazyPropertyDescriptors;
35+
36+
public LazyPropertiesMetadata(
37+
string entityName,
38+
IDictionary<string, LazyPropertyDescriptor> lazyPropertyDescriptors)
39+
{
40+
EntityName = entityName;
41+
_lazyPropertyDescriptors = lazyPropertyDescriptors;
42+
HasLazyProperties = _lazyPropertyDescriptors?.Count > 0;
43+
LazyPropertyNames = HasLazyProperties
44+
? new ReadOnlySet<string>(new HashSet<string>(_lazyPropertyDescriptors.Keys))
45+
: CollectionHelper.EmptySet<string>();
46+
// TODO: port lazy fetch groups
47+
}
48+
49+
public string EntityName { get; }
50+
51+
public bool HasLazyProperties { get; }
52+
53+
public ISet<string> LazyPropertyNames { get; }
54+
55+
public IEnumerable<LazyPropertyDescriptor> LazyPropertyDescriptors =>
56+
_lazyPropertyDescriptors?.Values ?? Enumerable.Empty<LazyPropertyDescriptor>();
57+
}
58+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
[Serializable]
16+
public class LazyPropertyDescriptor
17+
{
18+
public static LazyPropertyDescriptor From(
19+
Mapping.Property property,
20+
int propertyIndex,
21+
int lazyIndex)
22+
{
23+
// TODO: port lazy fetch groups
24+
25+
return new LazyPropertyDescriptor(
26+
propertyIndex,
27+
lazyIndex,
28+
property.Name,
29+
property.Type
30+
);
31+
}
32+
33+
private LazyPropertyDescriptor(
34+
int propertyIndex,
35+
int lazyIndex,
36+
string name,
37+
IType type)
38+
{
39+
if (propertyIndex < lazyIndex)
40+
{
41+
throw new InvalidOperationException("Property index is lower than the lazy index.");
42+
}
43+
44+
PropertyIndex = propertyIndex;
45+
LazyIndex = lazyIndex;
46+
Name = name;
47+
Type = type;
48+
}
49+
50+
/// <summary>
51+
/// Access to the index of the property in terms of its position in the entity persister
52+
/// </summary>
53+
public int PropertyIndex { get; }
54+
55+
/// <summary>
56+
/// Access to the index of the property in terms of its position within the lazy properties of the persister
57+
/// </summary>
58+
public int LazyIndex { get; }
59+
60+
/// <summary>
61+
/// Access to the name of the property
62+
/// </summary>
63+
public string Name { get; }
64+
65+
/// <summary>
66+
/// Access to the property's type
67+
/// </summary>
68+
public IType Type { get; }
69+
}
70+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.Serialization;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace NHibernate.Bytecode
9+
{
10+
/// <summary>
11+
/// Indicates a condition where an instrumented/enhanced class was expected, but the class was not
12+
/// instrumented/enhanced.
13+
///
14+
/// Author: Steve Ebersole
15+
/// </summary>
16+
[Serializable]
17+
public class NotInstrumentedException : HibernateException
18+
{
19+
/// <summary>
20+
/// Constructs a NotInstrumentedException.
21+
/// </summary>
22+
/// <param name="message">Message explaining the exception condition.</param>
23+
public NotInstrumentedException(string message) : base(message)
24+
{
25+
}
26+
27+
/// <inheritdoc />
28+
protected NotInstrumentedException(SerializationInfo info, StreamingContext context)
29+
: base(info, context) {}
30+
}
31+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Iesi.Collections.Generic;
5+
using NHibernate.Util;
6+
7+
namespace NHibernate.Bytecode
8+
{
9+
/// <summary>
10+
/// Information about all properties mapped as lazy="no-proxy" for an entity
11+
/// </summary>
12+
[Serializable]
13+
public class UnwrapProxyPropertiesMetadata
14+
{
15+
public static UnwrapProxyPropertiesMetadata NonEnhanced(string entityName)
16+
{
17+
return new UnwrapProxyPropertiesMetadata(entityName, null);
18+
}
19+
20+
public static UnwrapProxyPropertiesMetadata From(
21+
string entityName,
22+
IEnumerable<UnwrapProxyPropertyDescriptor> unwrapProxyPropertyDescriptors)
23+
{
24+
return new UnwrapProxyPropertiesMetadata(
25+
entityName,
26+
unwrapProxyPropertyDescriptors.ToDictionary(o => o.Name));
27+
}
28+
29+
private readonly IDictionary<string, UnwrapProxyPropertyDescriptor> _unwrapProxyPropertyDescriptors;
30+
31+
public UnwrapProxyPropertiesMetadata(
32+
string entityName,
33+
IDictionary<string, UnwrapProxyPropertyDescriptor> unwrapProxyPropertyDescriptors)
34+
{
35+
EntityName = entityName;
36+
_unwrapProxyPropertyDescriptors = unwrapProxyPropertyDescriptors;
37+
HasUnwrapProxyProperties = unwrapProxyPropertyDescriptors?.Count > 0;
38+
UnwrapProxyPropertyNames = HasUnwrapProxyProperties
39+
? new ReadOnlySet<string>(new HashSet<string>(unwrapProxyPropertyDescriptors.Keys))
40+
: CollectionHelper.EmptySet<string>();
41+
}
42+
43+
public string EntityName { get; }
44+
45+
public bool HasUnwrapProxyProperties { get; }
46+
47+
public ISet<string> UnwrapProxyPropertyNames { get; }
48+
49+
public IEnumerable<UnwrapProxyPropertyDescriptor> UnwrapProxyPropertyDescriptors =>
50+
_unwrapProxyPropertyDescriptors?.Values ?? Enumerable.Empty<UnwrapProxyPropertyDescriptor>();
51+
52+
public int GetUnwrapProxyPropertyIndex(string propertyName)
53+
{
54+
if (!_unwrapProxyPropertyDescriptors.TryGetValue(propertyName, out var descriptor))
55+
{
56+
throw new InvalidOperationException(
57+
$"Property {propertyName} is not mapped as lazy=\"no-proxy\" on entity {EntityName}");
58+
}
59+
60+
return descriptor.PropertyIndex;
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)