33using System . Security ;
44using NHibernate . Impl ;
55using NHibernate . Persister . Entity ;
6- using NHibernate . Type ;
76
87namespace NHibernate . Engine
98{
@@ -12,28 +11,44 @@ namespace NHibernate.Engine
1211 /// and the identifier space (eg. tablename)
1312 /// </summary>
1413 [ Serializable ]
15- public sealed class EntityKey : IDeserializationCallback , ISerializable , IEquatable < EntityKey >
14+ public struct EntityKey : ISerializable , IEquatable < EntityKey >
1615 {
16+ public static EntityKey Null { get ; } = new EntityKey ( ) ;
17+
18+ public bool IsNull => identifier == null ;
19+ public bool IsNotNull => ! IsNull ;
20+
1721 private readonly object identifier ;
1822 private readonly IEntityPersister _persister ;
1923 // hashcode may vary among processes, they cannot be stored and have to be re-computed after deserialization
20- [ NonSerialized ]
21- private int ? _hashCode ;
24+ private readonly int _hashCode ;
2225
2326 /// <summary> Construct a unique identifier for an entity class instance</summary>
2427 public EntityKey ( object id , IEntityPersister persister )
2528 {
2629 identifier = id ?? throw new AssertionFailure ( "null identifier" ) ;
2730 _persister = persister ;
31+ _hashCode = 0 ;
32+
2833 _hashCode = GenerateHashCode ( ) ;
2934 }
3035
3136 private EntityKey ( SerializationInfo info , StreamingContext context )
3237 {
38+ _hashCode = 0 ;
39+
3340 identifier = info . GetValue ( nameof ( Identifier ) , typeof ( object ) ) ;
41+ if ( identifier == null )
42+ {
43+ _persister = null ;
44+ return ;
45+ }
46+
3447 var factory = ( ISessionFactoryImplementor ) info . GetValue ( nameof ( _persister . Factory ) , typeof ( ISessionFactoryImplementor ) ) ;
35- var entityName = ( string ) info . GetValue ( nameof ( EntityName ) , typeof ( string ) ) ;
48+ var entityName = info . GetString ( nameof ( EntityName ) ) ;
49+
3650 _persister = factory . GetEntityPersister ( entityName ) ;
51+ _hashCode = GenerateHashCode ( ) ;
3752 }
3853
3954 public bool IsBatchLoadable => _persister . IsBatchLoadable ;
@@ -54,10 +69,8 @@ public override bool Equals(object other)
5469
5570 public bool Equals ( EntityKey other )
5671 {
57- if ( other == null )
58- {
59- return false ;
60- }
72+ if ( other . IsNull )
73+ return IsNull ;
6174
6275 return
6376 other . RootEntityName . Equals ( RootEntityName )
@@ -66,17 +79,7 @@ public bool Equals(EntityKey other)
6679
6780 public override int GetHashCode ( )
6881 {
69- // If the object is put in a set or dictionary during deserialization, the hashcode will not yet be
70- // computed. Compute the hashcode on the fly. So long as this happens only during deserialization, there
71- // will be no thread safety issues. For the hashcode to be always defined after deserialization, the
72- // deserialization callback is used.
73- return _hashCode ?? GenerateHashCode ( ) ;
74- }
75-
76- /// <inheritdoc />
77- public void OnDeserialization ( object sender )
78- {
79- _hashCode = GenerateHashCode ( ) ;
82+ return _hashCode ;
8083 }
8184
8285 private int GenerateHashCode ( )
@@ -99,6 +102,9 @@ public override string ToString()
99102 public void GetObjectData ( SerializationInfo info , StreamingContext context )
100103 {
101104 info . AddValue ( nameof ( Identifier ) , identifier ) ;
105+ if ( identifier == null )
106+ return ;
107+
102108 info . AddValue ( nameof ( _persister . Factory ) , _persister . Factory ) ;
103109 info . AddValue ( nameof ( EntityName ) , EntityName ) ;
104110 }
0 commit comments