diff --git a/src/NHibernate.DomainModel/CustomPersister.cs b/src/NHibernate.DomainModel/CustomPersister.cs
index 47d6c9a7692..556eabbd021 100644
--- a/src/NHibernate.DomainModel/CustomPersister.cs
+++ b/src/NHibernate.DomainModel/CustomPersister.cs
@@ -316,8 +316,8 @@ public object Load(object id, object optionalObject, LockMode lockMode, ISession
Custom obj = (Custom)Instances[id];
if (obj != null)
{
- clone = (Custom)obj.Clone();
- TwoPhaseLoad.AddUninitializedEntity(new EntityKey(id, this, session.EntityMode), clone, this, LockMode.None, false,
+ clone = (Custom)obj.Clone();
+ TwoPhaseLoad.AddUninitializedEntity(session.GenerateEntityKey(id, this), clone, this, LockMode.None, false,
session);
TwoPhaseLoad.PostHydrate(this, id, new String[] {obj.Name}, null, clone, LockMode.None, false, session);
TwoPhaseLoad.InitializeEntity(clone, false, session, new PreLoadEvent((IEventSource) session),
diff --git a/src/NHibernate.Test/CacheTest/CacheFixture.cs b/src/NHibernate.Test/CacheTest/CacheFixture.cs
index 8c41063d7b9..dadc7008649 100644
--- a/src/NHibernate.Test/CacheTest/CacheFixture.cs
+++ b/src/NHibernate.Test/CacheTest/CacheFixture.cs
@@ -18,7 +18,7 @@ public void TestSimpleCache()
private CacheKey CreateCacheKey(string text)
{
- return new CacheKey(text, NHibernateUtil.String, "Foo", EntityMode.Poco, null);
+ return new CacheKey(text, NHibernateUtil.String, "Foo", EntityMode.Poco, null, null);
}
public void DoTestCache(ICacheProvider cacheProvider)
diff --git a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs
index d1a1d37299f..096ebb3ecf0 100644
--- a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs
+++ b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs
@@ -32,7 +32,7 @@ public void SecondLevelCachedCollectionsFiltering()
.GetCollectionPersister(typeof(Salesperson).FullName + ".Orders");
Assert.IsTrue(persister.HasCache, "No cache for collection");
CacheKey cacheKey =
- new CacheKey(testData.steveId, persister.KeyType, persister.Role, EntityMode.Poco, (ISessionFactoryImplementor) sessions);
+ new CacheKey(testData.steveId, persister.KeyType, persister.Role, EntityMode.Poco, null, (ISessionFactoryImplementor) sessions);
CollectionCacheEntry cachedData = (CollectionCacheEntry)persister.Cache.Cache.Get(cacheKey);
Assert.IsNotNull(cachedData, "collection was not in cache");
diff --git a/src/NHibernate/Action/CollectionAction.cs b/src/NHibernate/Action/CollectionAction.cs
index 7dc692bb99e..a28b28a8213 100644
--- a/src/NHibernate/Action/CollectionAction.cs
+++ b/src/NHibernate/Action/CollectionAction.cs
@@ -96,7 +96,7 @@ public virtual void BeforeExecutions()
// second-level cache invalidation only)
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, session.EntityMode, session.Factory);
+ CacheKey ck = session.GenerateCacheKey(key, persister.KeyType, persister.Role);
softLock = persister.Cache.Lock(ck, null);
}
}
@@ -120,7 +120,7 @@ public virtual AfterTransactionCompletionProcessDelegate AfterTransactionComplet
{
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(key, persister.KeyType, persister.Role);
persister.Cache.Release(ck, softLock);
}
});
@@ -138,7 +138,7 @@ protected internal void Evict()
{
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, session.EntityMode, session.Factory);
+ CacheKey ck = session.GenerateCacheKey(key, persister.KeyType, persister.Role);
persister.Cache.Evict(ck);
}
}
diff --git a/src/NHibernate/Action/CollectionUpdateAction.cs b/src/NHibernate/Action/CollectionUpdateAction.cs
index c56f9f5bb11..7c9c91b0b4c 100644
--- a/src/NHibernate/Action/CollectionUpdateAction.cs
+++ b/src/NHibernate/Action/CollectionUpdateAction.cs
@@ -130,7 +130,7 @@ public override AfterTransactionCompletionProcessDelegate AfterTransactionComple
// NH Different behavior: to support unlocking collections from the cache.(r3260)
if (Persister.HasCache)
{
- CacheKey ck = new CacheKey(Key, Persister.KeyType, Persister.Role, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
if (success)
{
diff --git a/src/NHibernate/Action/EntityDeleteAction.cs b/src/NHibernate/Action/EntityDeleteAction.cs
index a38b792e361..665a6cead8c 100644
--- a/src/NHibernate/Action/EntityDeleteAction.cs
+++ b/src/NHibernate/Action/EntityDeleteAction.cs
@@ -57,7 +57,7 @@ public override void Execute()
CacheKey ck;
if (persister.HasCache)
{
- ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, session.EntityMode, session.Factory);
+ ck = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
sLock = persister.Cache.Lock(ck, version);
}
else
@@ -83,7 +83,7 @@ public override void Execute()
}
entry.PostDelete();
- EntityKey key = new EntityKey(entry.Id, entry.Persister, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(entry.Id, entry.Persister);
persistenceContext.RemoveEntity(key);
persistenceContext.RemoveProxy(key);
@@ -131,7 +131,7 @@ protected override void AfterTransactionCompletionProcessImpl(bool success)
{
if (Persister.HasCache)
{
- CacheKey ck = new CacheKey(Id, Persister.IdentifierType, Persister.RootEntityName, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(Id, Persister.IdentifierType, Persister.RootEntityName);
Persister.Cache.Release(ck, sLock);
}
if (success)
diff --git a/src/NHibernate/Action/EntityIdentityInsertAction.cs b/src/NHibernate/Action/EntityIdentityInsertAction.cs
index c041cc2113d..114f6360bc8 100644
--- a/src/NHibernate/Action/EntityIdentityInsertAction.cs
+++ b/src/NHibernate/Action/EntityIdentityInsertAction.cs
@@ -41,7 +41,7 @@ private EntityKey GenerateDelayedEntityKey()
if (!isDelayed)
throw new HibernateException("Cannot request delayed entity-key for non-delayed post-insert-id generation");
- return new EntityKey(new DelayedPostInsertIdentifier(), Persister, Session.EntityMode);
+ return Session.GenerateEntityKey(new DelayedPostInsertIdentifier(), Persister);
}
}
diff --git a/src/NHibernate/Action/EntityInsertAction.cs b/src/NHibernate/Action/EntityInsertAction.cs
index 882ed904525..d4b450155be 100644
--- a/src/NHibernate/Action/EntityInsertAction.cs
+++ b/src/NHibernate/Action/EntityInsertAction.cs
@@ -84,7 +84,7 @@ public override void Execute()
CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance, session.EntityMode), version, session, instance);
cacheEntry = persister.CacheEntryStructure.Structure(ce);
- CacheKey ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
bool put = persister.Cache.Insert(ck, cacheEntry, version);
if (put && factory.Statistics.IsStatisticsEnabled)
@@ -108,7 +108,7 @@ protected override void AfterTransactionCompletionProcessImpl(bool success)
IEntityPersister persister = Persister;
if (success && IsCachePutEnabled(persister))
{
- CacheKey ck = new CacheKey(Id, persister.IdentifierType, persister.RootEntityName, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(Id, persister.IdentifierType, persister.RootEntityName);
bool put = persister.Cache.AfterInsert(ck, cacheEntry, version);
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
diff --git a/src/NHibernate/Action/EntityUpdateAction.cs b/src/NHibernate/Action/EntityUpdateAction.cs
index 4751a9a6d13..d361c48f3b6 100644
--- a/src/NHibernate/Action/EntityUpdateAction.cs
+++ b/src/NHibernate/Action/EntityUpdateAction.cs
@@ -70,7 +70,7 @@ public override void Execute()
CacheKey ck = null;
if (persister.HasCache)
{
- ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, session.EntityMode, factory);
+ ck = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
slock = persister.Cache.Lock(ck, previousVersion);
}
@@ -140,7 +140,7 @@ protected override void AfterTransactionCompletionProcessImpl(bool success)
IEntityPersister persister = Persister;
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(Id, persister.IdentifierType, persister.RootEntityName, Session.EntityMode, Session.Factory);
+ CacheKey ck = Session.GenerateCacheKey(Id, persister.IdentifierType, persister.RootEntityName);
if (success && cacheEntry != null)
{
diff --git a/src/NHibernate/Cache/CacheKey.cs b/src/NHibernate/Cache/CacheKey.cs
index af17ec233d4..ff6a11c1c3e 100644
--- a/src/NHibernate/Cache/CacheKey.cs
+++ b/src/NHibernate/Cache/CacheKey.cs
@@ -17,25 +17,27 @@ public class CacheKey
private readonly string entityOrRoleName;
private readonly int hashCode;
private readonly EntityMode entityMode;
+ private readonly string tenantId;
- ///
- /// Construct a new key for a collection or entity instance.
- /// Note that an entity name should always be the root entity
- /// name, not a subclass entity name.
- ///
- /// The identifier associated with the cached data
- /// The Hibernate type mapping
- /// The entity or collection-role name.
- /// The entiyt mode of the originating session
- /// The session factory for which we are caching
- public CacheKey(object id, IType type, string entityOrRoleName, EntityMode entityMode, ISessionFactoryImplementor factory)
- {
- key = id;
- this.type = type;
- this.entityOrRoleName = entityOrRoleName;
- this.entityMode = entityMode;
- hashCode = type.GetHashCode(key, entityMode, factory);
- }
+ ///
+ /// Construct a new key for a collection or entity instance.
+ /// Note that an entity name should always be the root entity
+ /// name, not a subclass entity name.
+ ///
+ /// The identifier associated with the cached data
+ /// The Hibernate type mapping
+ /// The entity or collection-role name.
+ /// The entiyt mode of the originating session
+ /// The session factory for which we are caching
+ public CacheKey(object id, IType type, string entityOrRoleName, EntityMode entityMode, string tenantId, ISessionFactoryImplementor factory)
+ {
+ key = id;
+ this.type = type;
+ this.entityOrRoleName = entityOrRoleName;
+ this.entityMode = entityMode;
+ this.tenantId = tenantId;
+ hashCode = type.GetHashCode(key, entityMode, factory);
+ }
//Mainly for SysCache and Memcache
public override String ToString()
diff --git a/src/NHibernate/Cfg/Environment.cs b/src/NHibernate/Cfg/Environment.cs
index 020742eedbd..cab6a711728 100644
--- a/src/NHibernate/Cfg/Environment.cs
+++ b/src/NHibernate/Cfg/Environment.cs
@@ -90,6 +90,9 @@ public static string Version
/// The EntityMode in which set the Session opened from the SessionFactory.
public const string DefaultEntityMode = "default_entity_mode";
+ /// The multi tenancy strategy to use
+ public const string MultiTenancyStrategy = "multi_tenancy_strategy";
+
///
/// When using an enhanced id generator and pooled optimizers (),
/// prefer interpreting the database value as the lower (lo) boundary. The default is to interpret it as the high boundary.
diff --git a/src/NHibernate/Cfg/MultiTenancyStrategy.cs b/src/NHibernate/Cfg/MultiTenancyStrategy.cs
new file mode 100644
index 00000000000..e8e0c1a31ca
--- /dev/null
+++ b/src/NHibernate/Cfg/MultiTenancyStrategy.cs
@@ -0,0 +1,51 @@
+
+namespace NHibernate.Cfg
+{
+ public enum MultiTenancyStrategy
+ {
+ ///
+ /// Multi-tenancy implemented by use of discriminator columns (i.e. tenantId)
+ ///
+ Discriminator,
+
+ ///
+ /// Tenant per-schema
+ ///
+ Schema,
+
+ ///
+ /// Tenant per-database
+ ///
+ Database,
+
+ ///
+ /// No multi-tenancy (default)
+ ///
+ None
+ }
+
+ public static class MultiTenancyStrategyParser
+ {
+ public const string DiscriminatorXmlName = "discriminator";
+ public const string SchemaXmlName = "per-schema";
+ public const string DatabaseXmlName = "per-database";
+ public const string NoneXmlName = "none";
+
+ public static MultiTenancyStrategy Convert(string value)
+ {
+ switch (value)
+ {
+ case NoneXmlName:
+ return MultiTenancyStrategy.None;
+ case SchemaXmlName:
+ throw new HibernateException("multi-tenancy strategies are not yet supported");
+ case DatabaseXmlName:
+ throw new HibernateException("multi-tenancy strategies are not yet supported");
+ case DiscriminatorXmlName:
+ throw new HibernateException("multi-tenancy strategies are not yet supported");
+ default:
+ throw new HibernateException(string.Format("unknown multi-tenancy strategy: {0}", value));
+ }
+ }
+ }
+}
diff --git a/src/NHibernate/Cfg/Settings.cs b/src/NHibernate/Cfg/Settings.cs
index 211e79b5e5d..6b7c5efdf79 100644
--- a/src/NHibernate/Cfg/Settings.cs
+++ b/src/NHibernate/Cfg/Settings.cs
@@ -48,7 +48,9 @@ public Settings()
public string DefaultSchemaName { get; set; }
- public string DefaultCatalogName { get; internal set; }
+ public string DefaultCatalogName { get; internal set; }
+
+ public MultiTenancyStrategy MultiTenancyStrategy { get; internal set; }
public string SessionFactoryName { get; internal set; }
diff --git a/src/NHibernate/Cfg/SettingsFactory.cs b/src/NHibernate/Cfg/SettingsFactory.cs
index 5383973f21f..41504b67fb8 100644
--- a/src/NHibernate/Cfg/SettingsFactory.cs
+++ b/src/NHibernate/Cfg/SettingsFactory.cs
@@ -109,7 +109,12 @@ public Settings BuildSettings(IDictionary properties)
if (defaultCatalog != null)
log.Info("Default catalog: " + defaultCatalog);
settings.DefaultSchemaName = defaultSchema;
- settings.DefaultCatalogName = defaultCatalog;
+ settings.DefaultCatalogName = defaultCatalog;
+
+ string multiTenancyStrategy = PropertiesHelper.GetString(
+ Environment.MultiTenancyStrategy, properties, MultiTenancyStrategyParser.NoneXmlName);
+ settings.MultiTenancyStrategy = MultiTenancyStrategyParser.Convert(multiTenancyStrategy);
+ log.Info("multi-tenancy strategy: " + multiTenancyStrategy);
int batchFetchSize = PropertiesHelper.GetInt32(Environment.DefaultBatchFetchSize, properties, 1);
log.Info("Default batch fetch size: " + batchFetchSize);
diff --git a/src/NHibernate/Engine/BatchFetchQueue.cs b/src/NHibernate/Engine/BatchFetchQueue.cs
index 89501701bdb..042085aeb45 100644
--- a/src/NHibernate/Engine/BatchFetchQueue.cs
+++ b/src/NHibernate/Engine/BatchFetchQueue.cs
@@ -167,7 +167,7 @@ public object[] GetCollectionBatch(ICollectionPersister collectionPersister, obj
end = i;
//checkForEnd = false;
}
- else if (!IsCached(ce.LoadedKey, collectionPersister, entityMode))
+ else if (!IsCached(ce.LoadedKey, collectionPersister))
{
keys[i++] = ce.LoadedKey;
//count++;
@@ -220,7 +220,7 @@ public object[] GetEntityBatch(IEntityPersister persister,object id,int batchSiz
}
else
{
- if (!IsCached(key, persister, entityMode))
+ if (!IsCached(key, persister))
{
ids[i++] = key.Identifier;
}
@@ -236,24 +236,21 @@ public object[] GetEntityBatch(IEntityPersister persister,object id,int batchSiz
return ids; //we ran out of ids to try
}
- private bool IsCached(EntityKey entityKey, IEntityPersister persister, EntityMode entityMode)
+ private bool IsCached(EntityKey entityKey, IEntityPersister persister)
{
if (persister.HasCache)
{
- CacheKey key =
- new CacheKey(entityKey.Identifier, persister.IdentifierType, entityKey.EntityName, entityMode,
- context.Session.Factory);
+ CacheKey key = context.Session.GenerateCacheKey(entityKey.Identifier, persister.IdentifierType, entityKey.EntityName);
return persister.Cache.Cache.Get(key) != null;
}
return false;
}
- private bool IsCached(object collectionKey, ICollectionPersister persister, EntityMode entityMode)
+ private bool IsCached(object collectionKey, ICollectionPersister persister)
{
if (persister.HasCache)
{
- CacheKey cacheKey =
- new CacheKey(collectionKey, persister.KeyType, persister.Role, entityMode, context.Session.Factory);
+ CacheKey cacheKey = context.Session.GenerateCacheKey(collectionKey, persister.KeyType, persister.Role);
return persister.Cache.Cache.Get(cacheKey) != null;
}
return false;
diff --git a/src/NHibernate/Engine/Collections.cs b/src/NHibernate/Engine/Collections.cs
index 0e792889843..ca40300ae32 100644
--- a/src/NHibernate/Engine/Collections.cs
+++ b/src/NHibernate/Engine/Collections.cs
@@ -60,7 +60,7 @@ private static void ProcessDereferencedCollection(IPersistentCollection coll, IS
// throw new AssertionFailure("Unable to determine collection owner identifier for orphan-delete processing");
// }
//}
- EntityKey key = new EntityKey(ownerId, loadedPersister.OwnerEntityPersister, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(ownerId, loadedPersister.OwnerEntityPersister);
object owner = persistenceContext.GetEntity(key);
if (owner == null)
{
diff --git a/src/NHibernate/Engine/EntityEntry.cs b/src/NHibernate/Engine/EntityEntry.cs
index 9320a9dc585..fd933cc582d 100644
--- a/src/NHibernate/Engine/EntityEntry.cs
+++ b/src/NHibernate/Engine/EntityEntry.cs
@@ -22,52 +22,55 @@ public sealed class EntityEntry
private object version;
[NonSerialized]
- private IEntityPersister persister; // for convenience to save some lookups
-
- private readonly EntityMode entityMode;
- private readonly string entityName;
- private EntityKey cachedEntityKey;
- private readonly bool isBeingReplicated;
- private readonly bool loadedWithLazyPropertiesUnfetched;
-
- [NonSerialized]
- private readonly object rowId;
-
- ///
- /// Initializes a new instance of EntityEntry.
- ///
- /// The current of the Entity.
- /// The snapshot of the Entity's state when it was loaded.
- ///
- /// The identifier of the Entity in the database.
- /// The version of the Entity.
- /// The for the Entity.
- /// A boolean indicating if the Entity exists in the database.
- /// The that is responsible for this Entity.
- ///
- ///
- ///
- internal EntityEntry(Status status, object[] loadedState, object rowId, object id, object version, LockMode lockMode,
- bool existsInDatabase, IEntityPersister persister, EntityMode entityMode,
- bool disableVersionIncrement, bool lazyPropertiesAreUnfetched)
- {
- this.status = status;
- this.previousStatus = null;
- // only retain loaded state if the status is not Status.ReadOnly
- if (status != Status.ReadOnly) { this.loadedState = loadedState; }
- this.id = id;
- this.rowId = rowId;
- this.existsInDatabase = existsInDatabase;
- this.version = version;
- this.lockMode = lockMode;
- isBeingReplicated = disableVersionIncrement;
- loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
- this.persister = persister;
- this.entityMode = entityMode;
- entityName = persister == null ? null : persister.EntityName;
- }
-
- ///
+ private IEntityPersister persister; // for convenience to save some lookups
+
+ private readonly EntityMode entityMode;
+ private readonly string tenantId;
+ private readonly string entityName;
+ private EntityKey cachedEntityKey;
+ private readonly bool isBeingReplicated;
+ private readonly bool loadedWithLazyPropertiesUnfetched;
+
+ [NonSerialized]
+ private readonly object rowId;
+
+ ///
+ /// Initializes a new instance of EntityEntry.
+ ///
+ /// The current of the Entity.
+ /// The snapshot of the Entity's state when it was loaded.
+ ///
+ /// The identifier of the Entity in the database.
+ /// The version of the Entity.
+ /// The for the Entity.
+ /// A boolean indicating if the Entity exists in the database.
+ /// The that is responsible for this Entity.
+ ///
+ /// The tenant for the current session
+ ///
+ ///
+ internal EntityEntry(Status status, object[] loadedState, object rowId, object id, object version, LockMode lockMode,
+ bool existsInDatabase, IEntityPersister persister, EntityMode entityMode, string tenantId,
+ bool disableVersionIncrement, bool lazyPropertiesAreUnfetched)
+ {
+ this.status = status;
+ this.previousStatus = null;
+ // only retain loaded state if the status is not Status.ReadOnly
+ if (status != Status.ReadOnly) { this.loadedState = loadedState; }
+ this.id = id;
+ this.rowId = rowId;
+ this.existsInDatabase = existsInDatabase;
+ this.version = version;
+ this.lockMode = lockMode;
+ isBeingReplicated = disableVersionIncrement;
+ loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
+ this.persister = persister;
+ this.entityMode = entityMode;
+ this.tenantId = tenantId;
+ entityName = persister == null ? null : persister.EntityName;
+ }
+
+ ///
/// Gets or sets the current of the Entity.
///
/// The of the Entity.
@@ -200,7 +203,7 @@ public EntityKey EntityKey
if (id == null)
throw new InvalidOperationException("cannot generate an EntityKey when id is null.");
- cachedEntityKey = new EntityKey(id, persister, entityMode);
+ cachedEntityKey = new EntityKey(id, persister, entityMode, tenantId);
}
return cachedEntityKey;
}
@@ -259,8 +262,8 @@ public void ForceLocked(object entity, object nextVersion)
}
public bool IsNullifiable(bool earlyInsert, ISessionImplementor session)
- {
- return Status == Status.Saving || (earlyInsert ? !ExistsInDatabase : session.PersistenceContext.NullifiableEntityKeys.Contains(new EntityKey(Id, Persister, entityMode)));
+ {
+ return Status == Status.Saving || (earlyInsert ? !ExistsInDatabase : session.PersistenceContext.NullifiableEntityKeys.Contains(session.GenerateEntityKey(Id, Persister)));
}
public bool RequiresDirtyCheck(object entity)
diff --git a/src/NHibernate/Engine/EntityKey.cs b/src/NHibernate/Engine/EntityKey.cs
index bc8a4682df3..53350e95254 100644
--- a/src/NHibernate/Engine/EntityKey.cs
+++ b/src/NHibernate/Engine/EntityKey.cs
@@ -16,40 +16,45 @@ public sealed class EntityKey
private readonly string rootEntityName;
private readonly string entityName;
private readonly IType identifierType;
- private readonly bool isBatchLoadable;
+ private readonly bool isBatchLoadable;
+ private readonly string tenantId;
[NonSerialized]
private ISessionFactoryImplementor factory;
private int hashCode;
- private readonly EntityMode entityMode;
-
- /// Construct a unique identifier for an entity class instance
- public EntityKey(object id, IEntityPersister persister, EntityMode entityMode)
- : this(id, persister.RootEntityName, persister.EntityName, persister.IdentifierType, persister.IsBatchLoadable, persister.Factory, entityMode) {}
-
- /// Used to reconstruct an EntityKey during deserialization.
- /// The identifier value
- /// The root entity name
- /// The specific entity name
- /// The type of the identifier value
- /// Whether represented entity is eligible for batch loading
- /// The session factory
- /// The entity's entity mode
- private EntityKey(object identifier, string rootEntityName, string entityName, IType identifierType, bool batchLoadable, ISessionFactoryImplementor factory, EntityMode entityMode)
- {
- if (identifier == null)
- throw new AssertionFailure("null identifier");
-
- this.identifier = identifier;
- this.rootEntityName = rootEntityName;
- this.entityName = entityName;
- this.identifierType = identifierType;
- isBatchLoadable = batchLoadable;
- this.factory = factory;
- this.entityMode = entityMode;
- hashCode = GenerateHashCode();
- }
+ private readonly EntityMode entityMode;
+
+ /// Construct a unique identifier for an entity class instance
+ ///
+ public EntityKey(object id, IEntityPersister persister, EntityMode entityMode, string tenantId)
+ : this(id, persister.RootEntityName, persister.EntityName, persister.IdentifierType, persister.IsBatchLoadable, persister.Factory, entityMode, tenantId) { }
+
+ /// Used to reconstruct an EntityKey during deserialization.
+ /// The identifier value
+ /// The root entity name
+ /// The specific entity name
+ /// The type of the identifier value
+ /// Whether represented entity is eligible for batch loading
+ /// The session factory
+ /// The entity's entity mode
+ /// The tenant identifier of the session to which this key belongs
+ private EntityKey(object identifier, string rootEntityName, string entityName, IType identifierType, bool batchLoadable, ISessionFactoryImplementor factory, EntityMode entityMode, string tenantId)
+ {
+ if (identifier == null)
+ throw new AssertionFailure("null identifier");
+
+ this.identifier = identifier;
+ this.rootEntityName = rootEntityName;
+ this.entityName = entityName;
+ this.identifierType = identifierType;
+ isBatchLoadable = batchLoadable;
+ this.factory = factory;
+ this.entityMode = entityMode;
+ this.tenantId = tenantId;
+ hashCode = GenerateHashCode();
+
+ }
public bool IsBatchLoadable
{
@@ -73,7 +78,8 @@ public override bool Equals(object other)
return
otherKey.rootEntityName.Equals(rootEntityName)
- && identifierType.IsEqual(otherKey.Identifier, Identifier, entityMode, factory);
+ && identifierType.IsEqual(otherKey.Identifier, Identifier, entityMode, factory)
+ && string.Equals(tenantId, otherKey.tenantId);
}
private int GenerateHashCode()
diff --git a/src/NHibernate/Engine/ISessionImplementor.cs b/src/NHibernate/Engine/ISessionImplementor.cs
index f6eed43ef2f..1daf21f244d 100644
--- a/src/NHibernate/Engine/ISessionImplementor.cs
+++ b/src/NHibernate/Engine/ISessionImplementor.cs
@@ -2,7 +2,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
-using NHibernate.AdoNet;
+using NHibernate.AdoNet;
+using NHibernate.Cache;
using NHibernate.Collection;
using NHibernate.Engine.Query.Sql;
using NHibernate.Event;
@@ -302,6 +303,15 @@ public interface ISessionImplementor
ITransactionContext TransactionContext { get; set; }
- void CloseSessionFromDistributedTransaction();
+ void CloseSessionFromDistributedTransaction();
+
+ ///
+ /// The tenant identifier of this session
+ ///
+ string TenantIdentifier { get; }
+
+ EntityKey GenerateEntityKey(object id, IEntityPersister persister);
+
+ CacheKey GenerateCacheKey(object id, IType type, string entityOrRoleName);
}
}
diff --git a/src/NHibernate/Engine/Loading/CollectionLoadContext.cs b/src/NHibernate/Engine/Loading/CollectionLoadContext.cs
index 34ab36ef59c..e6a69a1d22f 100644
--- a/src/NHibernate/Engine/Loading/CollectionLoadContext.cs
+++ b/src/NHibernate/Engine/Loading/CollectionLoadContext.cs
@@ -323,7 +323,7 @@ private void AddCollectionToCache(LoadingCollectionEntry lce, ICollectionPersist
}
CollectionCacheEntry entry = new CollectionCacheEntry(lce.Collection, persister);
- CacheKey cacheKey = new CacheKey(lce.Key, persister.KeyType, persister.Role, session.EntityMode, factory);
+ CacheKey cacheKey = session.GenerateCacheKey(lce.Key, persister.KeyType, persister.Role);
bool put = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry),
session.Timestamp, version, versionComparator,
factory.Settings.IsMinimalPutsEnabled && session.CacheMode != CacheMode.Refresh);
diff --git a/src/NHibernate/Engine/StatefulPersistenceContext.cs b/src/NHibernate/Engine/StatefulPersistenceContext.cs
index 349991b27c3..551f22fdaa4 100644
--- a/src/NHibernate/Engine/StatefulPersistenceContext.cs
+++ b/src/NHibernate/Engine/StatefulPersistenceContext.cs
@@ -330,7 +330,7 @@ public void AfterTransactionCompletion()
///
public object[] GetDatabaseSnapshot(object id, IEntityPersister persister)
{
- EntityKey key = new EntityKey(id, persister, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(id, persister);
object cached;
if (entitySnapshotsByKey.TryGetValue(key, out cached))
{
@@ -532,7 +532,7 @@ public EntityEntry AddEntry(object entity, Status status, object[] loadedState,
bool disableVersionIncrement, bool lazyPropertiesAreUnfetched)
{
EntityEntry e =
- new EntityEntry(status, loadedState, rowId, id, version, lockMode, existsInDatabase, persister, session.EntityMode,
+ new EntityEntry(status, loadedState, rowId, id, version, lockMode, existsInDatabase, persister, session.EntityMode, session.TenantIdentifier,
disableVersionIncrement, lazyPropertiesAreUnfetched);
entityEntries[entity] = e;
@@ -614,7 +614,7 @@ private void ReassociateProxy(ILazyInitializer li, INHibernateProxy proxy)
if (li.Session != Session)
{
IEntityPersister persister = session.Factory.GetEntityPersister(li.EntityName);
- EntityKey key = new EntityKey(li.Identifier, persister, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(li.Identifier, persister);
// any earlier proxy takes precedence
if (!proxiesByKey.ContainsKey(key))
{
@@ -777,13 +777,13 @@ public object ProxyFor(object impl)
{
EntityEntry e = GetEntry(impl);
IEntityPersister p = e.Persister;
- return ProxyFor(p, new EntityKey(e.Id, p, session.EntityMode), impl);
+ return ProxyFor(p, session.GenerateEntityKey(e.Id, p), impl);
}
/// Get the entity that owns this persistent collection
public object GetCollectionOwner(object key, ICollectionPersister collectionPersister)
{
- return GetEntity(new EntityKey(key, collectionPersister.OwnerEntityPersister, session.EntityMode));
+ return GetEntity(session.GenerateEntityKey(key, collectionPersister.OwnerEntityPersister));
}
/// Get the entity that owned this persistent collection when it was loaded
@@ -1351,7 +1351,7 @@ public void ReplaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, object gene
var oldEntry = (EntityEntry) tempObject2;
parentsByChild.Clear();
- var newKey = new EntityKey(generatedId, oldEntry.Persister, Session.EntityMode);
+ var newKey = Session.GenerateEntityKey(generatedId, oldEntry.Persister);
AddEntity(newKey, entity);
AddEntry(entity, oldEntry.Status, oldEntry.LoadedState, oldEntry.RowId, generatedId, oldEntry.Version,
oldEntry.LockMode, oldEntry.ExistsInDatabase, oldEntry.Persister, oldEntry.IsBeingReplicated,
diff --git a/src/NHibernate/Engine/TwoPhaseLoad.cs b/src/NHibernate/Engine/TwoPhaseLoad.cs
index 5bc30f4e616..ace3d277707 100644
--- a/src/NHibernate/Engine/TwoPhaseLoad.cs
+++ b/src/NHibernate/Engine/TwoPhaseLoad.cs
@@ -106,7 +106,7 @@ public static void InitializeEntity(object entity, bool readOnly, ISessionImplem
object version = Versioning.GetVersion(hydratedState, persister);
CacheEntry entry =
new CacheEntry(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity);
- CacheKey cacheKey = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, session.EntityMode, session.Factory);
+ CacheKey cacheKey = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
bool put =
persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version,
persister.IsVersioned ? persister.VersionType.Comparator : null,
diff --git a/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs b/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs
index e8b1ced368f..96db51e2388 100644
--- a/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs
+++ b/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs
@@ -47,7 +47,7 @@ protected virtual void UpgradeLock(object entity, EntityEntry entry, LockMode re
CacheKey ck;
if (persister.HasCache)
{
- ck = new CacheKey(entry.Id, persister.IdentifierType, persister.RootEntityName, source.EntityMode, source.Factory);
+ ck = source.GenerateCacheKey(entry.Id, persister.IdentifierType, persister.RootEntityName);
slock = persister.Cache.Lock(ck, entry.Version);
}
else
diff --git a/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs b/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs
index e5ce1fa5466..7e653829825 100644
--- a/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs
+++ b/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs
@@ -33,7 +33,7 @@ protected EntityEntry Reassociate(AbstractEvent @event, object entity, object id
}
IEventSource source = @event.Session;
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
source.PersistenceContext.CheckUniqueness(key, entity);
diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs
index fa8512a8f37..d7c94621c18 100644
--- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs
+++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs
@@ -160,7 +160,7 @@ protected virtual object PerformSave(object entity, object id, IEntityPersister
EntityKey key;
if (!useIdentityColumn)
{
- key = new EntityKey(id, persister, source.EntityMode);
+ key = source.GenerateEntityKey(id, persister);
object old = source.PersistenceContext.GetEntity(key);
if (old != null)
{
@@ -260,7 +260,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE
id = insert.GeneratedId;
//now done in EntityIdentityInsertAction
//persister.setIdentifier( entity, id, source.getEntityMode() );
- key = new EntityKey(id, persister, source.EntityMode);
+ key = source.GenerateEntityKey(id, persister);
source.PersistenceContext.CheckUniqueness(key, entity);
//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
}
diff --git a/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs b/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs
index 42d366efb23..96d38e5d5f2 100644
--- a/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs
@@ -65,7 +65,7 @@ public virtual void OnDelete(DeleteEvent @event, ISet transientEntities)
throw new TransientObjectException("the detached instance passed to delete() had a null identifier");
}
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
persistenceContext.CheckUniqueness(key, entity);
@@ -197,7 +197,7 @@ protected virtual void DeleteEntity(IEventSource session, object entity, EntityE
// before any callbacks, etc, so subdeletions see that this deletion happened first
persistenceContext.SetEntryStatus(entityEntry, Status.Deleted);
- EntityKey key = new EntityKey(entityEntry.Id, persister, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(entityEntry.Id, persister);
CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);
diff --git a/src/NHibernate/Event/Default/DefaultEvictEventListener.cs b/src/NHibernate/Event/Default/DefaultEvictEventListener.cs
index e3c2e561c6d..01dd86fe7ed 100644
--- a/src/NHibernate/Event/Default/DefaultEvictEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultEvictEventListener.cs
@@ -33,7 +33,7 @@ public virtual void OnEvict(EvictEvent @event)
{
throw new ArgumentException("null identifier");
}
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
persistenceContext.RemoveProxy(key);
if (!li.IsUninitialized)
{
diff --git a/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs b/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs
index acc80da7285..96cfa9859d1 100644
--- a/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs
@@ -522,7 +522,7 @@ private object[] GetDatabaseSnapshot(ISessionImplementor session, IEntityPersist
else
{
//TODO: optimize away this lookup for entities w/o unsaved-value="undefined"
- EntityKey entityKey = new EntityKey(id, persister, session.EntityMode);
+ EntityKey entityKey = session.GenerateEntityKey(id, persister);
return session.PersistenceContext.GetCachedDatabaseSnapshot(entityKey);
}
}
diff --git a/src/NHibernate/Event/Default/DefaultInitializeCollectionEventListener.cs b/src/NHibernate/Event/Default/DefaultInitializeCollectionEventListener.cs
index 0d391528ef5..78984ff134b 100644
--- a/src/NHibernate/Event/Default/DefaultInitializeCollectionEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultInitializeCollectionEventListener.cs
@@ -80,7 +80,7 @@ private bool InitializeCollectionFromCache(object id, ICollectionPersister persi
{
ISessionFactoryImplementor factory = source.Factory;
- CacheKey ck = new CacheKey(id, persister.KeyType, persister.Role, source.EntityMode, factory);
+ CacheKey ck = source.GenerateCacheKey(id, persister.KeyType, persister.Role);
object ce = persister.Cache.Get(ck, source.Timestamp);
if (factory.Statistics.IsStatisticsEnabled)
diff --git a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs
index e4e934ffd6b..a4669cdfbf3 100644
--- a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs
@@ -65,7 +65,7 @@ public virtual void OnLoad(LoadEvent @event, LoadType loadType)
}
}
- EntityKey keyToLoad = new EntityKey(@event.EntityId, persister, source.EntityMode);
+ EntityKey keyToLoad = source.GenerateEntityKey(@event.EntityId, persister);
try
{
if (loadType.IsNakedEntityReturned)
@@ -248,7 +248,7 @@ protected virtual object LockAndLoad(LoadEvent @event, IEntityPersister persiste
CacheKey ck;
if (persister.HasCache)
{
- ck = new CacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName, source.EntityMode, source.Factory);
+ ck = source.GenerateCacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName);
sLock = persister.Cache.Lock(ck, null);
}
else
@@ -420,7 +420,7 @@ protected virtual object LoadFromSecondLevelCache(LoadEvent @event, IEntityPersi
{
ISessionFactoryImplementor factory = source.Factory;
- CacheKey ck = new CacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName, source.EntityMode, factory);
+ CacheKey ck = source.GenerateCacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName);
object ce = persister.Cache.Get(ck, source.Timestamp);
if (factory.Statistics.IsStatisticsEnabled)
@@ -468,7 +468,7 @@ private object AssembleCacheEntry(CacheEntry entry, object id, IEntityPersister
object result = optionalObject ?? session.Instantiate(subclassPersister, id);
// make it circular-reference safe
- EntityKey entityKey = new EntityKey(id, subclassPersister, session.EntityMode);
+ EntityKey entityKey = session.GenerateEntityKey(id, subclassPersister);
TwoPhaseLoad.AddUninitializedCachedEntity(entityKey, result, subclassPersister, LockMode.None, entry.AreLazyPropertiesUnfetched, entry.Version, session);
IType[] types = subclassPersister.PropertyTypes;
diff --git a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs
index 68235a8d146..78f3dcd625f 100644
--- a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs
@@ -138,7 +138,7 @@ public virtual void OnMerge(MergeEvent @event, IDictionary copiedAlready)
object id = persister.GetIdentifier(entity, source.EntityMode);
if (id != null)
{
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
object managedEntity = source.PersistenceContext.GetEntity(key);
entry = source.PersistenceContext.GetEntry(managedEntity);
if (entry != null)
@@ -437,7 +437,7 @@ private static bool ExistsInDatabase(object entity, IEventSource source, IEntity
object id = persister.GetIdentifier(entity, source.EntityMode);
if (id != null)
{
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
object managedEntity = source.PersistenceContext.GetEntity(key);
entry = source.PersistenceContext.GetEntry(managedEntity);
}
diff --git a/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs b/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs
index 97cd2eeac56..b591b6d5308 100644
--- a/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs
@@ -56,7 +56,7 @@ public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready)
{
log.Debug("refreshing transient " + MessageHelper.InfoString(persister, id, source.Factory));
}
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
if (source.PersistenceContext.GetEntry(key) != null)
{
throw new PersistentObjectException("attempted to refresh transient instance when persistent instance was already associated with the Session: " +
@@ -84,7 +84,7 @@ public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready)
if (e != null)
{
- EntityKey key = new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(id, persister);
source.PersistenceContext.RemoveEntity(key);
if (persister.HasCollections)
new EvictVisitor(source).Process(obj, persister);
@@ -92,7 +92,7 @@ public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready)
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, source.EntityMode, source.Factory);
+ CacheKey ck = source.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
persister.Cache.Remove(ck);
}
diff --git a/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs b/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs
index bf48655d5cf..0d242538ff9 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 : new EntityKey(id, persister, source.EntityMode);
+ EntityKey key = regenerate ? null : source.GenerateEntityKey(id, persister);
PerformSaveOrReplicate(entity, key, persister, regenerate, replicationMode, source, true);
}
@@ -113,8 +113,8 @@ private void PerformReplication(object entity, object id, object version, IEntit
source.PersistenceContext.AddEntity(
entity,
persister.IsMutable ? Status.Loaded : Status.ReadOnly,
- null,
- new EntityKey(id, persister, source.EntityMode),
+ null,
+ source.GenerateEntityKey(id, persister),
version,
LockMode.None,
true,
diff --git a/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs b/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs
index e5d1c473bb8..cce3a374256 100644
--- a/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs
+++ b/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs
@@ -222,7 +222,7 @@ protected virtual void PerformUpdate(SaveOrUpdateEvent @event, object entity, IE
IEventSource source = @event.Session;
- EntityKey key = new EntityKey(@event.RequestedId, persister, source.EntityMode);
+ EntityKey key = source.GenerateEntityKey(@event.RequestedId, persister);
source.PersistenceContext.CheckUniqueness(key, entity);
diff --git a/src/NHibernate/Impl/AbstractSessionImpl.cs b/src/NHibernate/Impl/AbstractSessionImpl.cs
index 5ff5df6294f..0fdd0399627 100644
--- a/src/NHibernate/Impl/AbstractSessionImpl.cs
+++ b/src/NHibernate/Impl/AbstractSessionImpl.cs
@@ -3,6 +3,8 @@
using System.Collections.Generic;
using System.Data;
using NHibernate.AdoNet;
+using NHibernate.Cache;
+using NHibernate.Cfg;
using NHibernate.Collection;
using NHibernate.Engine;
using NHibernate.Engine.Query;
@@ -29,6 +31,21 @@ public abstract class AbstractSessionImpl : ISessionImplementor
private readonly Guid sessionId = Guid.NewGuid();
private bool closed;
+ private string _tenantIdentifier;
+ public string TenantIdentifier
+ {
+ get
+ {
+ return _tenantIdentifier;
+ }
+ set
+ {
+ if (MultiTenancyStrategy.None == factory.Settings.MultiTenancyStrategy)
+ throw new HibernateException("Sessionfactory was not configured for multi-tenancy");
+ _tenantIdentifier = value;
+ }
+ }
+
public ITransactionContext TransactionContext
{
get; set;
@@ -71,6 +88,21 @@ public void Initialize()
public abstract object ImmediateLoad(string entityName, object id);
public abstract long Timestamp { get; }
+ public EntityKey GenerateEntityKey(object id, IEntityPersister persister)
+ {
+ return GenerateEntityKey(id, persister, EntityMode);
+ }
+
+ public EntityKey GenerateEntityKey(object id, IEntityPersister persister, EntityMode entityMode)
+ {
+ return new EntityKey(id, persister, entityMode, TenantIdentifier);
+ }
+
+ public CacheKey GenerateCacheKey(object id, IType type, string entityOrRoleName)
+ {
+ return new CacheKey(id, type, entityOrRoleName, EntityMode, TenantIdentifier, Factory);
+ }
+
public ISessionFactoryImplementor Factory
{
get { return factory; }
diff --git a/src/NHibernate/Impl/SessionFactoryImpl.cs b/src/NHibernate/Impl/SessionFactoryImpl.cs
index 55dbbd06a5d..adbe84ee57c 100644
--- a/src/NHibernate/Impl/SessionFactoryImpl.cs
+++ b/src/NHibernate/Impl/SessionFactoryImpl.cs
@@ -819,8 +819,8 @@ public void Evict(System.Type persistentClass, object id)
if (log.IsDebugEnabled)
{
log.Debug("evicting second-level cache: " + MessageHelper.InfoString(p, id));
- }
- CacheKey ck = new CacheKey(id, p.IdentifierType, p.RootEntityName, EntityMode.Poco, this);
+ }
+ CacheKey ck = GenerateCacheKeyForEvict(id, p.IdentifierType, p.RootEntityName);
p.Cache.Remove(ck);
}
}
@@ -849,35 +849,54 @@ public void EvictEntity(string entityName)
}
p.Cache.Clear();
}
- }
-
- public void EvictEntity(string entityName, object id)
- {
- IEntityPersister p = GetEntityPersister(entityName);
- if (p.HasCache)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("evicting second-level cache: " + MessageHelper.InfoString(p, id, this));
- }
- CacheKey cacheKey = new CacheKey(id, p.IdentifierType, p.RootEntityName, EntityMode.Poco, this);
- p.Cache.Remove(cacheKey);
- }
- }
-
- public void EvictCollection(string roleName, object id)
- {
- ICollectionPersister p = GetCollectionPersister(roleName);
- if (p.HasCache)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("evicting second-level cache: " + MessageHelper.InfoString(p, id));
- }
- CacheKey ck = new CacheKey(id, p.KeyType, p.Role, EntityMode.Poco, this);
- p.Cache.Remove(ck);
- }
- }
+ }
+
+ public void EvictEntity(string entityName, object id)
+ {
+ IEntityPersister p = GetEntityPersister(entityName);
+ if (p.HasCache)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("evicting second-level cache: " + MessageHelper.InfoString(p, id, this));
+ }
+ CacheKey cacheKey = GenerateCacheKeyForEvict(id, p.IdentifierType, p.RootEntityName);
+ p.Cache.Remove(cacheKey);
+ }
+ }
+
+ public void EvictCollection(string roleName, object id)
+ {
+ ICollectionPersister p = GetCollectionPersister(roleName);
+ if (p.HasCache)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("evicting second-level cache: " + MessageHelper.InfoString(p, id));
+ }
+ CacheKey ck = GenerateCacheKeyForEvict(id, p.KeyType, p.Role);
+ p.Cache.Remove(ck);
+ }
+ }
+
+ private CacheKey GenerateCacheKeyForEvict(object id, IType type, string entityOrRoleName)
+ {
+ // if there is a session context, use that to generate the key (may be tenant-specific session)
+ if (CurrentSessionContext != null)
+ {
+ return CurrentSessionContext
+ .CurrentSession()
+ .GetSessionImplementation()
+ .GenerateCacheKey(id, type, entityOrRoleName);
+ }
+
+ if (MultiTenancyStrategy.None != Settings.MultiTenancyStrategy)
+ {
+ throw new ApplicationException("Could not find an open session. When using a multi-tenant Session Factory, a open session context is required to evict entities by id");
+ }
+ return new CacheKey(id, type, entityOrRoleName, EntityMode.Poco, null, this);
+
+ }
public void EvictCollection(string roleName)
{
diff --git a/src/NHibernate/Impl/StatelessSessionImpl.cs b/src/NHibernate/Impl/StatelessSessionImpl.cs
index 2fe64bf5554..e2e2278132b 100644
--- a/src/NHibernate/Impl/StatelessSessionImpl.cs
+++ b/src/NHibernate/Impl/StatelessSessionImpl.cs
@@ -70,7 +70,7 @@ public override object InternalLoad(string entityName, object id, bool eager, bo
{
CheckAndUpdateSessionStatus();
IEntityPersister persister = Factory.GetEntityPersister(entityName);
- object loaded = temporaryPersistenceContext.GetEntity(new EntityKey(id, persister, EntityMode.Poco));
+ object loaded = temporaryPersistenceContext.GetEntity(GenerateEntityKey(id, persister, EntityMode.Poco));
if (loaded != null)
{
return loaded;
@@ -827,7 +827,7 @@ public void Refresh(string entityName, object entity, LockMode lockMode)
if (persister.HasCache)
{
- CacheKey ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, EntityMode, Factory);
+ CacheKey ck = GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
persister.Cache.Remove(ck);
}
diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs
index e5c039e93b0..01a622e78e6 100644
--- a/src/NHibernate/Loader/Loader.cs
+++ b/src/NHibernate/Loader/Loader.cs
@@ -313,7 +313,7 @@ internal static EntityKey GetOptionalObjectKey(QueryParameters queryParameters,
if (optionalObject != null && !string.IsNullOrEmpty(optionalEntityName))
{
- return new EntityKey(optionalId, session.GetEntityPersister(optionalEntityName, optionalObject), session.EntityMode);
+ return session.GenerateEntityKey(optionalId, session.GetEntityPersister(optionalEntityName, optionalObject));
}
else
{
@@ -799,7 +799,7 @@ private EntityKey GetKeyFromResultSet(int i, IEntityPersister persister, object
}
}
- return resultId == null ? null : new EntityKey(resultId, persister, session.EntityMode);
+ return resultId == null ? null : session.GenerateEntityKey(resultId, persister);
}
///
diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj
index 5c4221830e1..49036787e23 100644
--- a/src/NHibernate/NHibernate.csproj
+++ b/src/NHibernate/NHibernate.csproj
@@ -125,13 +125,16 @@
+
+
+
diff --git a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
index c46f7e44cad..3988c1641eb 100644
--- a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
+++ b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
@@ -612,8 +612,8 @@ private ICollectionInitializer GetSubselectInitializer(object key, ISessionImple
IPersistenceContext persistenceContext = session.PersistenceContext;
- SubselectFetch subselect =
- persistenceContext.BatchFetchQueue.GetSubselect(new EntityKey(key, OwnerEntityPersister, session.EntityMode));
+ SubselectFetch subselect =
+ persistenceContext.BatchFetchQueue.GetSubselect(session.GenerateEntityKey(key, OwnerEntityPersister));
if (subselect == null)
{
diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
index cea61588399..6403da9be14 100644
--- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
+++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
@@ -1208,7 +1208,7 @@ public virtual object InitializeLazyProperty(string fieldName, object entity, IS
if (HasCache)
{
- CacheKey cacheKey = new CacheKey(id, IdentifierType, EntityName, session.EntityMode, Factory);
+ CacheKey cacheKey = session.GenerateCacheKey(id, IdentifierType, EntityName);
object ce = Cache.Get(cacheKey, session.Timestamp);
if (ce != null)
{
@@ -3076,7 +3076,7 @@ public void Delete(object id, object version, object obj, ISessionImplementor se
// first we need to locate the "loaded" state
//
// Note, it potentially could be a proxy, so perform the location the safe way...
- EntityKey key = new EntityKey(id, this, session.EntityMode);
+ EntityKey key = session.GenerateEntityKey(id, this);
object entity = session.PersistenceContext.GetEntity(key);
if (entity != null)
{
@@ -3719,7 +3719,7 @@ public virtual void AfterReassociate(object entity, ISessionImplementor session)
// check to see if it is in the second-level cache
if (HasCache)
{
- CacheKey ck = new CacheKey(id, IdentifierType, RootEntityName, session.EntityMode, session.Factory);
+ CacheKey ck = session.GenerateCacheKey(id, IdentifierType, RootEntityName);
if (Cache.Get(ck, session.Timestamp) != null)
return false;
}
diff --git a/src/NHibernate/Persister/Entity/NamedQueryLoader.cs b/src/NHibernate/Persister/Entity/NamedQueryLoader.cs
index 6dc46f0ba10..fd955f7538f 100644
--- a/src/NHibernate/Persister/Entity/NamedQueryLoader.cs
+++ b/src/NHibernate/Persister/Entity/NamedQueryLoader.cs
@@ -46,7 +46,7 @@ public object Load(object id, object optionalObject, ISessionImplementor session
// now look up the object we are really interested in!
// (this lets us correctly handle proxies and multi-row
// or multi-column queries)
- return session.PersistenceContext.GetEntity(new EntityKey(id, persister, session.EntityMode));
+ return session.PersistenceContext.GetEntity(session.GenerateEntityKey(id, persister));
}
}
}
\ No newline at end of file
diff --git a/src/NHibernate/Proxy/AbstractLazyInitializer.cs b/src/NHibernate/Proxy/AbstractLazyInitializer.cs
index 71f3f34a5bd..038acd30c9b 100644
--- a/src/NHibernate/Proxy/AbstractLazyInitializer.cs
+++ b/src/NHibernate/Proxy/AbstractLazyInitializer.cs
@@ -198,8 +198,8 @@ public object GetImplementation()
/// The Session to get the object from.
/// The Persistent Object this proxy is Proxying, or .
public object GetImplementation(ISessionImplementor s)
- {
- EntityKey key = new EntityKey(Identifier, s.Factory.GetEntityPersister(EntityName), s.EntityMode);
+ {
+ EntityKey key = s.GenerateEntityKey(Identifier, s.Factory.GetEntityPersister(EntityName));
return s.PersistenceContext.GetEntity(key);
}
@@ -247,9 +247,9 @@ private void ErrorIfReadOnlySettingNotAvailable()
private static EntityKey GenerateEntityKeyOrNull(object id, ISessionImplementor s, string entityName)
{
if (id == null || s == null || entityName == null)
- return null;
-
- return new EntityKey(id, s.Factory.GetEntityPersister(entityName), s.EntityMode);
+ return null;
+
+ return s.GenerateEntityKey(id, s.Factory.GetEntityPersister(entityName));
}
private void CheckTargetState()
diff --git a/src/NHibernate/Proxy/Poco/BasicLazyInitializer.cs b/src/NHibernate/Proxy/Poco/BasicLazyInitializer.cs
index 35e9f6d5ff3..a6f33a909e8 100644
--- a/src/NHibernate/Proxy/Poco/BasicLazyInitializer.cs
+++ b/src/NHibernate/Proxy/Poco/BasicLazyInitializer.cs
@@ -111,7 +111,7 @@ public virtual object Invoke(MethodInfo method, object[] args, object proxy)
if (Target == null & Session != null)
{
- EntityKey key = new EntityKey(Identifier, Session.Factory.GetEntityPersister(EntityName), Session.EntityMode);
+ EntityKey key = Session.GenerateEntityKey(Identifier, Session.Factory.GetEntityPersister(EntityName));
object entity = Session.PersistenceContext.GetEntity(key);
if (entity != null)
SetImplementation(entity);
diff --git a/src/NHibernate/Type/ManyToOneType.cs b/src/NHibernate/Type/ManyToOneType.cs
index 1b11d9dae07..c5744090372 100644
--- a/src/NHibernate/Type/ManyToOneType.cs
+++ b/src/NHibernate/Type/ManyToOneType.cs
@@ -92,7 +92,7 @@ private void ScheduleBatchLoadIfNeeded(object id, ISessionImplementor session)
if (uniqueKeyPropertyName == null && id != null)
{
IEntityPersister persister = session.Factory.GetEntityPersister(GetAssociatedEntityName());
- EntityKey entityKey = new EntityKey(id, persister, session.EntityMode);
+ EntityKey entityKey = session.GenerateEntityKey(id, persister);
if (!session.PersistenceContext.ContainsEntity(entityKey))
{
session.PersistenceContext.BatchFetchQueue.AddBatchLoadableEntityKey(entityKey);
diff --git a/src/NHibernate/Type/OneToOneType.cs b/src/NHibernate/Type/OneToOneType.cs
index c72db0af253..85da360128f 100644
--- a/src/NHibernate/Type/OneToOneType.cs
+++ b/src/NHibernate/Type/OneToOneType.cs
@@ -74,7 +74,7 @@ public override bool IsNull(object owner, ISessionImplementor session)
IEntityPersister ownerPersister = session.Factory.GetEntityPersister(entityName);
object id = session.GetContextEntityIdentifier(owner);
- EntityKey entityKey = new EntityKey(id, ownerPersister, session.EntityMode);
+ EntityKey entityKey = session.GenerateEntityKey(id, ownerPersister);
return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
}
@@ -103,8 +103,8 @@ public override object Hydrate(IDataReader rs, string[] names, ISessionImplement
{
object[] values = ownerIdType.GetPropertyValues(identifier, session);
object id = componentType.ResolveIdentifier(values, session, null);
- IEntityPersister persister = session.Factory.GetEntityPersister(type.ReturnedClass.FullName);
- var key = new EntityKey(id, persister, session.EntityMode);
+ IEntityPersister persister = session.Factory.GetEntityPersister(type.ReturnedClass.FullName);
+ var key = session.GenerateEntityKey(id, persister);
return session.PersistenceContext.GetEntity(key);
}
}