diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index d4fa4e5f508..9d64a18fcdd 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -14,6 +14,7 @@ net461;netcoreapp2.0 net461;netcoreapp2.0;netstandard2.0 + 7.3 NHibernate NHibernate.info diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index 613f61cdd69..465339c247a 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -1,6 +1,7 @@  + The Visual Basic Unit Tests for NHibernate. $(NhAppTargetFrameworks) true diff --git a/src/NHibernate/Action/EntityIdentityInsertAction.cs b/src/NHibernate/Action/EntityIdentityInsertAction.cs index b796bf2be77..65eea399b20 100644 --- a/src/NHibernate/Action/EntityIdentityInsertAction.cs +++ b/src/NHibernate/Action/EntityIdentityInsertAction.cs @@ -19,7 +19,7 @@ public EntityIdentityInsertAction(object[] state, object instance, IEntityPersis : base(null, state, instance, persister, session) { this.isDelayed = isDelayed; - delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : null; + delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : EntityKey.Empty; } public object GeneratedId diff --git a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs index 985ead87deb..bdad87ff871 100644 --- a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs @@ -150,7 +150,7 @@ protected virtual async Task PerformSaveAsync(object entity, object id, } else { - key = null; + key = EntityKey.Empty; } if (InvokeSaveLifecycle(entity, persister, source)) @@ -184,7 +184,7 @@ protected virtual async Task PerformSaveOrReplicateAsync(object entity, cancellationToken.ThrowIfCancellationRequested(); Validate(entity, persister, source); - object id = key == null ? null : key.Identifier; + object id = key.IsEmpty ? null : key.Identifier; bool shouldDelayIdentityInserts = !requiresImmediateIdAccess; diff --git a/src/NHibernate/Async/Event/Default/DefaultReplicateEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultReplicateEventListener.cs index 124f45d1755..23122e893bd 100644 --- a/src/NHibernate/Async/Event/Default/DefaultReplicateEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultReplicateEventListener.cs @@ -102,7 +102,7 @@ public virtual async Task OnReplicateAsync(ReplicateEvent @event, CancellationTo } bool regenerate = persister.IsIdentifierAssignedByInsert; // prefer re-generation of identity! - EntityKey key = regenerate ? null : source.GenerateEntityKey(id, persister); + EntityKey key = regenerate ? EntityKey.Empty : source.GenerateEntityKey(id, persister); await (PerformSaveOrReplicateAsync(entity, key, persister, regenerate, replicationMode, source, true, cancellationToken)).ConfigureAwait(false); } diff --git a/src/NHibernate/Async/Impl/MultiCriteriaImpl.cs b/src/NHibernate/Async/Impl/MultiCriteriaImpl.cs index 3f063cf00e6..3a067ba8498 100644 --- a/src/NHibernate/Async/Impl/MultiCriteriaImpl.cs +++ b/src/NHibernate/Async/Impl/MultiCriteriaImpl.cs @@ -185,7 +185,7 @@ private async Task GetResultsFromDatabaseAsync(IList results, CancellationToken object o = await (loader.GetRowFromResultSetAsync(reader, session, queryParameters, loader.GetLockModes(queryParameters.LockModes), - null, hydratedObjects[i], keys, true, + EntityKey.Empty, hydratedObjects[i], keys, true, (persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false); if (createSubselects[i]) { diff --git a/src/NHibernate/Async/Loader/Loader.cs b/src/NHibernate/Async/Loader/Loader.cs index bf7d06b1046..acc9382f3d2 100644 --- a/src/NHibernate/Async/Loader/Loader.cs +++ b/src/NHibernate/Async/Loader/Loader.cs @@ -118,7 +118,7 @@ protected async Task LoadSingleRowAsync(DbDataReader resultSet, ISession try { result = - await (GetRowFromResultSetAsync(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), null, + await (GetRowFromResultSetAsync(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), EntityKey.Empty, hydratedObjects, new EntityKey[entitySpan], returnProxies, (persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } @@ -185,7 +185,7 @@ internal async Task GetRowFromResultSetAsync(DbDataReader resultSet, ISe { object entity = row[i]; var key = keys[i]; - if (entity == null && key != null && IsChildFetchEntity(i)) + if (entity == null && key.IsNotEmpty && IsChildFetchEntity(i)) { // The entity was missing in the session, fallback on internal load (which will just yield a // proxy if the persister supports it). @@ -564,7 +564,7 @@ private async Task GetKeyFromResultSetAsync(int i, IEntityPersister p } } - return resultId == null ? null : session.GenerateEntityKey(resultId, persister); + return resultId == null ? EntityKey.Empty : session.GenerateEntityKey(resultId, persister); } /// @@ -620,7 +620,7 @@ private async Task GetRowAsync(DbDataReader rs, ILoadable[] persisters object obj = null; EntityKey key = keys[i]; - if (key == null) + if (key.IsEmpty) { // do nothing /* TODO NH-1001 : if (persisters[i]...EntityType) is an OneToMany or a ManyToOne and @@ -756,7 +756,7 @@ private async Task InstanceNotYetLoadedAsync(DbDataReader dr, int i, ILo string instanceClass = await (GetInstanceClassAsync(dr, i, persister, key.Identifier, session, cancellationToken)).ConfigureAwait(false); - if (optionalObjectKey != null && key.Equals(optionalObjectKey)) + if (optionalObjectKey.IsNotEmpty && key.Equals(optionalObjectKey)) { // its the given optional object obj = optionalObject; diff --git a/src/NHibernate/Engine/BatchFetchQueue.cs b/src/NHibernate/Engine/BatchFetchQueue.cs index 2a4c61160f4..07253bc51de 100644 --- a/src/NHibernate/Engine/BatchFetchQueue.cs +++ b/src/NHibernate/Engine/BatchFetchQueue.cs @@ -61,7 +61,7 @@ public void Clear() /// The entity key for which to locate any defined subselect fetch. /// The fetch descriptor; may return null if no subselect fetch queued for /// this entity key. - public SubselectFetch GetSubselect(EntityKey key) + public SubselectFetch GetSubselect(in EntityKey key) { SubselectFetch result; subselectsByEntityKey.TryGetValue(key, out result); @@ -73,7 +73,7 @@ public SubselectFetch GetSubselect(EntityKey key) /// /// The entity for which to register the subselect fetch. /// The fetch descriptor. - public void AddSubselect(EntityKey key, SubselectFetch subquery) + public void AddSubselect(in EntityKey key, SubselectFetch subquery) { subselectsByEntityKey[key] = subquery; } @@ -84,7 +84,7 @@ public void AddSubselect(EntityKey key, SubselectFetch subquery) /// call this after loading the entity, since we might still /// need to load its collections) /// - public void RemoveSubselect(EntityKey key) + public void RemoveSubselect(in EntityKey key) { subselectsByEntityKey.Remove(key); } @@ -111,7 +111,7 @@ public void ClearSubselects() /// referenced entity to be included in a batch even though it is /// already associated with the . /// - public void AddBatchLoadableEntityKey(EntityKey key) + public void AddBatchLoadableEntityKey(in EntityKey key) { if (key.IsBatchLoadable) { @@ -129,7 +129,7 @@ public void AddBatchLoadableEntityKey(EntityKey key) /// need to batch fetch it anymore, remove it from the queue /// if necessary /// - public void RemoveBatchLoadableEntityKey(EntityKey key) + public void RemoveBatchLoadableEntityKey(in EntityKey key) { if (key.IsBatchLoadable) { diff --git a/src/NHibernate/Engine/EntityEntry.cs b/src/NHibernate/Engine/EntityEntry.cs index ac702632adb..c485260bf8d 100644 --- a/src/NHibernate/Engine/EntityEntry.cs +++ b/src/NHibernate/Engine/EntityEntry.cs @@ -215,7 +215,7 @@ public EntityKey EntityKey { get { - if (cachedEntityKey == null) + if (cachedEntityKey.IsEmpty) { if (id == null) throw new InvalidOperationException("cannot generate an EntityKey when id is null."); diff --git a/src/NHibernate/Engine/EntityKey.cs b/src/NHibernate/Engine/EntityKey.cs index 443ca3e2d40..15c4fcddc7a 100644 --- a/src/NHibernate/Engine/EntityKey.cs +++ b/src/NHibernate/Engine/EntityKey.cs @@ -6,14 +6,18 @@ namespace NHibernate.Engine { - //TODO 6.0: Remove IDeserializationCallback interface /// /// A globally unique identifier of an instance, consisting of the user-visible identifier /// and the identifier space (eg. tablename) /// [Serializable] - public sealed class EntityKey : IDeserializationCallback, ISerializable, IEquatable + public readonly struct EntityKey : ISerializable, IEquatable { + public static EntityKey Empty { get; } = new EntityKey(); + + public bool IsEmpty => identifier == null; + public bool IsNotEmpty => !IsEmpty; + private readonly object identifier; private readonly IEntityPersister _persister; // hashcode may vary among processes, they cannot be stored and have to be re-computed after deserialization @@ -30,8 +34,16 @@ public EntityKey(object id, IEntityPersister persister) private EntityKey(SerializationInfo info, StreamingContext context) { identifier = info.GetValue(nameof(Identifier), typeof(object)); + if (identifier == null) + { + _hashCode = 0; + _persister = null; + return; + } + var factory = (ISessionFactoryImplementor) info.GetValue(nameof(_persister.Factory), typeof(ISessionFactoryImplementor)); - var entityName = (string) info.GetValue(nameof(EntityName), typeof(string)); + var entityName = info.GetString(nameof(EntityName)); + _persister = factory.GetEntityPersister(entityName); _hashCode = GenerateHashCode(_persister, identifier); } @@ -54,10 +66,8 @@ public override bool Equals(object other) public bool Equals(EntityKey other) { - if (other == null) - { - return false; - } + if (other.IsEmpty) + return IsEmpty; return other.RootEntityName.Equals(RootEntityName) @@ -82,19 +92,20 @@ private static int GenerateHashCode(IEntityPersister persister, object id) public override string ToString() { - return "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister.Factory); + return IsEmpty + ? Util.StringHelper.NullObject + : "EntityKey" + MessageHelper.InfoString(_persister, Identifier, _persister?.Factory); } [SecurityCritical] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue(nameof(Identifier), identifier); + if (identifier == null) + return; + info.AddValue(nameof(_persister.Factory), _persister.Factory); info.AddValue(nameof(EntityName), EntityName); } - - [Obsolete("IDeserializationCallback interface has no usages and will be removed in a future version")] - public void OnDeserialization(object sender) - {} } } diff --git a/src/NHibernate/Engine/IPersistenceContext.cs b/src/NHibernate/Engine/IPersistenceContext.cs index 3544bc2d3a9..c207b5e2e48 100644 --- a/src/NHibernate/Engine/IPersistenceContext.cs +++ b/src/NHibernate/Engine/IPersistenceContext.cs @@ -113,7 +113,7 @@ public partial interface IPersistenceContext /// an entry of NO_ROW here is interpreted as an exception /// /// - object[] GetCachedDatabaseSnapshot(EntityKey key); + object[] GetCachedDatabaseSnapshot(in EntityKey key); /// /// Get the values of the natural id fields as known to the underlying @@ -123,22 +123,22 @@ public partial interface IPersistenceContext object[] GetNaturalIdSnapshot(object id, IEntityPersister persister); /// Add a canonical mapping from entity key to entity instance - void AddEntity(EntityKey key, object entity); + void AddEntity(in EntityKey key, object entity); /// /// Get the entity instance associated with the given EntityKey /// - object GetEntity(EntityKey key); + object GetEntity(in EntityKey key); /// Is there an entity with the given key in the persistence context - bool ContainsEntity(EntityKey key); + bool ContainsEntity(in EntityKey key); /// /// Remove an entity from the session cache, also clear /// up other state associated with the entity, all except /// for the EntityEntry /// - object RemoveEntity(EntityKey key); + object RemoveEntity(in EntityKey key); /// Get an entity cached by unique key object GetEntity(EntityUniqueKey euk); @@ -216,9 +216,9 @@ EntityEntry AddEntry(object entity, Status status, object[] loadedState, object /// Attempts to check whether the given key represents an entity already loaded within the /// current session. /// - /// The entity reference against which to perform the uniqueness check. /// The entity key. - void CheckUniqueness(EntityKey key, object obj); + /// The entity reference against which to perform the uniqueness check. + void CheckUniqueness(in EntityKey key, object obj); /// /// If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy @@ -231,14 +231,14 @@ EntityEntry AddEntry(object entity, Status status, object[] loadedState, object /// The internal cache key for the proxied entity. /// (optional) the actual proxied entity instance. /// An appropriately narrowed instance. - object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, EntityKey key, object obj); + object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, in EntityKey key, object obj); /// /// Return the existing proxy associated with the given EntityKey, or the /// third argument (the entity associated with the key) if no proxy exists. Init /// the proxy to the target implementation, if necessary. /// - object ProxyFor(IEntityPersister persister, EntityKey key, object impl); + object ProxyFor(IEntityPersister persister,in EntityKey key, object impl); /// /// Return the existing proxy associated with the given EntityKey, or the @@ -326,13 +326,13 @@ EntityEntry AddEntry(object entity, Status status, object[] loadedState, object CollectionEntry GetCollectionEntryOrNull(object collection); /// Get an existing proxy by key - object GetProxy(EntityKey key); + object GetProxy(in EntityKey key); /// Add a proxy to the session cache - void AddProxy(EntityKey key, INHibernateProxy proxy); + void AddProxy(in EntityKey key, INHibernateProxy proxy); /// Remove a proxy from the session cache - object RemoveProxy(EntityKey key); + object RemoveProxy(in EntityKey key); /// Called before cascading int IncrementCascadeLevel(); @@ -360,10 +360,10 @@ EntityEntry AddEntry(object entity, Status status, object[] loadedState, object /// /// Record the fact that the association belonging to the keyed entity is null. /// - void AddNullProperty(EntityKey ownerKey, string propertyName); + void AddNullProperty(in EntityKey ownerKey, string propertyName); /// Is the association property belonging to the keyed entity null? - bool IsPropertyNull(EntityKey ownerKey, string propertyName); + bool IsPropertyNull(in EntityKey ownerKey, string propertyName); /// /// Change the read-only status of an entity (or proxy). @@ -398,7 +398,7 @@ EntityEntry AddEntry(object entity, Status status, object[] loadedState, object /// bool IsReadOnly(object entityOrProxy); - void ReplaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, object generatedId); + void ReplaceDelayedEntityIdentityInsertKeys(in EntityKey oldKey, object generatedId); /// Is in a two-phase load? bool IsLoadFinished { get; } @@ -425,7 +425,7 @@ public static EntityEntry AddEntity( object entity, Status status, object[] loadedState, - EntityKey entityKey, + in EntityKey entityKey, object version, LockMode lockMode, bool existsInDatabase, diff --git a/src/NHibernate/Engine/StatefulPersistenceContext.cs b/src/NHibernate/Engine/StatefulPersistenceContext.cs index 021bf96bd23..6254d7089e7 100644 --- a/src/NHibernate/Engine/StatefulPersistenceContext.cs +++ b/src/NHibernate/Engine/StatefulPersistenceContext.cs @@ -355,7 +355,7 @@ public object[] GetDatabaseSnapshot(object id, IEntityPersister persister) /// an entry of NO_ROW here is interpreted as an exception /// /// - public object[] GetCachedDatabaseSnapshot(EntityKey key) + public object[] GetCachedDatabaseSnapshot(in EntityKey key) { object snapshot; if (!entitySnapshotsByKey.TryGetValue(key, out snapshot)) @@ -418,7 +418,7 @@ public object[] GetNaturalIdSnapshot(object id, IEntityPersister persister) } /// Add a canonical mapping from entity key to entity instance - public void AddEntity(EntityKey key, object entity) + public void AddEntity(in EntityKey key, object entity) { entitiesByKey[key] = entity; BatchFetchQueue.RemoveBatchLoadableEntityKey(key); @@ -427,7 +427,7 @@ public void AddEntity(EntityKey key, object entity) /// /// Get the entity instance associated with the given EntityKey /// - public object GetEntity(EntityKey key) + public object GetEntity(in EntityKey key) { object result; entitiesByKey.TryGetValue(key, out result); @@ -435,7 +435,7 @@ public object GetEntity(EntityKey key) } /// Is there an entity with the given key in the persistence context - public bool ContainsEntity(EntityKey key) + public bool ContainsEntity(in EntityKey key) { return entitiesByKey.ContainsKey(key); } @@ -445,7 +445,7 @@ public bool ContainsEntity(EntityKey key) /// up other state associated with the entity, all except /// for the EntityEntry /// - public object RemoveEntity(EntityKey key) + public object RemoveEntity(in EntityKey key) { object tempObject = entitiesByKey[key]; entitiesByKey.Remove(key); @@ -525,7 +525,7 @@ public EntityEntry AddEntity(object entity, Status status, object[] loadedState, } /// Adds an entity to the internal caches. - public EntityEntry AddEntity(object entity, Status status, object[] loadedState, EntityKey entityKey, object version, + public EntityEntry AddEntity(object entity, Status status, object[] loadedState, in EntityKey entityKey, object version, LockMode lockMode, bool existsInDatabase, IEntityPersister persister, bool disableVersionIncrement) { @@ -712,9 +712,9 @@ public object UnproxyAndReassociate(object maybeProxy) /// Attempts to check whether the given key represents an entity already loaded within the /// current session. /// - /// The entity reference against which to perform the uniqueness check. /// The entity key. - public void CheckUniqueness(EntityKey key, object obj) + /// The entity reference against which to perform the uniqueness check. + public void CheckUniqueness(in EntityKey key, object obj) { object entity = GetEntity(key); if (entity == obj) @@ -738,7 +738,7 @@ public void CheckUniqueness(EntityKey key, object obj) /// The internal cache key for the proxied entity. /// (optional) the actual proxied entity instance. /// An appropriately narrowed instance. - public object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, EntityKey key, object obj) + public object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, in EntityKey key, object obj) { bool alreadyNarrow = persister.ConcreteProxyClass.IsInstanceOfType(proxy); @@ -782,9 +782,9 @@ public object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, En /// third argument (the entity associated with the key) if no proxy exists. Init /// the proxy to the target implementation, if necessary. /// - public object ProxyFor(IEntityPersister persister, EntityKey key, object impl) + public object ProxyFor(IEntityPersister persister, in EntityKey key, object impl) { - if (!persister.HasProxy || key == null) + if (!persister.HasProxy || key.IsEmpty) return impl; INHibernateProxy proxy; @@ -1076,7 +1076,7 @@ public CollectionEntry GetCollectionEntryOrNull(object collection) } /// Get an existing proxy by key - public object GetProxy(EntityKey key) + public object GetProxy(in EntityKey key) { INHibernateProxy result; if (proxiesByKey.TryGetValue(key, out result)) @@ -1086,13 +1086,13 @@ public object GetProxy(EntityKey key) } /// Add a proxy to the session cache - public void AddProxy(EntityKey key, INHibernateProxy proxy) + public void AddProxy(in EntityKey key, INHibernateProxy proxy) { proxiesByKey[key] = proxy; } /// Remove a proxy from the session cache - public object RemoveProxy(EntityKey key) + public object RemoveProxy(in EntityKey key) { if (batchFetchQueue != null) { @@ -1295,13 +1295,13 @@ private object GetIndexInParent(string property, object childEntity, IEntityPers /// /// Record the fact that the association belonging to the keyed entity is null. /// - public void AddNullProperty(EntityKey ownerKey, string propertyName) + public void AddNullProperty(in EntityKey ownerKey, string propertyName) { nullAssociations.Add(new AssociationKey(ownerKey, propertyName)); } /// Is the association property belonging to the keyed entity null? - public bool IsPropertyNull(EntityKey ownerKey, string propertyName) + public bool IsPropertyNull(in EntityKey ownerKey, string propertyName) { return nullAssociations.Contains(new AssociationKey(ownerKey, propertyName)); } @@ -1382,7 +1382,7 @@ public bool IsReadOnly(object entityOrProxy) return isReadOnly; } - public void ReplaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, object generatedId) + public void ReplaceDelayedEntityIdentityInsertKeys(in EntityKey oldKey, object generatedId) { object tempObject = entitiesByKey[oldKey]; entitiesByKey.Remove(oldKey); diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index f4fe501ab2e..7f1d40b5a2d 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -177,7 +177,7 @@ protected virtual object PerformSave(object entity, object id, IEntityPersister } else { - key = null; + key = EntityKey.Empty; } if (InvokeSaveLifecycle(entity, persister, source)) @@ -209,7 +209,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE { Validate(entity, persister, source); - object id = key == null ? null : key.Identifier; + object id = key.IsEmpty ? null : key.Identifier; bool shouldDelayIdentityInserts = !requiresImmediateIdAccess; diff --git a/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs b/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs index 5fa2dc26de7..1394d0be3d3 100644 --- a/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs @@ -95,7 +95,7 @@ public virtual void OnReplicate(ReplicateEvent @event) } bool regenerate = persister.IsIdentifierAssignedByInsert; // prefer re-generation of identity! - EntityKey key = regenerate ? null : source.GenerateEntityKey(id, persister); + EntityKey key = regenerate ? EntityKey.Empty : source.GenerateEntityKey(id, persister); PerformSaveOrReplicate(entity, key, persister, regenerate, replicationMode, source, true); } diff --git a/src/NHibernate/Impl/MultiCriteriaImpl.cs b/src/NHibernate/Impl/MultiCriteriaImpl.cs index 4920acc5306..f631abbb8a9 100644 --- a/src/NHibernate/Impl/MultiCriteriaImpl.cs +++ b/src/NHibernate/Impl/MultiCriteriaImpl.cs @@ -258,7 +258,7 @@ private void GetResultsFromDatabase(IList results) object o = loader.GetRowFromResultSet(reader, session, queryParameters, loader.GetLockModes(queryParameters.LockModes), - null, hydratedObjects[i], keys, true, + EntityKey.Empty, hydratedObjects[i], keys, true, (persister, data) => cacheBatcher.AddToBatch(persister, data)); if (createSubselects[i]) { diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index a89c9b9b007..56d210b2177 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -313,7 +313,7 @@ protected object LoadSingleRow(DbDataReader resultSet, ISessionImplementor sessi try { result = - GetRowFromResultSet(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), null, + GetRowFromResultSet(resultSet, session, queryParameters, GetLockModes(queryParameters.LockModes), EntityKey.Empty, hydratedObjects, new EntityKey[entitySpan], returnProxies, (persister, data) => cacheBatcher.AddToBatch(persister, data)); } catch (HibernateException) @@ -347,7 +347,7 @@ internal static EntityKey GetOptionalObjectKey(QueryParameters queryParameters, } else { - return null; + return EntityKey.Empty; } } @@ -392,7 +392,7 @@ internal object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor { object entity = row[i]; var key = keys[i]; - if (entity == null && key != null && IsChildFetchEntity(i)) + if (entity == null && key.IsNotEmpty && IsChildFetchEntity(i)) { // The entity was missing in the session, fallback on internal load (which will just yield a // proxy if the persister supports it). @@ -567,7 +567,7 @@ private static ISet[] Transpose(IList keys) for (int i = 0; i < keys.Count; i++) { EntityKey key = keys[i][j]; - if (key != null) + if (key.IsNotEmpty) { result[j].Add(key); } @@ -587,7 +587,7 @@ internal void CreateSubselects(IList keys, QueryParameters queryPar { for (int i = 0; i < rowKeys.Length; i++) { - if (rowKeys[i] != null && subSelects[i] != null) + if (rowKeys[i].IsNotEmpty && subSelects[i] != null) { session.PersistenceContext.BatchFetchQueue.AddSubselect(rowKeys[i], subSelects[i]); } @@ -777,7 +777,7 @@ private void RegisterNonExists(EntityKey[] keys, ISessionImplementor session) if (owner > -1) { EntityKey ownerKey = keys[owner]; - if (keys[i] == null && ownerKey != null) + if (keys[i].IsEmpty && ownerKey.IsNotEmpty) { bool isOneToOneAssociation = ownerAssociationTypes != null && ownerAssociationTypes[i] != null && ownerAssociationTypes[i].IsOneToOne; @@ -913,7 +913,7 @@ private EntityKey GetKeyFromResultSet(int i, IEntityPersister persister, object } } - return resultId == null ? null : session.GenerateEntityKey(resultId, persister); + return resultId == null ? EntityKey.Empty : session.GenerateEntityKey(resultId, persister); } /// @@ -967,7 +967,7 @@ private object[] GetRow(DbDataReader rs, ILoadable[] persisters, EntityKey[] key object obj = null; EntityKey key = keys[i]; - if (key == null) + if (key.IsEmpty) { // do nothing /* 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, string instanceClass = GetInstanceClass(dr, i, persister, key.Identifier, session); - if (optionalObjectKey != null && key.Equals(optionalObjectKey)) + if (optionalObjectKey.IsNotEmpty && key.Equals(optionalObjectKey)) { // its the given optional object obj = optionalObject; diff --git a/src/NHibernate/Proxy/AbstractLazyInitializer.cs b/src/NHibernate/Proxy/AbstractLazyInitializer.cs index ddc12f5398b..5b9a441a02d 100644 --- a/src/NHibernate/Proxy/AbstractLazyInitializer.cs +++ b/src/NHibernate/Proxy/AbstractLazyInitializer.cs @@ -231,7 +231,7 @@ private void ErrorIfReadOnlySettingNotAvailable() private static EntityKey GenerateEntityKeyOrNull(object id, ISessionImplementor s, string entityName) { if (id == null || s == null || entityName == null) - return null; + return EntityKey.Empty; return s.GenerateEntityKey(id, s.Factory.GetEntityPersister(entityName)); } @@ -250,7 +250,7 @@ private void CheckTargetState() private object GetProxyOrNull() { EntityKey entityKey = GenerateEntityKeyOrNull(_id, _session, _entityName); - if (entityKey != null && _session != null && _session.IsOpen) + if (entityKey.IsNotEmpty && _session != null && _session.IsOpen) { return _session.PersistenceContext.GetProxy(entityKey); } @@ -269,7 +269,7 @@ private void SetReadOnly(bool readOnly) if (initialized) { EntityKey key = GenerateEntityKeyOrNull(_id, _session, _entityName); - if (key != null && _session.PersistenceContext.ContainsEntity(key)) + if (key.IsNotEmpty && _session.PersistenceContext.ContainsEntity(key)) { _session.PersistenceContext.SetReadOnly(_target, readOnly); } diff --git a/src/NHibernate/Util/StringHelper.cs b/src/NHibernate/Util/StringHelper.cs index c80f1d85852..1a50abb5e53 100644 --- a/src/NHibernate/Util/StringHelper.cs +++ b/src/NHibernate/Util/StringHelper.cs @@ -10,6 +10,8 @@ namespace NHibernate.Util /// public static class StringHelper { + internal const string NullObject = "(null)"; + /// /// This allows for both CRLF and lone LF line separators. /// @@ -396,9 +398,9 @@ public static bool BooleanValue(string value) return trimmed.Equals("true", StringComparison.OrdinalIgnoreCase) || trimmed.Equals("t", StringComparison.OrdinalIgnoreCase); } - private static string NullSafeToString(object obj) + private static string NullSafeToString(T obj) { - return obj == null ? "(null)" : obj.ToString(); + return obj == null ? NullObject : obj.ToString(); } /// @@ -407,6 +409,11 @@ private static string NullSafeToString(object obj) /// /// public static string ToString(object[] array) + { + return ToString(array); + } + + internal static string ToString(T[] array) { int len = array.Length;