Skip to content

Commit 15bf5ce

Browse files
committed
Convert EntityKey to struct
1 parent 109f085 commit 15bf5ce

14 files changed

+60
-37
lines changed

src/NHibernate/Action/EntityIdentityInsertAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public EntityIdentityInsertAction(object[] state, object instance, IEntityPersis
1919
: base(null, state, instance, persister, session)
2020
{
2121
this.isDelayed = isDelayed;
22-
delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : null;
22+
delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : EntityKey.Null;
2323
}
2424

2525
public object GeneratedId

src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ protected virtual async Task<object> PerformSaveAsync(object entity, object id,
150150
}
151151
else
152152
{
153-
key = null;
153+
key = EntityKey.Null;
154154
}
155155

156156
if (InvokeSaveLifecycle(entity, persister, source))
@@ -184,7 +184,7 @@ protected virtual async Task<object> PerformSaveOrReplicateAsync(object entity,
184184
cancellationToken.ThrowIfCancellationRequested();
185185
Validate(entity, persister, source);
186186

187-
object id = key == null ? null : key.Identifier;
187+
object id = key.IsNull ? null : key.Identifier;
188188

189189
bool shouldDelayIdentityInserts = !requiresImmediateIdAccess;
190190

src/NHibernate/Async/Event/Default/DefaultReplicateEventListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public virtual async Task OnReplicateAsync(ReplicateEvent @event, CancellationTo
102102
}
103103

104104
bool regenerate = persister.IsIdentifierAssignedByInsert; // prefer re-generation of identity!
105-
EntityKey key = regenerate ? null : source.GenerateEntityKey(id, persister);
105+
EntityKey key = regenerate ? EntityKey.Null : source.GenerateEntityKey(id, persister);
106106

107107
await (PerformSaveOrReplicateAsync(entity, key, persister, regenerate, replicationMode, source, true, cancellationToken)).ConfigureAwait(false);
108108
}

src/NHibernate/Async/Impl/MultiCriteriaImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ private async Task GetResultsFromDatabaseAsync(IList results, CancellationToken
185185

186186
object o =
187187
await (loader.GetRowFromResultSetAsync(reader, session, queryParameters, loader.GetLockModes(queryParameters.LockModes),
188-
null, hydratedObjects[i], keys, true,
188+
EntityKey.Null, hydratedObjects[i], keys, true,
189189
(persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false);
190190
if (createSubselects[i])
191191
{

src/NHibernate/Async/Loader/Loader.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ protected async Task<object> LoadSingleRowAsync(DbDataReader resultSet, ISession
118118
try
119119
{
120120
result =
121-
await (GetRowFromResultSetAsync(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), null,
121+
await (GetRowFromResultSetAsync(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), EntityKey.Null,
122122
hydratedObjects, new EntityKey[entitySpan], returnProxies, (persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false);
123123
}
124124
catch (OperationCanceledException) { throw; }
@@ -185,7 +185,7 @@ internal async Task<object> GetRowFromResultSetAsync(DbDataReader resultSet, ISe
185185
{
186186
object entity = row[i];
187187
var key = keys[i];
188-
if (entity == null && key != null && IsChildFetchEntity(i))
188+
if (entity == null && key.IsNotNull && IsChildFetchEntity(i))
189189
{
190190
// The entity was missing in the session, fallback on internal load (which will just yield a
191191
// proxy if the persister supports it).
@@ -564,7 +564,7 @@ private async Task<EntityKey> GetKeyFromResultSetAsync(int i, IEntityPersister p
564564
}
565565
}
566566

567-
return resultId == null ? null : session.GenerateEntityKey(resultId, persister);
567+
return resultId == null ? EntityKey.Null : session.GenerateEntityKey(resultId, persister);
568568
}
569569

570570
/// <summary>
@@ -620,7 +620,7 @@ private async Task<object[]> GetRowAsync(DbDataReader rs, ILoadable[] persisters
620620
object obj = null;
621621
EntityKey key = keys[i];
622622

623-
if (key == null)
623+
if (key.IsNull)
624624
{
625625
// do nothing
626626
/* TODO NH-1001 : if (persisters[i]...EntityType) is an OneToMany or a ManyToOne and
@@ -756,7 +756,7 @@ private async Task<object> InstanceNotYetLoadedAsync(DbDataReader dr, int i, ILo
756756

757757
string instanceClass = await (GetInstanceClassAsync(dr, i, persister, key.Identifier, session, cancellationToken)).ConfigureAwait(false);
758758

759-
if (optionalObjectKey != null && key.Equals(optionalObjectKey))
759+
if (optionalObjectKey.IsNotNull && key.Equals(optionalObjectKey))
760760
{
761761
// its the given optional object
762762
obj = optionalObject;

src/NHibernate/Engine/EntityEntry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public EntityKey EntityKey
215215
{
216216
get
217217
{
218-
if (cachedEntityKey == null)
218+
if (cachedEntityKey.IsNull)
219219
{
220220
if (id == null)
221221
throw new InvalidOperationException("cannot generate an EntityKey when id is null.");

src/NHibernate/Engine/EntityKey.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ namespace NHibernate.Engine
1212
/// and the identifier space (eg. tablename)
1313
/// </summary>
1414
[Serializable]
15-
public sealed class EntityKey : IDeserializationCallback, ISerializable, IEquatable<EntityKey>
15+
public struct EntityKey : ISerializable, IEquatable<EntityKey>
1616
{
17+
public static EntityKey Null { get; } = new EntityKey();
18+
19+
public bool IsNull => identifier == null;
20+
public bool IsNotNull => !IsNull;
21+
1722
private readonly object identifier;
1823
private readonly IEntityPersister _persister;
1924
// hashcode may vary among processes, they cannot be stored and have to be re-computed after deserialization
@@ -30,8 +35,16 @@ public EntityKey(object id, IEntityPersister persister)
3035
private EntityKey(SerializationInfo info, StreamingContext context)
3136
{
3237
identifier = info.GetValue(nameof(Identifier), typeof(object));
38+
if (identifier == null)
39+
{
40+
_hashCode = 0;
41+
_persister = null;
42+
return;
43+
}
44+
3345
var factory = (ISessionFactoryImplementor) info.GetValue(nameof(_persister.Factory), typeof(ISessionFactoryImplementor));
34-
var entityName = (string) info.GetValue(nameof(EntityName), typeof(string));
46+
var entityName = info.GetString(nameof(EntityName));
47+
3548
_persister = factory.GetEntityPersister(entityName);
3649
_hashCode = GenerateHashCode(_persister, identifier);
3750
}
@@ -54,10 +67,8 @@ public override bool Equals(object other)
5467

5568
public bool Equals(EntityKey other)
5669
{
57-
if (other == null)
58-
{
59-
return false;
60-
}
70+
if (other.IsNull)
71+
return IsNull;
6172

6273
return
6374
other.RootEntityName.Equals(RootEntityName)
@@ -82,13 +93,18 @@ private static int GenerateHashCode(IEntityPersister persister, object id)
8293

8394
public override string ToString()
8495
{
85-
return "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister.Factory);
96+
return IsNull
97+
? Util.StringHelper.NullObject
98+
: "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister?.Factory);
8699
}
87100

88101
[SecurityCritical]
89102
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
90103
{
91104
info.AddValue(nameof(Identifier), identifier);
105+
if (identifier == null)
106+
return;
107+
92108
info.AddValue(nameof(_persister.Factory), _persister.Factory);
93109
info.AddValue(nameof(EntityName), EntityName);
94110
}

src/NHibernate/Engine/StatefulPersistenceContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ public object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, En
784784
/// </summary>
785785
public object ProxyFor(IEntityPersister persister, EntityKey key, object impl)
786786
{
787-
if (!persister.HasProxy || key == null)
787+
if (!persister.HasProxy || key.IsNull)
788788
return impl;
789789

790790
INHibernateProxy proxy;

src/NHibernate/Event/Default/AbstractSaveEventListener.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ protected virtual object PerformSave(object entity, object id, IEntityPersister
177177
}
178178
else
179179
{
180-
key = null;
180+
key = EntityKey.Null;
181181
}
182182

183183
if (InvokeSaveLifecycle(entity, persister, source))
@@ -209,7 +209,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE
209209
{
210210
Validate(entity, persister, source);
211211

212-
object id = key == null ? null : key.Identifier;
212+
object id = key.IsNull ? null : key.Identifier;
213213

214214
bool shouldDelayIdentityInserts = !requiresImmediateIdAccess;
215215

src/NHibernate/Event/Default/DefaultReplicateEventListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public virtual void OnReplicate(ReplicateEvent @event)
9595
}
9696

9797
bool regenerate = persister.IsIdentifierAssignedByInsert; // prefer re-generation of identity!
98-
EntityKey key = regenerate ? null : source.GenerateEntityKey(id, persister);
98+
EntityKey key = regenerate ? EntityKey.Null : source.GenerateEntityKey(id, persister);
9999

100100
PerformSaveOrReplicate(entity, key, persister, regenerate, replicationMode, source, true);
101101
}

src/NHibernate/Impl/MultiCriteriaImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ private void GetResultsFromDatabase(IList results)
258258

259259
object o =
260260
loader.GetRowFromResultSet(reader, session, queryParameters, loader.GetLockModes(queryParameters.LockModes),
261-
null, hydratedObjects[i], keys, true,
261+
EntityKey.Null, hydratedObjects[i], keys, true,
262262
(persister, data) => cacheBatcher.AddToBatch(persister, data));
263263
if (createSubselects[i])
264264
{

src/NHibernate/Loader/Loader.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ protected object LoadSingleRow(DbDataReader resultSet, ISessionImplementor sessi
313313
try
314314
{
315315
result =
316-
GetRowFromResultSet(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), null,
316+
GetRowFromResultSet(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), EntityKey.Null,
317317
hydratedObjects, new EntityKey[entitySpan], returnProxies, (persister, data) => cacheBatcher.AddToBatch(persister, data));
318318
}
319319
catch (HibernateException)
@@ -347,7 +347,7 @@ internal static EntityKey GetOptionalObjectKey(QueryParameters queryParameters,
347347
}
348348
else
349349
{
350-
return null;
350+
return EntityKey.Null;
351351
}
352352
}
353353

@@ -392,7 +392,7 @@ internal object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor
392392
{
393393
object entity = row[i];
394394
var key = keys[i];
395-
if (entity == null && key != null && IsChildFetchEntity(i))
395+
if (entity == null && key.IsNotNull && IsChildFetchEntity(i))
396396
{
397397
// The entity was missing in the session, fallback on internal load (which will just yield a
398398
// proxy if the persister supports it).
@@ -567,7 +567,7 @@ private static ISet<EntityKey>[] Transpose(IList<EntityKey[]> keys)
567567
for (int i = 0; i < keys.Count; i++)
568568
{
569569
EntityKey key = keys[i][j];
570-
if (key != null)
570+
if (key.IsNotNull)
571571
{
572572
result[j].Add(key);
573573
}
@@ -587,7 +587,7 @@ internal void CreateSubselects(IList<EntityKey[]> keys, QueryParameters queryPar
587587
{
588588
for (int i = 0; i < rowKeys.Length; i++)
589589
{
590-
if (rowKeys[i] != null && subSelects[i] != null)
590+
if (rowKeys[i].IsNotNull && subSelects[i] != null)
591591
{
592592
session.PersistenceContext.BatchFetchQueue.AddSubselect(rowKeys[i], subSelects[i]);
593593
}
@@ -777,7 +777,7 @@ private void RegisterNonExists(EntityKey[] keys, ISessionImplementor session)
777777
if (owner > -1)
778778
{
779779
EntityKey ownerKey = keys[owner];
780-
if (keys[i] == null && ownerKey != null)
780+
if (keys[i].IsNull && ownerKey.IsNotNull)
781781
{
782782
bool isOneToOneAssociation = ownerAssociationTypes != null && ownerAssociationTypes[i] != null
783783
&& ownerAssociationTypes[i].IsOneToOne;
@@ -913,7 +913,7 @@ private EntityKey GetKeyFromResultSet(int i, IEntityPersister persister, object
913913
}
914914
}
915915

916-
return resultId == null ? null : session.GenerateEntityKey(resultId, persister);
916+
return resultId == null ? EntityKey.Null : session.GenerateEntityKey(resultId, persister);
917917
}
918918

919919
/// <summary>
@@ -967,7 +967,7 @@ private object[] GetRow(DbDataReader rs, ILoadable[] persisters, EntityKey[] key
967967
object obj = null;
968968
EntityKey key = keys[i];
969969

970-
if (key == null)
970+
if (key.IsNull)
971971
{
972972
// do nothing
973973
/* TODO NH-1001 : if (persisters[i]...EntityType) is an OneToMany or a ManyToOne and
@@ -1105,7 +1105,7 @@ private object InstanceNotYetLoaded(DbDataReader dr, int i, ILoadable persister,
11051105

11061106
string instanceClass = GetInstanceClass(dr, i, persister, key.Identifier, session);
11071107

1108-
if (optionalObjectKey != null && key.Equals(optionalObjectKey))
1108+
if (optionalObjectKey.IsNotNull && key.Equals(optionalObjectKey))
11091109
{
11101110
// its the given optional object
11111111
obj = optionalObject;

src/NHibernate/Proxy/AbstractLazyInitializer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ private void ErrorIfReadOnlySettingNotAvailable()
231231
private static EntityKey GenerateEntityKeyOrNull(object id, ISessionImplementor s, string entityName)
232232
{
233233
if (id == null || s == null || entityName == null)
234-
return null;
234+
return EntityKey.Null;
235235

236236
return s.GenerateEntityKey(id, s.Factory.GetEntityPersister(entityName));
237237
}
@@ -250,7 +250,7 @@ private void CheckTargetState()
250250
private object GetProxyOrNull()
251251
{
252252
EntityKey entityKey = GenerateEntityKeyOrNull(_id, _session, _entityName);
253-
if (entityKey != null && _session != null && _session.IsOpen)
253+
if (entityKey.IsNotNull && _session != null && _session.IsOpen)
254254
{
255255
return _session.PersistenceContext.GetProxy(entityKey);
256256
}
@@ -269,7 +269,7 @@ private void SetReadOnly(bool readOnly)
269269
if (initialized)
270270
{
271271
EntityKey key = GenerateEntityKeyOrNull(_id, _session, _entityName);
272-
if (key != null && _session.PersistenceContext.ContainsEntity(key))
272+
if (key.IsNotNull && _session.PersistenceContext.ContainsEntity(key))
273273
{
274274
_session.PersistenceContext.SetReadOnly(_target, readOnly);
275275
}

src/NHibernate/Util/StringHelper.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace NHibernate.Util
1010
/// <summary></summary>
1111
public static class StringHelper
1212
{
13+
internal const string NullObject = "(null)";
14+
1315
/// <summary>
1416
/// This allows for both CRLF and lone LF line separators.
1517
/// </summary>
@@ -396,9 +398,9 @@ public static bool BooleanValue(string value)
396398
return trimmed.Equals("true", StringComparison.OrdinalIgnoreCase) || trimmed.Equals("t", StringComparison.OrdinalIgnoreCase);
397399
}
398400

399-
private static string NullSafeToString(object obj)
401+
private static string NullSafeToString<T>(T obj)
400402
{
401-
return obj == null ? "(null)" : obj.ToString();
403+
return obj == null ? NullObject : obj.ToString();
402404
}
403405

404406
/// <summary>
@@ -407,6 +409,11 @@ private static string NullSafeToString(object obj)
407409
/// <param name="array"></param>
408410
/// <returns></returns>
409411
public static string ToString(object[] array)
412+
{
413+
return ToString<object>(array);
414+
}
415+
416+
internal static string ToString<T>(T[] array)
410417
{
411418
int len = array.Length;
412419

0 commit comments

Comments
 (0)