3
3
using System . Security ;
4
4
using NHibernate . Impl ;
5
5
using NHibernate . Persister . Entity ;
6
- using NHibernate . Type ;
7
6
8
7
namespace NHibernate . Engine
9
8
{
@@ -12,28 +11,41 @@ namespace NHibernate.Engine
12
11
/// and the identifier space (eg. tablename)
13
12
/// </summary>
14
13
[ Serializable ]
15
- public sealed class EntityKey : IDeserializationCallback , ISerializable , IEquatable < EntityKey >
14
+ public struct EntityKey : ISerializable , IEquatable < EntityKey >
16
15
{
16
+ public static EntityKey Null { get ; } = new EntityKey ( ) ;
17
+
18
+ public bool IsNull => identifier == null ;
19
+ public bool IsNotNull => ! IsNull ;
20
+
17
21
private readonly object identifier ;
18
22
private readonly IEntityPersister _persister ;
19
23
// 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 ;
22
25
23
26
/// <summary> Construct a unique identifier for an entity class instance</summary>
24
27
public EntityKey ( object id , IEntityPersister persister )
25
28
{
26
29
identifier = id ?? throw new AssertionFailure ( "null identifier" ) ;
27
30
_persister = persister ;
28
- _hashCode = GenerateHashCode ( ) ;
31
+ _hashCode = GenerateHashCode ( persister , id ) ;
29
32
}
30
33
31
34
private EntityKey ( SerializationInfo info , StreamingContext context )
32
35
{
33
36
identifier = info . GetValue ( nameof ( Identifier ) , typeof ( object ) ) ;
37
+ if ( identifier == null )
38
+ {
39
+ _hashCode = 0 ;
40
+ _persister = null ;
41
+ return ;
42
+ }
43
+
34
44
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
+
36
47
_persister = factory . GetEntityPersister ( entityName ) ;
48
+ _hashCode = GenerateHashCode ( _persister , identifier ) ;
37
49
}
38
50
39
51
public bool IsBatchLoadable => _persister . IsBatchLoadable ;
@@ -54,10 +66,8 @@ public override bool Equals(object other)
54
66
55
67
public bool Equals ( EntityKey other )
56
68
{
57
- if ( other == null )
58
- {
59
- return false ;
60
- }
69
+ if ( other . IsNull )
70
+ return IsNull ;
61
71
62
72
return
63
73
other . RootEntityName . Equals ( RootEntityName )
@@ -66,26 +76,16 @@ public bool Equals(EntityKey other)
66
76
67
77
public override int GetHashCode ( )
68
78
{
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 ;
80
80
}
81
81
82
- private int GenerateHashCode ( )
82
+ private static int GenerateHashCode ( IEntityPersister persister , object id )
83
83
{
84
84
int result = 17 ;
85
85
unchecked
86
86
{
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 ) ;
89
89
}
90
90
return result ;
91
91
}
@@ -99,6 +99,9 @@ public override string ToString()
99
99
public void GetObjectData ( SerializationInfo info , StreamingContext context )
100
100
{
101
101
info . AddValue ( nameof ( Identifier ) , identifier ) ;
102
+ if ( identifier == null )
103
+ return ;
104
+
102
105
info . AddValue ( nameof ( _persister . Factory ) , _persister . Factory ) ;
103
106
info . AddValue ( nameof ( EntityName ) , EntityName ) ;
104
107
}
0 commit comments