Skip to content

Commit 14c5cdb

Browse files
maca88hazzik
authored andcommitted
Port Hibernate's EntityKey optimization (nhibernate#1972)
This makes EntityKey as small as possible to reduce memory footprint. Also it modifies ManyToOneType.ScheduleBatchLoadIfNeeded not to generate an entity key when batching is disabled to reduce garbage collection.
1 parent c7d2a6f commit 14c5cdb

File tree

2 files changed

+43
-46
lines changed

2 files changed

+43
-46
lines changed

src/NHibernate/Engine/EntityKey.cs

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Runtime.Serialization;
3+
using System.Security;
34
using NHibernate.Impl;
45
using NHibernate.Persister.Entity;
56
using NHibernate.Type;
@@ -11,73 +12,56 @@ namespace NHibernate.Engine
1112
/// and the identifier space (eg. tablename)
1213
/// </summary>
1314
[Serializable]
14-
public sealed class EntityKey : IDeserializationCallback
15+
public sealed class EntityKey : IDeserializationCallback, ISerializable, IEquatable<EntityKey>
1516
{
1617
private readonly object identifier;
17-
private readonly string rootEntityName;
18-
private readonly string entityName;
19-
private readonly IType identifierType;
20-
private readonly bool isBatchLoadable;
21-
22-
private ISessionFactoryImplementor factory;
18+
private readonly IEntityPersister _persister;
2319
// hashcode may vary among processes, they cannot be stored and have to be re-computed after deserialization
2420
[NonSerialized]
2521
private int? _hashCode;
2622

2723
/// <summary> Construct a unique identifier for an entity class instance</summary>
2824
public EntityKey(object id, IEntityPersister persister)
29-
: this(id, persister.RootEntityName, persister.EntityName, persister.IdentifierType, persister.IsBatchLoadable, persister.Factory) {}
30-
31-
/// <summary> Used to reconstruct an EntityKey during deserialization. </summary>
32-
/// <param name="identifier">The identifier value </param>
33-
/// <param name="rootEntityName">The root entity name </param>
34-
/// <param name="entityName">The specific entity name </param>
35-
/// <param name="identifierType">The type of the identifier value </param>
36-
/// <param name="batchLoadable">Whether represented entity is eligible for batch loading </param>
37-
/// <param name="factory">The session factory </param>
38-
private EntityKey(object identifier, string rootEntityName, string entityName, IType identifierType, bool batchLoadable, ISessionFactoryImplementor factory)
3925
{
40-
if (identifier == null)
41-
throw new AssertionFailure("null identifier");
42-
43-
this.identifier = identifier;
44-
this.rootEntityName = rootEntityName;
45-
this.entityName = entityName;
46-
this.identifierType = identifierType;
47-
isBatchLoadable = batchLoadable;
48-
this.factory = factory;
49-
26+
identifier = id ?? throw new AssertionFailure("null identifier");
27+
_persister = persister;
5028
_hashCode = GenerateHashCode();
5129
}
5230

53-
public bool IsBatchLoadable
31+
private EntityKey(SerializationInfo info, StreamingContext context)
5432
{
55-
get { return isBatchLoadable; }
33+
identifier = info.GetValue(nameof(Identifier), typeof(object));
34+
var factory = (ISessionFactoryImplementor) info.GetValue(nameof(_persister.Factory), typeof(ISessionFactoryImplementor));
35+
var entityName = (string) info.GetValue(nameof(EntityName), typeof(string));
36+
_persister = factory.GetEntityPersister(entityName);
5637
}
5738

39+
public bool IsBatchLoadable => _persister.IsBatchLoadable;
40+
5841
public object Identifier
5942
{
6043
get { return identifier; }
6144
}
6245

63-
public string EntityName
64-
{
65-
get { return entityName; }
66-
}
46+
public string EntityName => _persister.EntityName;
47+
48+
internal string RootEntityName => _persister.RootEntityName;
6749

68-
internal string RootEntityName
50+
public override bool Equals(object other)
6951
{
70-
get { return rootEntityName; }
52+
return other is EntityKey otherKey && Equals(otherKey);
7153
}
7254

73-
public override bool Equals(object other)
55+
public bool Equals(EntityKey other)
7456
{
75-
var otherKey = other as EntityKey;
76-
if(otherKey==null) return false;
57+
if (other == null)
58+
{
59+
return false;
60+
}
7761

7862
return
79-
otherKey.rootEntityName.Equals(rootEntityName)
80-
&& identifierType.IsEqual(otherKey.Identifier, Identifier, factory);
63+
other.RootEntityName.Equals(RootEntityName)
64+
&& _persister.IdentifierType.IsEqual(other.Identifier, Identifier, _persister.Factory);
8165
}
8266

8367
public override int GetHashCode()
@@ -100,15 +84,23 @@ private int GenerateHashCode()
10084
int result = 17;
10185
unchecked
10286
{
103-
result = 37 * result + rootEntityName.GetHashCode();
104-
result = 37 * result + identifierType.GetHashCode(identifier, factory);
87+
result = 37 * result + RootEntityName.GetHashCode();
88+
result = 37 * result + _persister.IdentifierType.GetHashCode(identifier, _persister.Factory);
10589
}
10690
return result;
10791
}
10892

10993
public override string ToString()
11094
{
111-
return "EntityKey" + MessageHelper.InfoString(factory.GetEntityPersister(EntityName), Identifier, factory);
95+
return "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister.Factory);
96+
}
97+
98+
[SecurityCritical]
99+
public void GetObjectData(SerializationInfo info, StreamingContext context)
100+
{
101+
info.AddValue(nameof(Identifier), identifier);
102+
info.AddValue(nameof(_persister.Factory), _persister.Factory);
103+
info.AddValue(nameof(EntityName), EntityName);
112104
}
113105
}
114106
}

src/NHibernate/Type/ManyToOneType.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,14 @@ private void ScheduleBatchLoadIfNeeded(object id, ISessionImplementor session)
9999
//cannot batch fetch by unique key (property-ref associations)
100100
if (uniqueKeyPropertyName == null && id != null)
101101
{
102-
IEntityPersister persister = session.Factory.GetEntityPersister(GetAssociatedEntityName());
103-
EntityKey entityKey = session.GenerateEntityKey(id, persister);
104-
if (entityKey.IsBatchLoadable && !session.PersistenceContext.ContainsEntity(entityKey))
102+
var persister = session.Factory.GetEntityPersister(GetAssociatedEntityName());
103+
if (!persister.IsBatchLoadable)
104+
{
105+
return;
106+
}
107+
108+
var entityKey = session.GenerateEntityKey(id, persister);
109+
if (!session.PersistenceContext.ContainsEntity(entityKey))
105110
{
106111
session.PersistenceContext.BatchFetchQueue.AddBatchLoadableEntityKey(entityKey);
107112
}

0 commit comments

Comments
 (0)