From c1e7d96a4ad799cae8fe7cb307a1f7da6c604c34 Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 13 Jan 2019 18:02:50 +0100 Subject: [PATCH 1/2] Port's Hibernate EntityKey optimization --- src/NHibernate/Engine/EntityKey.cs | 69 +++++++++++----------------- src/NHibernate/Type/ManyToOneType.cs | 11 +++-- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/NHibernate/Engine/EntityKey.cs b/src/NHibernate/Engine/EntityKey.cs index 22dde296645..8ef5c1d1d92 100644 --- a/src/NHibernate/Engine/EntityKey.cs +++ b/src/NHibernate/Engine/EntityKey.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Serialization; +using System.Security; using NHibernate.Impl; using NHibernate.Persister.Entity; using NHibernate.Type; @@ -11,64 +12,40 @@ namespace NHibernate.Engine /// and the identifier space (eg. tablename) /// [Serializable] - public sealed class EntityKey : IDeserializationCallback + public sealed class EntityKey : IDeserializationCallback, ISerializable { private readonly object identifier; - private readonly string rootEntityName; - private readonly string entityName; - private readonly IType identifierType; - private readonly bool isBatchLoadable; - - private ISessionFactoryImplementor factory; + private readonly IEntityPersister _persister; // hashcode may vary among processes, they cannot be stored and have to be re-computed after deserialization [NonSerialized] private int? _hashCode; /// Construct a unique identifier for an entity class instance public EntityKey(object id, IEntityPersister persister) - : this(id, persister.RootEntityName, persister.EntityName, persister.IdentifierType, persister.IsBatchLoadable, persister.Factory) {} - - /// Used to reconstruct an EntityKey during deserialization. - /// The identifier value - /// The root entity name - /// The specific entity name - /// The type of the identifier value - /// Whether represented entity is eligible for batch loading - /// The session factory - private EntityKey(object identifier, string rootEntityName, string entityName, IType identifierType, bool batchLoadable, ISessionFactoryImplementor factory) { - if (identifier == null) - throw new AssertionFailure("null identifier"); - - this.identifier = identifier; - this.rootEntityName = rootEntityName; - this.entityName = entityName; - this.identifierType = identifierType; - isBatchLoadable = batchLoadable; - this.factory = factory; - + identifier = id ?? throw new AssertionFailure("null identifier"); + _persister = persister; _hashCode = GenerateHashCode(); } - public bool IsBatchLoadable + private EntityKey(SerializationInfo info, StreamingContext context) { - get { return isBatchLoadable; } + identifier = info.GetValue(nameof(Identifier), typeof(object)); + var factory = (ISessionFactoryImplementor) info.GetValue(nameof(_persister.Factory), typeof(ISessionFactoryImplementor)); + var entityName = (string) info.GetValue(nameof(EntityName), typeof(string)); + _persister = factory.GetEntityPersister(entityName); } + public bool IsBatchLoadable => _persister.IsBatchLoadable; + public object Identifier { get { return identifier; } } - public string EntityName - { - get { return entityName; } - } + public string EntityName => _persister.EntityName; - internal string RootEntityName - { - get { return rootEntityName; } - } + internal string RootEntityName => _persister.RootEntityName; public override bool Equals(object other) { @@ -76,8 +53,8 @@ public override bool Equals(object other) if(otherKey==null) return false; return - otherKey.rootEntityName.Equals(rootEntityName) - && identifierType.IsEqual(otherKey.Identifier, Identifier, factory); + otherKey.RootEntityName.Equals(RootEntityName) + && _persister.IdentifierType.IsEqual(otherKey.Identifier, Identifier, _persister.Factory); } public override int GetHashCode() @@ -100,15 +77,23 @@ private int GenerateHashCode() int result = 17; unchecked { - result = 37 * result + rootEntityName.GetHashCode(); - result = 37 * result + identifierType.GetHashCode(identifier, factory); + result = 37 * result + RootEntityName.GetHashCode(); + result = 37 * result + _persister.IdentifierType.GetHashCode(identifier, _persister.Factory); } return result; } public override string ToString() { - return "EntityKey" + MessageHelper.InfoString(factory.GetEntityPersister(EntityName), Identifier, factory); + return "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister.Factory); + } + + [SecurityCritical] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(Identifier), identifier); + info.AddValue(nameof(_persister.Factory), _persister.Factory); + info.AddValue(nameof(EntityName), EntityName); } } } diff --git a/src/NHibernate/Type/ManyToOneType.cs b/src/NHibernate/Type/ManyToOneType.cs index 4ac52cd54f2..8e38b1f685d 100644 --- a/src/NHibernate/Type/ManyToOneType.cs +++ b/src/NHibernate/Type/ManyToOneType.cs @@ -99,9 +99,14 @@ private void ScheduleBatchLoadIfNeeded(object id, ISessionImplementor session) //cannot batch fetch by unique key (property-ref associations) if (uniqueKeyPropertyName == null && id != null) { - IEntityPersister persister = session.Factory.GetEntityPersister(GetAssociatedEntityName()); - EntityKey entityKey = session.GenerateEntityKey(id, persister); - if (entityKey.IsBatchLoadable && !session.PersistenceContext.ContainsEntity(entityKey)) + var persister = session.Factory.GetEntityPersister(GetAssociatedEntityName()); + if (!persister.IsBatchLoadable) + { + return; + } + + var entityKey = session.GenerateEntityKey(id, persister); + if (!session.PersistenceContext.ContainsEntity(entityKey)) { session.PersistenceContext.BatchFetchQueue.AddBatchLoadableEntityKey(entityKey); } From b8cc5c7caf01bb48e4601f0916b861b25865128a Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 13 Jan 2019 21:02:28 +0100 Subject: [PATCH 2/2] Implemented IEquatable --- src/NHibernate/Engine/EntityKey.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/NHibernate/Engine/EntityKey.cs b/src/NHibernate/Engine/EntityKey.cs index 8ef5c1d1d92..e6646f1fda5 100644 --- a/src/NHibernate/Engine/EntityKey.cs +++ b/src/NHibernate/Engine/EntityKey.cs @@ -12,7 +12,7 @@ namespace NHibernate.Engine /// and the identifier space (eg. tablename) /// [Serializable] - public sealed class EntityKey : IDeserializationCallback, ISerializable + public sealed class EntityKey : IDeserializationCallback, ISerializable, IEquatable { private readonly object identifier; private readonly IEntityPersister _persister; @@ -49,12 +49,19 @@ public object Identifier public override bool Equals(object other) { - var otherKey = other as EntityKey; - if(otherKey==null) return false; + return other is EntityKey otherKey && Equals(otherKey); + } + + public bool Equals(EntityKey other) + { + if (other == null) + { + return false; + } return - otherKey.RootEntityName.Equals(RootEntityName) - && _persister.IdentifierType.IsEqual(otherKey.Identifier, Identifier, _persister.Factory); + other.RootEntityName.Equals(RootEntityName) + && _persister.IdentifierType.IsEqual(other.Identifier, Identifier, _persister.Factory); } public override int GetHashCode()