33using System . Security ;
44using NHibernate . Impl ;
55using NHibernate . Persister . Entity ;
6- using NHibernate . Type ;
76
87namespace NHibernate . Engine
98{
@@ -12,28 +11,41 @@ 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 ;
28- _hashCode = GenerateHashCode ( ) ;
31+ _hashCode = GenerateHashCode ( persister , id ) ;
2932 }
3033
3134 private EntityKey ( SerializationInfo info , StreamingContext context )
3235 {
3336 identifier = info . GetValue ( nameof ( Identifier ) , typeof ( object ) ) ;
37+ if ( identifier == null )
38+ {
39+ _hashCode = 0 ;
40+ _persister = null ;
41+ return ;
42+ }
43+
3444 var factory = ( ISessionFactoryImplementor ) info . GetValue ( nameof ( _persister . Factory ) , typeof ( ISessionFactoryImplementor ) ) ;
35- var entityName = ( string ) info . GetValue ( nameof ( EntityName ) , typeof ( string ) ) ;
45+ var entityName = info . GetString ( nameof ( EntityName ) ) ;
46+
3647 _persister = factory . GetEntityPersister ( entityName ) ;
48+ _hashCode = GenerateHashCode ( _persister , identifier ) ;
3749 }
3850
3951 public bool IsBatchLoadable => _persister . IsBatchLoadable ;
@@ -54,10 +66,8 @@ public override bool Equals(object other)
5466
5567 public bool Equals ( EntityKey other )
5668 {
57- if ( other == null )
58- {
59- return false ;
60- }
69+ if ( other . IsNull )
70+ return IsNull ;
6171
6272 return
6373 other . RootEntityName . Equals ( RootEntityName )
@@ -66,39 +76,34 @@ public bool Equals(EntityKey other)
6676
6777 public override int GetHashCode ( )
6878 {
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 ( ) ;
79+ return _hashCode ;
8080 }
8181
82- private int GenerateHashCode ( )
82+ private static int GenerateHashCode ( IEntityPersister persister , object id )
8383 {
8484 int result = 17 ;
8585 unchecked
8686 {
87- result = 37 * result + RootEntityName . GetHashCode ( ) ;
88- result = 37 * result + _persister . IdentifierType . GetHashCode ( identifier , _persister . Factory ) ;
87+ result = 37 * result + persister . RootEntityName . GetHashCode ( ) ;
88+ result = 37 * result + persister . IdentifierType . GetHashCode ( id , persister . Factory ) ;
8989 }
9090 return result ;
9191 }
9292
9393 public override string ToString ( )
9494 {
95- return "EntityKey" + MessageHelper . InfoString ( _persister , Identifier , _persister . Factory ) ;
95+ return IsNull
96+ ? Util . StringHelper . NullObject
97+ : "EntityKey" + MessageHelper . InfoString ( _persister , Identifier , _persister ? . Factory ) ;
9698 }
9799
98100 [ SecurityCritical ]
99101 public void GetObjectData ( SerializationInfo info , StreamingContext context )
100102 {
101103 info . AddValue ( nameof ( Identifier ) , identifier ) ;
104+ if ( identifier == null )
105+ return ;
106+
102107 info . AddValue ( nameof ( _persister . Factory ) , _persister . Factory ) ;
103108 info . AddValue ( nameof ( EntityName ) , EntityName ) ;
104109 }
0 commit comments