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,44 @@ 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 ;
31
+ _hashCode = 0 ;
32
+
28
33
_hashCode = GenerateHashCode ( ) ;
29
34
}
30
35
31
36
private EntityKey ( SerializationInfo info , StreamingContext context )
32
37
{
38
+ _hashCode = 0 ;
39
+
33
40
identifier = info . GetValue ( nameof ( Identifier ) , typeof ( object ) ) ;
41
+ if ( identifier == null )
42
+ {
43
+ _persister = null ;
44
+ return ;
45
+ }
46
+
34
47
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
+
36
50
_persister = factory . GetEntityPersister ( entityName ) ;
51
+ _hashCode = GenerateHashCode ( ) ;
37
52
}
38
53
39
54
public bool IsBatchLoadable => _persister . IsBatchLoadable ;
@@ -54,10 +69,8 @@ public override bool Equals(object other)
54
69
55
70
public bool Equals ( EntityKey other )
56
71
{
57
- if ( other == null )
58
- {
59
- return false ;
60
- }
72
+ if ( other . IsNull )
73
+ return IsNull ;
61
74
62
75
return
63
76
other . RootEntityName . Equals ( RootEntityName )
@@ -66,17 +79,7 @@ public bool Equals(EntityKey other)
66
79
67
80
public override int GetHashCode ( )
68
81
{
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 ;
80
83
}
81
84
82
85
private int GenerateHashCode ( )
@@ -99,6 +102,9 @@ public override string ToString()
99
102
public void GetObjectData ( SerializationInfo info , StreamingContext context )
100
103
{
101
104
info . AddValue ( nameof ( Identifier ) , identifier ) ;
105
+ if ( identifier == null )
106
+ return ;
107
+
102
108
info . AddValue ( nameof ( _persister . Factory ) , _persister . Factory ) ;
103
109
info . AddValue ( nameof ( EntityName ) , EntityName ) ;
104
110
}
0 commit comments