diff --git a/doc/reference/modules/configuration.xml b/doc/reference/modules/configuration.xml index 9a0a6df137a..57f6f8b1e3e 100644 --- a/doc/reference/modules/configuration.xml +++ b/doc/reference/modules/configuration.xml @@ -722,6 +722,24 @@ var session = sessions.OpenSession(conn); + + + query.throw_never_cached + + + Should queries set as cacheable raise an error if they reference an entity using the cache + (the default is enabled). + + eg. + true | false + + + Disabling this setting causes NHibernate to ignore the caching of such queries without + raising an error. Furthermore NHibernate will log a warning on cacheable queries + referencing an entity using the never cache strategy. + + + query.factory_class diff --git a/doc/reference/modules/performance.xml b/doc/reference/modules/performance.xml index 1cd041b08af..f44a5f6a9f8 100644 --- a/doc/reference/modules/performance.xml +++ b/doc/reference/modules/performance.xml @@ -733,8 +733,8 @@ using(var iter = session - ]]> @@ -742,8 +742,9 @@ using(var iter = session usage specifies the caching strategy: read-write, - nonstrict-read-write or - read-only + nonstrict-read-write, + read-only or + never @@ -824,6 +825,26 @@ using(var iter = session + + Strategy: never + + + By default, without a cache configuration, entities are not cacheable. But they may still be referenced + in cacheable queries, which results will then be cached according to the values these non cacheable + entities have. So, their data may be indirectly cached through cacheable queries. + + + + By using the cache strategy never, such indirect caching of these entities data will + be forbidden by NHibernate. Setting as cacheable a query referencing entities with strategy + never will be treated as an error by default. Alternatively, the + query.throw_never_cached setting can be + set to false: instead of raising an error, it will disable the query cache on such + queries, and log a warning. + + + + The following table shows which providers are compatible with which concurrency strategies. diff --git a/src/NHibernate.Test/App.config b/src/NHibernate.Test/App.config index 40cf748a495..6bbf371c023 100644 --- a/src/NHibernate.Test/App.config +++ b/src/NHibernate.Test/App.config @@ -38,6 +38,7 @@ true false + true true 1, false 0, yes 'Y', no 'N' 10 diff --git a/src/NHibernate.Test/Async/SecondLevelCacheTest/NeverCachedEntityTests.cs b/src/NHibernate.Test/Async/SecondLevelCacheTest/NeverCachedEntityTests.cs new file mode 100644 index 00000000000..bfcac5833ed --- /dev/null +++ b/src/NHibernate.Test/Async/SecondLevelCacheTest/NeverCachedEntityTests.cs @@ -0,0 +1,225 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using NHibernate.Cache; +using NHibernate.Cfg; +using NHibernate.Impl; +using NHibernate.Linq; +using NHibernate.Test.SecondLevelCacheTests; +using NSubstitute; +using NUnit.Framework; + +namespace NHibernate.Test.SecondLevelCacheTest +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class NeverCachedEntityTestsAsync : TestCase + { + protected override string CacheConcurrencyStrategy => null; + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { "SecondLevelCacheTest.Item.hbm.xml" }; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.CacheProvider, typeof(HashtableCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + } + + [Test] + public async Task NeverInvalidateEntitiesAsync() + { + var debugSessionFactory = (DebugSessionFactory) Sfi; + + var cache = Substitute.For(Sfi.Settings, new Dictionary()); + + var updateTimestampsCacheField = typeof(SessionFactoryImpl).GetField( + "updateTimestampsCache", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + + updateTimestampsCacheField.SetValue(debugSessionFactory.ActualFactory, cache); + + //"Received" assertions can not be used since the collection is reused and cleared between calls. + //The received args are cloned and stored + var preInvalidations = new List>(); + var invalidations = new List>(); + + await (cache.PreInvalidateAsync(Arg.Do>(x => preInvalidations.Add(x.ToList())), CancellationToken.None)); + await (cache.InvalidateAsync(Arg.Do>(x => invalidations.Add(x.ToList())), CancellationToken.None)); + + using (var session = OpenSession()) + { + List ids = new List(); + //Add NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in Enumerable.Range(1, 10)) + { + var item = new NeverItem { Name = "Abatay" }; + item.Childrens.Add(new NeverChildItem() + { + Name = "Child", + Parent = item + }); + await (session.SaveAsync(item)); + ids.Add(item.Id); + } + + await (tx.CommitAsync()); + } + + //Update NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in ids) + { + var item = await (session.GetAsync(i)); + item.Name = item.Id.ToString(); + } + + await (tx.CommitAsync()); + } + + //Delete NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in ids) + { + var item = await (session.GetAsync(i)); + await (session.DeleteAsync(item)); + } + + await (tx.CommitAsync()); + } + + //Update NeverItem using HQL + using (var tx = session.BeginTransaction()) + { + await (session.CreateQuery("UPDATE NeverItem SET Name='Test'").ExecuteUpdateAsync()); + + await (tx.CommitAsync()); + } + + //Update NeverItem using LINQ + using (var tx = session.BeginTransaction()) + { + await (session.Query() + .UpdateBuilder() + .Set(x => x.Name, "Test") + .UpdateAsync()); + + await (tx.CommitAsync()); + } + } + + //Should receive none preinvalidation when Cache is configured as never + Assert.That(preInvalidations, Has.Count.EqualTo(0)); + + //Should receive none invalidation when Cache is configured as never + Assert.That(invalidations, Has.Count.EqualTo(0)); + } + + [Test] + public async Task QueryCache_ThrowsExceptionAsync() + { + using (var session = OpenSession()) + { + //Linq + using (var tx = session.BeginTransaction()) + { + Assert.ThrowsAsync(() => session + .Query().WithOptions(x => x.SetCacheable(true)).ToListAsync()); + + await (tx.CommitAsync()); + } + + //Linq Multiple with error message we will quarantied that gets 2 class in error message + using (var tx = session.BeginTransaction()) + { + Assert.ThrowsAsync(() => session + .Query().Where(x => x.Childrens.Any()) + .WithOptions(x => x.SetCacheable(true)) + .ToListAsync(), + $"Never cached entity:{string.Join(", ", typeof(NeverItem).FullName, typeof(NeverChildItem).FullName)} cannot be used in cacheable query"); + + await (tx.CommitAsync()); + } + + //Hql + using (var tx = session.BeginTransaction()) + { + Assert.ThrowsAsync(() => session + .CreateQuery("from NeverItem").SetCacheable(true).ListAsync()); + + await (tx.CommitAsync()); + } + + //ICriteria + using (var tx = session.BeginTransaction()) + { + Assert.ThrowsAsync(() => session + .CreateCriteria() + .SetCacheable(true) + .ListAsync()); + + await (tx.CommitAsync()); + } + + //Native Sql + using (var tx = session.BeginTransaction()) + { + Assert.ThrowsAsync(() => session + .CreateSQLQuery("select * from NeverItem") + .AddSynchronizedQuerySpace("NeverItem") + .SetCacheable(true) + .ListAsync()); + + await (tx.CommitAsync()); + } + } + } + + [Test] + public async Task ShouldAutoFlushAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var e1 = new NeverItem { Name = "Abatay" }; + e1.Childrens.Add(new NeverChildItem() + { + Name = "Child", + Parent = e1 + }); + await (session.SaveAsync(e1)); + + var result = await ((from e in session.Query() + where e.Name == "Abatay" + select e).ToListAsync()); + + Assert.That(result.Count, Is.EqualTo(1)); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + s.Delete("from NeverItem"); + tx.Commit(); + } + } + } +} diff --git a/src/NHibernate.Test/CfgTest/EntityCacheUsageParserFixture.cs b/src/NHibernate.Test/CfgTest/EntityCacheUsageParserFixture.cs index 5470a59b1b6..5a12f674afd 100644 --- a/src/NHibernate.Test/CfgTest/EntityCacheUsageParserFixture.cs +++ b/src/NHibernate.Test/CfgTest/EntityCacheUsageParserFixture.cs @@ -13,6 +13,7 @@ public void CovertToString() Assert.That(EntityCacheUsageParser.ToString(EntityCacheUsage.ReadWrite), Is.EqualTo("read-write")); Assert.That(EntityCacheUsageParser.ToString(EntityCacheUsage.NonStrictReadWrite), Is.EqualTo("nonstrict-read-write")); Assert.That(EntityCacheUsageParser.ToString(EntityCacheUsage.Transactional), Is.EqualTo("transactional")); + Assert.That(EntityCacheUsageParser.ToString(EntityCacheUsage.Never), Is.EqualTo("never")); } [Test] @@ -22,6 +23,7 @@ public void Parse() Assert.That(EntityCacheUsageParser.Parse("read-write"), Is.EqualTo(EntityCacheUsage.ReadWrite)); Assert.That(EntityCacheUsageParser.Parse("nonstrict-read-write"), Is.EqualTo(EntityCacheUsage.NonStrictReadWrite)); Assert.That(EntityCacheUsageParser.Parse("transactional"), Is.EqualTo(EntityCacheUsage.Transactional)); + Assert.That(EntityCacheUsageParser.Parse("never"), Is.EqualTo(EntityCacheUsage.Never)); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DebugSessionFactory.cs b/src/NHibernate.Test/DebugSessionFactory.cs index 7643924119f..7eb551bb83f 100644 --- a/src/NHibernate.Test/DebugSessionFactory.cs +++ b/src/NHibernate.Test/DebugSessionFactory.cs @@ -316,6 +316,16 @@ ICollectionPersister ISessionFactoryImplementor.GetCollectionPersister(string ro return ActualFactory.GetCollectionPersister(role); } + public ISet GetEntityPersisters(ISet spaces) + { + return ActualFactory.GetEntityPersisters(spaces); + } + + public ISet GetCollectionPersisters(ISet spaces) + { + return ActualFactory.GetCollectionPersisters(spaces); + } + IType[] ISessionFactoryImplementor.GetReturnTypes(string queryString) { return ActualFactory.GetReturnTypes(queryString); diff --git a/src/NHibernate.Test/SecondLevelCacheTest/Item.hbm.xml b/src/NHibernate.Test/SecondLevelCacheTest/Item.hbm.xml index 1012fc499cb..f21a1de71ba 100644 --- a/src/NHibernate.Test/SecondLevelCacheTest/Item.hbm.xml +++ b/src/NHibernate.Test/SecondLevelCacheTest/Item.hbm.xml @@ -26,8 +26,32 @@ + + + + + + + + + + + + + + + + + + + + + + + select ai.Name, count(*) from AnotherItem ai group by ai.Name - \ No newline at end of file + diff --git a/src/NHibernate.Test/SecondLevelCacheTest/NeverCachedEntityTests.cs b/src/NHibernate.Test/SecondLevelCacheTest/NeverCachedEntityTests.cs new file mode 100644 index 00000000000..7c0ba5f3602 --- /dev/null +++ b/src/NHibernate.Test/SecondLevelCacheTest/NeverCachedEntityTests.cs @@ -0,0 +1,213 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using NHibernate.Cache; +using NHibernate.Cfg; +using NHibernate.Impl; +using NHibernate.Linq; +using NHibernate.Test.SecondLevelCacheTests; +using NSubstitute; +using NUnit.Framework; + +namespace NHibernate.Test.SecondLevelCacheTest +{ + [TestFixture] + public class NeverCachedEntityTests : TestCase + { + protected override string CacheConcurrencyStrategy => null; + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { "SecondLevelCacheTest.Item.hbm.xml" }; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.CacheProvider, typeof(HashtableCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + } + + [Test] + public void NeverInvalidateEntities() + { + var debugSessionFactory = (DebugSessionFactory) Sfi; + + var cache = Substitute.For(Sfi.Settings, new Dictionary()); + + var updateTimestampsCacheField = typeof(SessionFactoryImpl).GetField( + "updateTimestampsCache", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + + updateTimestampsCacheField.SetValue(debugSessionFactory.ActualFactory, cache); + + //"Received" assertions can not be used since the collection is reused and cleared between calls. + //The received args are cloned and stored + var preInvalidations = new List>(); + var invalidations = new List>(); + + cache.PreInvalidate(Arg.Do>(x => preInvalidations.Add(x.ToList()))); + cache.Invalidate(Arg.Do>(x => invalidations.Add(x.ToList()))); + + using (var session = OpenSession()) + { + List ids = new List(); + //Add NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in Enumerable.Range(1, 10)) + { + var item = new NeverItem { Name = "Abatay" }; + item.Childrens.Add(new NeverChildItem() + { + Name = "Child", + Parent = item + }); + session.Save(item); + ids.Add(item.Id); + } + + tx.Commit(); + } + + //Update NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in ids) + { + var item = session.Get(i); + item.Name = item.Id.ToString(); + } + + tx.Commit(); + } + + //Delete NeverItem + using (var tx = session.BeginTransaction()) + { + foreach (var i in ids) + { + var item = session.Get(i); + session.Delete(item); + } + + tx.Commit(); + } + + //Update NeverItem using HQL + using (var tx = session.BeginTransaction()) + { + session.CreateQuery("UPDATE NeverItem SET Name='Test'").ExecuteUpdate(); + + tx.Commit(); + } + + //Update NeverItem using LINQ + using (var tx = session.BeginTransaction()) + { + session.Query() + .UpdateBuilder() + .Set(x => x.Name, "Test") + .Update(); + + tx.Commit(); + } + } + + //Should receive none preinvalidation when Cache is configured as never + Assert.That(preInvalidations, Has.Count.EqualTo(0)); + + //Should receive none invalidation when Cache is configured as never + Assert.That(invalidations, Has.Count.EqualTo(0)); + } + + [Test] + public void QueryCache_ThrowsException() + { + using (var session = OpenSession()) + { + //Linq + using (var tx = session.BeginTransaction()) + { + Assert.Throws(() => session + .Query().WithOptions(x => x.SetCacheable(true)).ToList()); + + tx.Commit(); + } + + //Linq Multiple with error message we will quarantied that gets 2 class in error message + using (var tx = session.BeginTransaction()) + { + Assert.Throws(() => session + .Query().Where(x => x.Childrens.Any()) + .WithOptions(x => x.SetCacheable(true)) + .ToList(), + $"Never cached entity:{string.Join(", ", typeof(NeverItem).FullName, typeof(NeverChildItem).FullName)} cannot be used in cacheable query"); + + tx.Commit(); + } + + //Hql + using (var tx = session.BeginTransaction()) + { + Assert.Throws(() => session + .CreateQuery("from NeverItem").SetCacheable(true).List()); + + tx.Commit(); + } + + //ICriteria + using (var tx = session.BeginTransaction()) + { + Assert.Throws(() => session + .CreateCriteria() + .SetCacheable(true) + .List()); + + tx.Commit(); + } + + //Native Sql + using (var tx = session.BeginTransaction()) + { + Assert.Throws(() => session + .CreateSQLQuery("select * from NeverItem") + .AddSynchronizedQuerySpace("NeverItem") + .SetCacheable(true) + .List()); + + tx.Commit(); + } + } + } + + [Test] + public void ShouldAutoFlush() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var e1 = new NeverItem { Name = "Abatay" }; + e1.Childrens.Add(new NeverChildItem() + { + Name = "Child", + Parent = e1 + }); + session.Save(e1); + + var result = (from e in session.Query() + where e.Name == "Abatay" + select e).ToList(); + + Assert.That(result.Count, Is.EqualTo(1)); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + s.Delete("from NeverItem"); + tx.Commit(); + } + } + } +} diff --git a/src/NHibernate.Test/SecondLevelCacheTest/NeverItem.cs b/src/NHibernate.Test/SecondLevelCacheTest/NeverItem.cs new file mode 100644 index 00000000000..69ad34f2c24 --- /dev/null +++ b/src/NHibernate.Test/SecondLevelCacheTest/NeverItem.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.SecondLevelCacheTests +{ + public class NeverItem + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual string Description { get; set; } + + public virtual IList Childrens { get; set; } = new List(); + } + + public class NeverChildItem + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + + public virtual NeverItem Parent { get; set; } + } +} diff --git a/src/NHibernate/Action/BulkOperationCleanupAction.cs b/src/NHibernate/Action/BulkOperationCleanupAction.cs index edd5b8f20bd..5308d2834d7 100644 --- a/src/NHibernate/Action/BulkOperationCleanupAction.cs +++ b/src/NHibernate/Action/BulkOperationCleanupAction.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; using NHibernate.Engine; -using NHibernate.Metadata; +using NHibernate.Persister; using NHibernate.Persister.Entity; using IQueryable = NHibernate.Persister.Entity.IQueryable; @@ -14,34 +14,45 @@ namespace NHibernate.Action /// Implementation of BulkOperationCleanupAction. /// [Serializable] - public partial class BulkOperationCleanupAction : IAsyncExecutable, IAfterTransactionCompletionProcess + public partial class BulkOperationCleanupAction : IAsyncExecutable, IAfterTransactionCompletionProcess, ICacheableExecutable { private readonly ISessionImplementor session; private readonly HashSet affectedEntityNames = new HashSet(); private readonly HashSet affectedCollectionRoles = new HashSet(); - private readonly List spaces; + private readonly string[] spaces; + private readonly string[] queryCacheSpaces; public BulkOperationCleanupAction(ISessionImplementor session, IQueryable[] affectedQueryables) { this.session = session; - List tmpSpaces = new List(); - for (int i = 0; i < affectedQueryables.Length; i++) + var affectedSpaces = new HashSet(); + var affectedQueryCacheSpaces = new HashSet(); + foreach (var affectedQueryable in affectedQueryables) { - if (affectedQueryables[i].HasCache) + if (affectedQueryable.HasCache) { - affectedEntityNames.Add(affectedQueryables[i].EntityName); + affectedEntityNames.Add(affectedQueryable.EntityName); } - ISet roles = session.Factory.GetCollectionRolesByEntityParticipant(affectedQueryables[i].EntityName); + ISet roles = session.Factory.GetCollectionRolesByEntityParticipant(affectedQueryable.EntityName); if (roles != null) { affectedCollectionRoles.UnionWith(roles); } - for (int y = 0; y < affectedQueryables[i].QuerySpaces.Length; y++) + + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + var supportsQuerySpace = affectedQueryable.SupportsQueryCache(); + foreach (var querySpace in affectedQueryable.QuerySpaces) { - tmpSpaces.Add(affectedQueryables[i].QuerySpaces[y]); + affectedSpaces.Add(querySpace); + if (supportsQuerySpace) + { + affectedQueryCacheSpaces.Add(querySpace); + } } } - spaces = new List(tmpSpaces); + + spaces = affectedSpaces.ToArray(); + queryCacheSpaces = affectedQueryCacheSpaces.ToArray(); } /// @@ -52,50 +63,45 @@ public BulkOperationCleanupAction(ISessionImplementor session, ISet quer //from H3.2 TODO: cache the autodetected information and pass it in instead. this.session = session; - ISet tmpSpaces = new HashSet(querySpaces); - ISessionFactoryImplementor factory = session.Factory; - IDictionary acmd = factory.GetAllClassMetadata(); - foreach (KeyValuePair entry in acmd) + var affectedSpaces = new HashSet(querySpaces); + var affectedQueryCacheSpaces = new HashSet(); + + foreach (var persister in session.Factory.GetEntityPersisters(querySpaces)) { - string entityName = entry.Key; - IEntityPersister persister = factory.GetEntityPersister(entityName); - string[] entitySpaces = persister.QuerySpaces; + if (persister.HasCache) + { + affectedEntityNames.Add(persister.EntityName); + } + ISet roles = session.Factory.GetCollectionRolesByEntityParticipant(persister.EntityName); + if (roles != null) + { + affectedCollectionRoles.UnionWith(roles); + } - if (AffectedEntity(querySpaces, entitySpaces)) + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + var supportsQuerySpace = persister.SupportsQueryCache(); + foreach (var querySpace in persister.QuerySpaces) { - if (persister.HasCache) + affectedSpaces.Add(querySpace); + if (supportsQuerySpace) { - affectedEntityNames.Add(persister.EntityName); - } - ISet roles = session.Factory.GetCollectionRolesByEntityParticipant(persister.EntityName); - if (roles != null) - { - affectedCollectionRoles.UnionWith(roles); - } - for (int y = 0; y < entitySpaces.Length; y++) - { - tmpSpaces.Add(entitySpaces[y]); + affectedQueryCacheSpaces.Add(querySpace); } } } - spaces = new List(tmpSpaces); - } - - private bool AffectedEntity(ISet querySpaces, string[] entitySpaces) - { - if (querySpaces == null || (querySpaces.Count == 0)) - { - return true; - } - return entitySpaces.Any(querySpaces.Contains); + spaces = affectedSpaces.ToArray(); + queryCacheSpaces = affectedQueryCacheSpaces.ToArray(); } #region IExecutable Members + /// + public string[] QueryCacheSpaces => queryCacheSpaces; + public string[] PropertySpaces { - get { return spaces.ToArray(); } + get { return spaces; } } public void BeforeExecutions() diff --git a/src/NHibernate/Action/CollectionAction.cs b/src/NHibernate/Action/CollectionAction.cs index e676e7d4f18..4071211cdb8 100644 --- a/src/NHibernate/Action/CollectionAction.cs +++ b/src/NHibernate/Action/CollectionAction.cs @@ -5,7 +5,9 @@ using NHibernate.Collection; using NHibernate.Engine; using NHibernate.Impl; +using NHibernate.Persister; using NHibernate.Persister.Collection; +using NHibernate.Persister.Entity; using NHibernate.Util; namespace NHibernate.Action @@ -14,7 +16,12 @@ namespace NHibernate.Action /// Any action relating to insert/update/delete of a collection /// [Serializable] - public abstract partial class CollectionAction : IAsyncExecutable, IComparable, IDeserializationCallback, IAfterTransactionCompletionProcess + public abstract partial class CollectionAction : + IAsyncExecutable, + IComparable, + IDeserializationCallback, + IAfterTransactionCompletionProcess, + ICacheableExecutable { private readonly object key; [NonSerialized] private ICollectionPersister persister; @@ -79,6 +86,15 @@ protected internal ISessionImplementor Session #region IExecutable Members + public string[] QueryCacheSpaces + { + get + { + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + return persister.SupportsQueryCache() ? persister.CollectionSpaces : null; + } + } + /// /// What spaces (tables) are affected by this action? /// diff --git a/src/NHibernate/Action/EntityAction.cs b/src/NHibernate/Action/EntityAction.cs index 70b2b1e60c2..07bcf94f097 100644 --- a/src/NHibernate/Action/EntityAction.cs +++ b/src/NHibernate/Action/EntityAction.cs @@ -5,6 +5,7 @@ using NHibernate.Persister.Entity; using NHibernate.Util; using NHibernate.Impl; +using NHibernate.Persister; namespace NHibernate.Action { @@ -18,7 +19,8 @@ public abstract partial class EntityAction : IBeforeTransactionCompletionProcess, IAfterTransactionCompletionProcess, IComparable, - IDeserializationCallback + IDeserializationCallback, + ICacheableExecutable { private readonly string entityName; private readonly object id; @@ -95,6 +97,15 @@ public IEntityPersister Persister #region IExecutable Members + public string[] QueryCacheSpaces + { + get + { + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + return persister.SupportsQueryCache() ? persister.PropertySpaces : null; + } + } + public string[] PropertySpaces { get { return persister.PropertySpaces; } diff --git a/src/NHibernate/Action/ICacheableExecutable.cs b/src/NHibernate/Action/ICacheableExecutable.cs new file mode 100644 index 00000000000..6f20df92f18 --- /dev/null +++ b/src/NHibernate/Action/ICacheableExecutable.cs @@ -0,0 +1,11 @@ +namespace NHibernate.Action +{ + //6.0 TODO: Merge to IExecutable + public interface ICacheableExecutable : IExecutable + { + /// + /// The query cache spaces (tables) which are affected by this action. + /// + string[] QueryCacheSpaces { get; } + } +} diff --git a/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs b/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs index 18d4553f24f..8c5201de202 100644 --- a/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs +++ b/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs @@ -14,13 +14,13 @@ using System.Threading; using System.Threading.Tasks; using NHibernate.Engine; -using NHibernate.Metadata; +using NHibernate.Persister; using NHibernate.Persister.Entity; using IQueryable = NHibernate.Persister.Entity.IQueryable; namespace NHibernate.Action { - public partial class BulkOperationCleanupAction : IAsyncExecutable, IAfterTransactionCompletionProcess + public partial class BulkOperationCleanupAction : IAsyncExecutable, IAfterTransactionCompletionProcess, ICacheableExecutable { #region IExecutable Members diff --git a/src/NHibernate/Async/Action/CollectionAction.cs b/src/NHibernate/Async/Action/CollectionAction.cs index 237d2c34afe..3c98605cda5 100644 --- a/src/NHibernate/Async/Action/CollectionAction.cs +++ b/src/NHibernate/Async/Action/CollectionAction.cs @@ -15,14 +15,21 @@ using NHibernate.Collection; using NHibernate.Engine; using NHibernate.Impl; +using NHibernate.Persister; using NHibernate.Persister.Collection; +using NHibernate.Persister.Entity; using NHibernate.Util; namespace NHibernate.Action { using System.Threading.Tasks; using System.Threading; - public abstract partial class CollectionAction : IAsyncExecutable, IComparable, IDeserializationCallback, IAfterTransactionCompletionProcess + public abstract partial class CollectionAction : + IAsyncExecutable, + IComparable, + IDeserializationCallback, + IAfterTransactionCompletionProcess, + ICacheableExecutable { protected async Task GetKeyAsync(CancellationToken cancellationToken) diff --git a/src/NHibernate/Async/Action/EntityAction.cs b/src/NHibernate/Async/Action/EntityAction.cs index a61ececcf29..26ae269b5cf 100644 --- a/src/NHibernate/Async/Action/EntityAction.cs +++ b/src/NHibernate/Async/Action/EntityAction.cs @@ -15,6 +15,7 @@ using NHibernate.Persister.Entity; using NHibernate.Util; using NHibernate.Impl; +using NHibernate.Persister; namespace NHibernate.Action { @@ -25,7 +26,8 @@ public abstract partial class EntityAction : IBeforeTransactionCompletionProcess, IAfterTransactionCompletionProcess, IComparable, - IDeserializationCallback + IDeserializationCallback, + ICacheableExecutable { #region IExecutable Members diff --git a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 8c78a478fca..9a34ba265f4 100644 --- a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -23,6 +23,7 @@ using NHibernate.Hql.Ast.ANTLR.Util; using NHibernate.Loader.Hql; using NHibernate.Param; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.SqlCommand; using NHibernate.Type; diff --git a/src/NHibernate/Async/Loader/Custom/CustomLoader.cs b/src/NHibernate/Async/Loader/Custom/CustomLoader.cs index 2e55c92a8ba..5f12f5314c9 100644 --- a/src/NHibernate/Async/Loader/Custom/CustomLoader.cs +++ b/src/NHibernate/Async/Loader/Custom/CustomLoader.cs @@ -22,6 +22,7 @@ using NHibernate.Transform; using NHibernate.Type; using IQueryable = NHibernate.Persister.Entity.IQueryable; +using NHibernate.Persister; namespace NHibernate.Loader.Custom { diff --git a/src/NHibernate/Async/Loader/Loader.cs b/src/NHibernate/Async/Loader/Loader.cs index a8a235d48c3..7629989c0ae 100644 --- a/src/NHibernate/Async/Loader/Loader.cs +++ b/src/NHibernate/Async/Loader/Loader.cs @@ -28,6 +28,7 @@ using NHibernate.Hql.Util; using NHibernate.Impl; using NHibernate.Param; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Proxy; diff --git a/src/NHibernate/Async/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Async/Persister/Collection/AbstractCollectionPersister.cs index da37c811661..3c7358c48d7 100644 --- a/src/NHibernate/Async/Persister/Collection/AbstractCollectionPersister.cs +++ b/src/NHibernate/Async/Persister/Collection/AbstractCollectionPersister.cs @@ -39,8 +39,14 @@ namespace NHibernate.Persister.Collection { using System.Threading.Tasks; using System.Threading; - public abstract partial class AbstractCollectionPersister : ICollectionMetadata, ISqlLoadableCollection, - IPostInsertIdentityPersister, ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable + public abstract partial class AbstractCollectionPersister : + ICollectionMetadata, + ISqlLoadableCollection, + IPostInsertIdentityPersister, + ISupportSelectModeJoinable, + ICompositeKeyPostInsertIdentityPersister, + ISupportLazyPropsJoinable, + IPersister { public Task InitializeAsync(object key, ISessionImplementor session, CancellationToken cancellationToken) diff --git a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs index d2d859aeff5..d5005ea10af 100644 --- a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs @@ -45,7 +45,8 @@ namespace NHibernate.Persister.Entity using System.Threading; public abstract partial class AbstractEntityPersister : IOuterJoinLoadable, IQueryable, IClassMetadata, IUniqueKeyLoadable, ISqlLoadable, ILazyPropertyInitializer, IPostInsertIdentityPersister, ILockable, - ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable + ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable, + IPersister { private partial class GeneratedIdentifierBinder : IBinder diff --git a/src/NHibernate/Cache/CacheFactory.cs b/src/NHibernate/Cache/CacheFactory.cs index 96c44ff3f88..d6853feb54b 100644 --- a/src/NHibernate/Cache/CacheFactory.cs +++ b/src/NHibernate/Cache/CacheFactory.cs @@ -22,6 +22,11 @@ public static class CacheFactory /// public const string Transactional = "transactional"; + /// + /// Never interact with second level cache or UpdateTimestampsCache. + /// + public const string Never = "never"; + /// /// Creates an from the parameters. /// diff --git a/src/NHibernate/Cfg/EntityCacheUsage.cs b/src/NHibernate/Cfg/EntityCacheUsage.cs index 25dba57a8ca..7b1a34e958f 100644 --- a/src/NHibernate/Cfg/EntityCacheUsage.cs +++ b/src/NHibernate/Cfg/EntityCacheUsage.cs @@ -12,7 +12,9 @@ public enum EntityCacheUsage /// Xml value: nonstrict-read-write NonStrictReadWrite, /// Xml value: transactional - Transactional + Transactional, + /// Xml value: never + Never } /// @@ -24,6 +26,7 @@ public static class EntityCacheUsageParser private const string ReadWriteXmlValue = "read-write"; private const string NonstrictReadWriteXmlValue = "nonstrict-read-write"; private const string TransactionalXmlValue = "transactional"; + private const string NeverXmlValue = "never"; /// /// Convert a in its xml expected value. @@ -42,6 +45,8 @@ public static string ToString(EntityCacheUsage value) return NonstrictReadWriteXmlValue; case EntityCacheUsage.Transactional: return TransactionalXmlValue; + case EntityCacheUsage.Never: + return NeverXmlValue; default: return string.Empty; } @@ -70,9 +75,11 @@ public static EntityCacheUsage Parse(string value) return EntityCacheUsage.NonStrictReadWrite; case TransactionalXmlValue: return EntityCacheUsage.Transactional; + case NeverXmlValue: + return EntityCacheUsage.Never; default: throw new HibernateConfigException(string.Format("Invalid EntityCacheUsage value:{0}", value)); } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Cfg/Environment.cs b/src/NHibernate/Cfg/Environment.cs index a2edd13597d..65783346714 100644 --- a/src/NHibernate/Cfg/Environment.cs +++ b/src/NHibernate/Cfg/Environment.cs @@ -176,6 +176,8 @@ public static string Version /// Should named queries be checked during startup (the default is enabled). /// Mainly intended for test environments. public const string QueryStartupChecking = "query.startup_check"; + /// Should using a never cached entity/collection in a cacheable query throw an exception? The default is true. /// + public const string QueryThrowNeverCached = "query.throw_never_cached"; /// Enable statistics collection public const string GenerateStatistics = "generate_statistics"; diff --git a/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs b/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs index aec0e5e457e..26211420da5 100644 --- a/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs +++ b/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs @@ -2,7 +2,7 @@ namespace NHibernate.Cfg.MappingSchema { /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -83,7 +83,7 @@ public HbmAny() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -110,7 +110,7 @@ public HbmMeta() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -128,7 +128,7 @@ public partial class HbmMetaValue { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -193,7 +193,7 @@ public partial class HbmColumn { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -207,7 +207,7 @@ public partial class HbmComment { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -366,7 +366,7 @@ public HbmArray() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -380,7 +380,7 @@ public partial class HbmSubselect { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -407,7 +407,7 @@ public HbmCache() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCacheUsage { @@ -427,10 +427,14 @@ public enum HbmCacheUsage { /// [System.Xml.Serialization.XmlEnumAttribute("transactional")] Transactional, + + /// + [System.Xml.Serialization.XmlEnumAttribute("never")] + Never, } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCacheInclude { @@ -445,7 +449,7 @@ public enum HbmCacheInclude { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -459,7 +463,7 @@ public partial class HbmSynchronize { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -518,7 +522,7 @@ public HbmKey() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmOndelete { @@ -533,7 +537,7 @@ public enum HbmOndelete { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -559,7 +563,7 @@ public partial class HbmIndex { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -580,7 +584,7 @@ public partial class HbmListIndex { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -612,7 +616,7 @@ public partial class HbmCompositeElement { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -630,7 +634,7 @@ public partial class HbmParent { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -762,7 +766,7 @@ public HbmManyToOne() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -776,7 +780,7 @@ public partial class HbmFormula { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmOuterJoinStrategy { @@ -795,7 +799,7 @@ public enum HbmOuterJoinStrategy { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmFetchMode { @@ -810,7 +814,7 @@ public enum HbmFetchMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmLaziness { @@ -829,7 +833,7 @@ public enum HbmLaziness { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmNotFoundMode { @@ -844,7 +848,7 @@ public enum HbmNotFoundMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -880,7 +884,7 @@ public partial class HbmNestedCompositeElement { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -982,7 +986,7 @@ public partial class HbmProperty { [System.Xml.Serialization.XmlAttributeAttribute()] [System.ComponentModel.DefaultValueAttribute(false)] public bool lazy; - + /// [System.Xml.Serialization.XmlAttributeAttribute("lazy-group")] public string lazygroup; @@ -1001,7 +1005,7 @@ public HbmProperty() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1019,7 +1023,7 @@ public partial class HbmType { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1037,7 +1041,7 @@ public partial class HbmParam { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmPropertyGeneration { @@ -1056,7 +1060,7 @@ public enum HbmPropertyGeneration { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1117,7 +1121,7 @@ public HbmElement() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1147,7 +1151,7 @@ public partial class HbmManyToAny { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1245,7 +1249,7 @@ public HbmManyToMany() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1267,7 +1271,7 @@ public partial class HbmFilter { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmRestrictedLaziness { @@ -1282,7 +1286,7 @@ public enum HbmRestrictedLaziness { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1313,7 +1317,7 @@ public HbmOneToMany() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1327,7 +1331,7 @@ public partial class HbmLoader { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1357,7 +1361,7 @@ public partial class HbmCustomSQL { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCustomSQLCheck { @@ -1376,7 +1380,7 @@ public enum HbmCustomSQLCheck { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCollectionFetchMode { @@ -1395,7 +1399,7 @@ public enum HbmCollectionFetchMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1569,7 +1573,7 @@ public HbmBag() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCollectionLazy { @@ -1588,7 +1592,7 @@ public enum HbmCollectionLazy { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1807,7 +1811,7 @@ public HbmClass() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1829,7 +1833,7 @@ public partial class HbmTuplizer { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmTuplizerEntitymode { @@ -1844,7 +1848,7 @@ public enum HbmTuplizerEntitymode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1894,7 +1898,7 @@ public HbmCompositeId() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1953,7 +1957,7 @@ public HbmKeyManyToOne() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -1998,7 +2002,7 @@ public partial class HbmKeyProperty { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmUnsavedValueType { @@ -2017,7 +2021,7 @@ public enum HbmUnsavedValueType { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2073,7 +2077,7 @@ public partial class HbmId { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2091,7 +2095,7 @@ public partial class HbmGenerator { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2145,7 +2149,7 @@ public HbmDiscriminator() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2172,7 +2176,7 @@ public HbmNaturalId() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2238,7 +2242,7 @@ public partial class HbmComponent { [System.Xml.Serialization.XmlAttributeAttribute()] [System.ComponentModel.DefaultValueAttribute(false)] public bool lazy; - + /// [System.Xml.Serialization.XmlAttributeAttribute("lazy-group")] public string lazygroup; @@ -2262,7 +2266,7 @@ public HbmComponent() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2326,7 +2330,7 @@ public HbmDynamicComponent() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2505,7 +2509,7 @@ public HbmList() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2693,7 +2697,7 @@ public HbmMap() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2712,7 +2716,7 @@ public partial class HbmCompositeIndex { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2731,7 +2735,7 @@ public partial class HbmCompositeMapKey { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2757,7 +2761,7 @@ public partial class HbmIndexManyToAny { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2787,7 +2791,7 @@ public partial class HbmIndexManyToMany { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2822,7 +2826,7 @@ public partial class HbmMapKey { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2857,7 +2861,7 @@ public partial class HbmMapKeyManyToMany { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -2944,7 +2948,7 @@ public HbmOneToOne() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3080,7 +3084,7 @@ public HbmPrimitiveArray() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmPrimitivearrayOuterjoin { @@ -3099,7 +3103,7 @@ public enum HbmPrimitivearrayOuterjoin { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmPrimitivearrayFetch { @@ -3118,7 +3122,7 @@ public enum HbmPrimitivearrayFetch { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3296,7 +3300,7 @@ public HbmSet() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3473,7 +3477,7 @@ public HbmIdbag() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3506,7 +3510,7 @@ public partial class HbmCollectionId { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3559,7 +3563,7 @@ public HbmTimestamp() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmTimestampUnsavedvalue { @@ -3574,7 +3578,7 @@ public enum HbmTimestampUnsavedvalue { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmTimestampSource { @@ -3589,7 +3593,7 @@ public enum HbmTimestampSource { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmVersionGeneration { @@ -3604,7 +3608,7 @@ public enum HbmVersionGeneration { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3665,7 +3669,7 @@ public HbmVersion() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3717,7 +3721,7 @@ public HbmProperties() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3800,7 +3804,7 @@ public HbmJoin() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:nhibernate-mapping-2.2")] public enum HbmJoinFetch { @@ -3815,7 +3819,7 @@ public enum HbmJoinFetch { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -3984,7 +3988,7 @@ public HbmJoinedSubclass() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4005,7 +4009,7 @@ public partial class HbmResultSet { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4036,7 +4040,7 @@ public HbmLoadCollection() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4058,7 +4062,7 @@ public partial class HbmReturnProperty { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4072,7 +4076,7 @@ public partial class HbmReturnColumn { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmLockMode { @@ -4099,7 +4103,7 @@ public enum HbmLockMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4138,7 +4142,7 @@ public HbmReturn() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4152,7 +4156,7 @@ public partial class HbmReturnDiscriminator { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4183,7 +4187,7 @@ public HbmReturnJoin() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4201,7 +4205,7 @@ public partial class HbmReturnScalar { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4276,7 +4280,7 @@ public HbmQuery() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4294,7 +4298,7 @@ public partial class HbmQueryParam { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmFlushMode { @@ -4317,7 +4321,7 @@ public enum HbmFlushMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmCacheMode { @@ -4344,7 +4348,7 @@ public enum HbmCacheMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4434,7 +4438,7 @@ public HbmSqlQuery() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4578,7 +4582,7 @@ public HbmSubclass() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4736,7 +4740,7 @@ public HbmUnionSubclass() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmPolymorphismType { @@ -4751,7 +4755,7 @@ public enum HbmPolymorphismType { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")] public enum HbmOptimisticLockMode { @@ -4774,7 +4778,7 @@ public enum HbmOptimisticLockMode { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4788,7 +4792,7 @@ public partial class HbmCreate { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4808,7 +4812,7 @@ public partial class HbmDatabaseObject { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4826,7 +4830,7 @@ public partial class HbmDefinition { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4840,7 +4844,7 @@ public partial class HbmDrop { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4858,7 +4862,7 @@ public partial class HbmDialectScope { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4893,7 +4897,7 @@ public HbmFilterDef() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -4911,7 +4915,7 @@ public partial class HbmFilterParam { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -5000,7 +5004,7 @@ public HbmMapping() { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] @@ -5022,7 +5026,7 @@ public partial class HbmTypedef { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.0.0-Alpha1")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("HbmXsd", "5.4.0-dev")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] diff --git a/src/NHibernate/Cfg/MappingSchema/HbmExtensions.cs b/src/NHibernate/Cfg/MappingSchema/HbmExtensions.cs index a378aac69f6..bca0e1c6945 100644 --- a/src/NHibernate/Cfg/MappingSchema/HbmExtensions.cs +++ b/src/NHibernate/Cfg/MappingSchema/HbmExtensions.cs @@ -49,6 +49,8 @@ public static string ToCacheConcurrencyStrategy(this HbmCacheUsage cacheUsage) return "nonstrict-read-write"; case HbmCacheUsage.Transactional: return "transactional"; + case HbmCacheUsage.Never: + return "never"; default: throw new ArgumentOutOfRangeException("cacheUsage"); } @@ -83,4 +85,4 @@ public static string JoinString(this string[] source) return null; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Cfg/Settings.cs b/src/NHibernate/Cfg/Settings.cs index 156fc64ff49..474f51cc7aa 100644 --- a/src/NHibernate/Cfg/Settings.cs +++ b/src/NHibernate/Cfg/Settings.cs @@ -141,6 +141,11 @@ public Settings() /// public bool ThrowOnSchemaUpdate { get; internal set; } + /// + /// Should using a never cached entity/collection in a cacheable query throw an exception. + /// + public bool QueryThrowNeverCached { get; internal set; } + #region NH specific public IsolationLevel IsolationLevel { get; internal set; } diff --git a/src/NHibernate/Cfg/SettingsFactory.cs b/src/NHibernate/Cfg/SettingsFactory.cs index 61265256586..f0a10519590 100644 --- a/src/NHibernate/Cfg/SettingsFactory.cs +++ b/src/NHibernate/Cfg/SettingsFactory.cs @@ -293,7 +293,11 @@ public Settings BuildSettings(IDictionary properties) bool namedQueryChecking = PropertiesHelper.GetBoolean(Environment.QueryStartupChecking, properties, true); log.Info("Named query checking : {0}", EnabledDisabled(namedQueryChecking)); settings.IsNamedQueryStartupCheckingEnabled = namedQueryChecking; - + + bool queryThrowNeverCached = PropertiesHelper.GetBoolean(Environment.QueryThrowNeverCached, properties, true); + log.Info("Never cached entities/collections query cache throws exception : {0}", EnabledDisabled(queryThrowNeverCached)); + settings.QueryThrowNeverCached = queryThrowNeverCached; + // Not ported - settings.StatementFetchSize = statementFetchSize; // Not ported - ScrollableResultSetsEnabled // Not ported - GetGeneratedKeysEnabled diff --git a/src/NHibernate/Engine/ActionQueue.cs b/src/NHibernate/Engine/ActionQueue.cs index 36a76591edd..9613c293f7a 100644 --- a/src/NHibernate/Engine/ActionQueue.cs +++ b/src/NHibernate/Engine/ActionQueue.cs @@ -216,8 +216,16 @@ private void RegisterCleanupActions(IExecutable executable) RegisterProcess(executable.AfterTransactionCompletionProcess); #pragma warning restore 618,619 } - if (executable.PropertySpaces != null) + if (executable is ICacheableExecutable cacheableExecutable) { + if (cacheableExecutable.QueryCacheSpaces != null) + { + executedSpaces.UnionWith(cacheableExecutable.QueryCacheSpaces); + } + } + else if (executable.PropertySpaces != null) + { + //TODO 6.0 remove this else block executedSpaces.UnionWith(executable.PropertySpaces); } } diff --git a/src/NHibernate/Engine/ISessionFactoryImplementor.cs b/src/NHibernate/Engine/ISessionFactoryImplementor.cs index 23d9f88429a..66d6ad5b55f 100644 --- a/src/NHibernate/Engine/ISessionFactoryImplementor.cs +++ b/src/NHibernate/Engine/ISessionFactoryImplementor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data.Common; +using System.Linq; using NHibernate.Cache; using NHibernate.Cfg; using NHibernate.Connection; @@ -9,6 +10,7 @@ using NHibernate.Engine.Query; using NHibernate.Exceptions; using NHibernate.Id; +using NHibernate.Impl; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Proxy; @@ -182,4 +184,61 @@ ISession OpenSession(DbConnection connection, bool flushBeforeCompletionEnabled, string TryGetGuessEntityName(System.Type implementor); #endregion } + + // 6.0 TODO: move below methods directly in ISessionFactoryImplementor then remove SessionFactoryImplementorExtension + public static class SessionFactoryImplementorExtension + { + /// + /// Get entity persisters by the given query spaces. + /// + /// The session factory. + /// The query spaces. + /// Unique list of entity persisters, if is null or empty then all persisters are returned. + public static ISet GetEntityPersisters(this ISessionFactoryImplementor factory, ISet spaces) + { + if (factory is SessionFactoryImpl sfi) + { + return sfi.GetEntityPersisters(spaces); + } + + ISet persisters = new HashSet(); + foreach (var entityName in factory.GetAllClassMetadata().Keys) + { + var persister = factory.GetEntityPersister(entityName); + // NativeSql does not have query spaces so include the persister, if spaces is null or empty. + if (spaces == null || spaces.Count == 0 || persister.QuerySpaces.Any(x => spaces.Contains(x))) + { + persisters.Add(persister); + } + } + + return persisters; + } + + /// + /// Get collection persisters by the given query spaces. + /// + /// The session factory. + /// The query spaces. + /// Unique list of collection persisters, if is null or empty then all persisters are returned. + public static ISet GetCollectionPersisters(this ISessionFactoryImplementor factory, ISet spaces) + { + if (factory is SessionFactoryImpl sfi) + { + return sfi.GetCollectionPersisters(spaces); + } + + ISet collectionPersisters = new HashSet(); + foreach (var roleName in factory.GetAllCollectionMetadata().Keys) + { + var collectionPersister = factory.GetCollectionPersister(roleName); + if (spaces == null || spaces.Count == 0 || collectionPersister.CollectionSpaces.Any(x => spaces.Contains(x))) + { + collectionPersisters.Add(collectionPersister); + } + } + + return collectionPersisters; + } + } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs index c08b0b4997f..a56c7483ce8 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs @@ -8,6 +8,7 @@ using NHibernate.Hql.Ast.ANTLR.Util; using NHibernate.Id; using NHibernate.Param; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.SqlCommand; @@ -51,6 +52,8 @@ public partial class HqlSqlWalker private readonly Dictionary selectExpressionsByResultVariable = new Dictionary(); private readonly HashSet _querySpaces = new HashSet(); + private bool _supportsQueryCache = true; + private HashSet _persisters; private readonly LiteralProcessor _literalProcessor; @@ -151,6 +154,10 @@ public ISet QuerySpaces get { return _querySpaces; } } + public bool SupportsQueryCache => _supportsQueryCache; + + internal ISet Persisters => _persisters ?? CollectionHelper.EmptySet(); + public IDictionary NamedParameters { get { return _namedParameterLocations; } @@ -473,7 +480,7 @@ IASTNode CreateIntoClause(string path, IASTNode propertySpec) intoClause.SetFirstChild(propertySpec); intoClause.Initialize(persister); - AddQuerySpaces(persister.QuerySpaces); + AddQuerySpaces(persister); return intoClause; } @@ -1235,6 +1242,30 @@ public IASTFactory ASTFactory internal bool IsNullComparison => _isNullComparison; + public void AddQuerySpaces(IEntityPersister persister) + { + AddPersister(persister); + AddQuerySpaces(persister.QuerySpaces); + } + + public void AddQuerySpaces(ICollectionPersister collectionPersister) + { + AddPersister(collectionPersister); + AddQuerySpaces(collectionPersister.CollectionSpaces); + } + + private void AddPersister(object persister) + { + if (!(persister is IPersister cacheablePersister)) + { + return; + } + + _supportsQueryCache &= cacheablePersister.SupportsQueryCache; + (_persisters = _persisters ?? new HashSet()).Add(cacheablePersister); + } + + //TODO NH 6.0 make this method private public void AddQuerySpaces(string[] spaces) { for (int i = 0; i < spaces.Length; i++) diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 1dea389b9b0..5b2f6a372d8 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -13,6 +13,7 @@ using NHibernate.Hql.Ast.ANTLR.Util; using NHibernate.Loader.Hql; using NHibernate.Param; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.SqlCommand; using NHibernate.Type; @@ -224,6 +225,10 @@ public ISet QuerySpaces get { return _sqlAst.Walker.QuerySpaces; } } + internal ISet Persisters => _sqlAst.Walker.Persisters; + + public bool SupportsQueryCache => _sqlAst.Walker.SupportsQueryCache; + public string SQLString { get { return _generator.Sql.ToString(); } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs index b5b849cd406..f0e2ac759e1 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs @@ -353,10 +353,11 @@ private void DereferenceCollection(CollectionType collectionType, bool implicitJ IEntityPersister entityPersister = elem.EntityPersister; if ( entityPersister != null ) { - Walker.AddQuerySpaces( entityPersister.QuerySpaces ); + Walker.AddQuerySpaces(entityPersister); } } - Walker.AddQuerySpaces( queryableCollection.CollectionSpaces ); // Always add the collection's query spaces. + // Always add the collection's query spaces. + Walker.AddQuerySpaces(queryableCollection); } private void DereferenceEntity(EntityType entityType, bool implicitJoin, string classAlias, bool generateJoin, IASTNode parent) @@ -547,7 +548,7 @@ private void DereferenceEntityJoin(string classAlias, EntityType propertyType, b } SetImpliedJoin( elem ); - Walker.AddQuerySpaces( elem.EntityPersister.QuerySpaces ); + Walker.AddQuerySpaces(elem.EntityPersister); FromElement = elem; // This 'dot' expression now refers to the resulting from element. } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index c534aa5c6be..8711100412a 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -21,7 +21,7 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) {ForceFilter = true} .AddJoin(entityType, tableAlias, joinType, Array.Empty()); - fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); + fromClause.Walker.AddQuerySpaces(entityPersister); } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs index 1324ffe7e7a..65c8585f735 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs @@ -87,7 +87,7 @@ public FromElement AddFromElement() null); // Add to the query spaces. - _fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); + _fromClause.Walker.AddQuerySpaces(entityPersister); return elem; } @@ -262,7 +262,7 @@ public FromElement CreateElementJoin(IQueryableCollection queryableCollection) _fromClause.AddCollectionJoinFromElementByPath(_path, destination); // origin.addDestination(destination); // Add the query spaces. - _fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); + _fromClause.Walker.AddQuerySpaces(entityPersister); CollectionType type = queryableCollection.CollectionType; string role = type.Role; @@ -359,7 +359,7 @@ private FromElement CreateEntityAssociation( } elem = CreateManyToMany(role, associatedEntityName, roleAlias, entityPersister, (EntityType)_queryableCollection.ElementType, joinType); - _fromClause.Walker.AddQuerySpaces(_queryableCollection.CollectionSpaces); + _fromClause.Walker.AddQuerySpaces(_queryableCollection); } elem.CollectionTableAlias = roleAlias; _fromClause.AddCollectionJoinFromElementByPath(_path, elem); @@ -391,7 +391,7 @@ private FromElement CreateCollectionJoin(JoinSequence collectionJoinSequence, st _origin.Text = ""; // The destination node will have all the FROM text. _origin.CollectionJoin = true; // The parent node is a collection join too (voodoo - see JoinProcessor) _fromClause.AddCollectionJoinFromElementByPath(_path, destination); - _fromClause.Walker.AddQuerySpaces(_queryableCollection.CollectionSpaces); + _fromClause.Walker.AddQuerySpaces(_queryableCollection); return destination; } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/IdentNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/IdentNode.cs index 095f8b03545..42dfb2e0f20 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/IdentNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/IdentNode.cs @@ -105,7 +105,7 @@ public override void ResolveIndex(IASTNode parent) FromElement elem = factory.CreateCollection(queryableCollection, role, JoinType.InnerJoin, false, true); FromElement = elem; - Walker.AddQuerySpaces(queryableCollection.CollectionSpaces); // Always add the collection's query spaces. + Walker.AddQuerySpaces(queryableCollection); // Always add the collection's query spaces. } public override void Resolve(bool generateJoin, bool implicitJoin, string classAlias, IASTNode parent) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/MethodNode.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/MethodNode.cs index dc6c04042e7..12b85dcf24b 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/MethodNode.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/MethodNode.cs @@ -182,7 +182,7 @@ private void HandleElements(FromReferenceNode collectionNode, String propertyNam _fromElement = collectionFromElement; if (!collectionFromElement.IsCollectionOfValuesOrComponents) { - Walker.AddQuerySpaces(queryableCollection.ElementPersister.QuerySpaces); + Walker.AddQuerySpaces(queryableCollection.ElementPersister); } DataType = queryableCollection.ElementType; diff --git a/src/NHibernate/Impl/SessionFactoryImpl.cs b/src/NHibernate/Impl/SessionFactoryImpl.cs index 08cd39404df..a81d31950c2 100644 --- a/src/NHibernate/Impl/SessionFactoryImpl.cs +++ b/src/NHibernate/Impl/SessionFactoryImpl.cs @@ -111,6 +111,8 @@ public void HandleEntityNotFound(string entityName, string propertyName, object private readonly IDictionary collectionMetadata; [NonSerialized] private readonly Dictionary collectionPersisters; + [NonSerialized] + private readonly ILookup collectionPersistersSpaces; [NonSerialized] private readonly IDictionary> collectionRolesByEntityParticipant; @@ -120,6 +122,8 @@ public void HandleEntityNotFound(string entityName, string propertyName, object private readonly IEntityNotFoundDelegate entityNotFoundDelegate; [NonSerialized] private readonly IDictionary entityPersisters; + [NonSerialized] + private readonly ILookup entityPersistersSpaces; /// /// NH specific : to avoid the use of entityName for generic implementation @@ -283,6 +287,11 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings implementorToEntityName[model.MappedClass] = model.EntityName; } } + + entityPersistersSpaces = entityPersisters + .SelectMany(x => x.Value.QuerySpaces.Select(y => new { QuerySpace = y, Persister = x.Value })) + .ToLookup(x => x.QuerySpace, x => x.Persister); + classMetadata = new ReadOnlyDictionary(classMeta); Dictionary> tmpEntityToCollectionRoleMap = new Dictionary>(); @@ -321,6 +330,11 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings roles.Add(persister.Role); } } + + collectionPersistersSpaces = collectionPersisters + .SelectMany(x => x.Value.CollectionSpaces.Select(y => new { QuerySpace = y, Persister = x.Value })) + .ToLookup(x => x.QuerySpace, x => x.Persister); + Dictionary tmpcollectionMetadata = new Dictionary(collectionPersisters.Count); foreach (KeyValuePair collectionPersister in collectionPersisters) { @@ -455,7 +469,7 @@ private ICacheConcurrencyStrategy GetCacheConcurrencyStrategy( bool isMutable, Dictionary, ICacheConcurrencyStrategy> caches) { - if (strategy == null || !settings.IsSecondLevelCacheEnabled) + if (strategy == null || strategy == CacheFactory.Never || !settings.IsSecondLevelCacheEnabled) return null; var cacheKey = new Tuple(cacheRegion, strategy); @@ -611,6 +625,48 @@ public ISet GetCollectionRolesByEntityParticipant(string entityName) return result; } + /// + /// Get entity persisters filtered by the given query spaces. + /// + /// The query spaces, or null or an empty set for getting all persisters. + /// A set of entity persisters. + public ISet GetEntityPersisters(ISet spaces) + { + if (spaces == null || spaces.Count == 0) + { + return new HashSet(entityPersisters.Values); + } + + var persisters = new HashSet(); + foreach (var space in spaces) + { + persisters.UnionWith(entityPersistersSpaces[space]); + } + + return persisters; + } + + /// + /// Get collection persisters filtered by the given query spaces. + /// + /// The query spaces, or null or an empty set for getting all persisters. + /// A set of collection persisters. + public ISet GetCollectionPersisters(ISet spaces) + { + if (spaces == null || spaces.Count == 0) + { + return new HashSet(collectionPersisters.Values); + } + + var persisters = new HashSet(); + foreach (var space in spaces) + { + persisters.UnionWith(collectionPersistersSpaces[space]); + } + + return persisters; + } + /// public HibernateDialect Dialect { diff --git a/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs b/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs index 0dfce6c01b4..9c262599356 100644 --- a/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs +++ b/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Type; namespace NHibernate.Loader.Criteria { - public class ComponentCollectionCriteriaInfoProvider : ICriteriaInfoProvider + public class ComponentCollectionCriteriaInfoProvider : ICriteriaInfoProvider, IExtendedCriteriaInfoProvider { private readonly IQueryableCollection persister; private readonly Dictionary subTypes = new Dictionary(); @@ -46,6 +47,8 @@ public IPropertyMapping PropertyMapping get { return persister; } } + IPersister IExtendedCriteriaInfoProvider.Persister => persister as IPersister; + public IType GetType(String relativePath) { // TODO: can a component have a nested component? then we may need to do something more here... diff --git a/src/NHibernate/Loader/Criteria/CriteriaLoader.cs b/src/NHibernate/Loader/Criteria/CriteriaLoader.cs index e3a5ff5dfda..091209372ab 100644 --- a/src/NHibernate/Loader/Criteria/CriteriaLoader.cs +++ b/src/NHibernate/Loader/Criteria/CriteriaLoader.cs @@ -98,6 +98,11 @@ public ISet QuerySpaces get { return querySpaces; } } + internal override bool IsCacheable(QueryParameters queryParameters) + { + return IsCacheable(queryParameters, translator.SupportsQueryCache, translator.GetPersisters()); + } + public override bool IsSubselectLoadingEnabled { get { return HasSubselectLoadableCollections(); } diff --git a/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs b/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs index 955c4802dd3..3524dcf9784 100644 --- a/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs +++ b/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs @@ -13,6 +13,7 @@ using NHibernate.Type; using NHibernate.Util; using IQueryable = NHibernate.Persister.Entity.IQueryable; +using NHibernate.Persister; namespace NHibernate.Loader.Criteria { @@ -56,9 +57,11 @@ public class EntityJoinInfo private readonly ICollection collectedParameterSpecifications; private readonly ICollection namedParameters; private readonly HashSet subQuerySpaces = new HashSet(); + private HashSet subPersisters; private Dictionary entityJoins = new Dictionary(); private readonly IQueryable rootPersister; + private readonly bool supportsQueryCache; //Key for the dictionary sub-criteria private class AliasKey : IEquatable @@ -127,6 +130,8 @@ public CriteriaQueryTranslator(ISessionFactoryImplementor factory, CriteriaImpl CreateCriteriaCollectionPersisters(); CreateCriteriaSQLAliasMap(); CreateSubQuerySpaces(); + + supportsQueryCache = GetPersisters().All(o => o.SupportsQueryCache); } [CLSCompliant(false)] // TODO: Why does this cause a problem in 1.1 @@ -154,6 +159,37 @@ public ISet GetQuerySpaces() return result; } + internal IEnumerable GetPersisters() + { + foreach (var info in criteriaInfoMap.Values) + { + if (info is IExtendedCriteriaInfoProvider extendedCriteriaInfo && extendedCriteriaInfo.Persister != null) + { + yield return extendedCriteriaInfo.Persister; + } + } + + foreach (var collectionPersister in criteriaCollectionPersisters) + { + if (collectionPersister is IPersister cacheablePersister) + { + yield return cacheablePersister; + } + } + + if (subPersisters == null) + { + yield break; + } + + foreach (var subPersister in subPersisters) + { + yield return subPersister; + } + } + + internal bool SupportsQueryCache => supportsQueryCache; + public int SQLAliasCount { get { return criteriaSQLAliasMap.Count; } @@ -1053,6 +1089,7 @@ private void CreateSubQuerySpaces() //The RootSqlAlias is not relevant, since we're only retreiving the query spaces var translator = new CriteriaQueryTranslator(sessionFactory, criteriaImpl, criteriaImpl.EntityOrClassName, RootSqlAlias); subQuerySpaces.UnionWith(translator.GetQuerySpaces()); + (subPersisters = subPersisters ?? new HashSet()).UnionWith(translator.GetPersisters()); } } diff --git a/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs b/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs index f3cccefc2c4..fbd96d1ab56 100644 --- a/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs +++ b/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs @@ -1,10 +1,11 @@ using System; +using NHibernate.Persister; using NHibernate.Persister.Entity; using NHibernate.Type; namespace NHibernate.Loader.Criteria { - public class EntityCriteriaInfoProvider : ICriteriaInfoProvider + public class EntityCriteriaInfoProvider : ICriteriaInfoProvider, IExtendedCriteriaInfoProvider { readonly IQueryable persister; @@ -37,9 +38,11 @@ public IPropertyMapping PropertyMapping } } + IPersister IExtendedCriteriaInfoProvider.Persister => persister as IPersister; + public IType GetType(String relativePath) { return persister.ToType(relativePath); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Loader/Criteria/IExtendedCriteriaInfoProvider.cs b/src/NHibernate/Loader/Criteria/IExtendedCriteriaInfoProvider.cs new file mode 100644 index 00000000000..952ddfa2be8 --- /dev/null +++ b/src/NHibernate/Loader/Criteria/IExtendedCriteriaInfoProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NHibernate.Persister; + +namespace NHibernate.Loader.Criteria +{ + // TODO 6.0: Move members to ICriteriaInfoProvider and remove this. + internal interface IExtendedCriteriaInfoProvider + { + IPersister Persister { get; } + } +} diff --git a/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs b/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs index 108e4ace1b3..826d4872ec4 100644 --- a/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs +++ b/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs @@ -1,12 +1,13 @@ using System; using NHibernate.Hql.Util; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Type; namespace NHibernate.Loader.Criteria { - public class ScalarCollectionCriteriaInfoProvider : ICriteriaInfoProvider + public class ScalarCollectionCriteriaInfoProvider : ICriteriaInfoProvider, IExtendedCriteriaInfoProvider { private readonly String role; private readonly IQueryableCollection persister; @@ -42,6 +43,8 @@ public IPropertyMapping PropertyMapping } } + IPersister IExtendedCriteriaInfoProvider.Persister => persister as IPersister; + public IType GetType(String relativePath) { //not sure what things are going to be passed here, how about 'id', maybe 'index' or 'key' or 'elements' ??? diff --git a/src/NHibernate/Loader/Custom/CustomLoader.cs b/src/NHibernate/Loader/Custom/CustomLoader.cs index dea693cf540..5427d153523 100644 --- a/src/NHibernate/Loader/Custom/CustomLoader.cs +++ b/src/NHibernate/Loader/Custom/CustomLoader.cs @@ -12,6 +12,7 @@ using NHibernate.Transform; using NHibernate.Type; using IQueryable = NHibernate.Persister.Entity.IQueryable; +using NHibernate.Persister; namespace NHibernate.Loader.Custom { @@ -25,6 +26,7 @@ public partial class CustomLoader : Loader private readonly SqlString sql; private readonly HashSet querySpaces = new HashSet(); + private readonly bool supportsQueryCache = true; private List parametersSpecifications; private readonly IQueryable[] entityPersisters; @@ -34,6 +36,7 @@ public partial class CustomLoader : Loader private readonly IQueryableCollection[] collectionPersisters; private readonly int[] collectionOwners; private readonly ICollectionAliases[] collectionAliases; + private readonly IPersister[] customPersisters; private readonly LockMode[] lockModes; private readonly ResultRowProcessor rowProcessor; @@ -46,6 +49,15 @@ public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory { sql = customQuery.SQL; querySpaces.UnionWith(customQuery.QuerySpaces); + if (querySpaces.Count > 0) + { + customPersisters = factory + .GetEntityPersisters(querySpaces).OfType() + .Concat(factory.GetCollectionPersisters(querySpaces).OfType()) + .ToArray(); + supportsQueryCache = customPersisters.All(x => x.SupportsQueryCache); + } + parametersSpecifications = customQuery.CollectedParametersSpecifications.ToList(); List entitypersisters = new List(); @@ -91,6 +103,8 @@ public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory specifiedAliases.Add(rootRtn.Alias); entityaliases.Add(rootRtn.EntityAliases); querySpaces.UnionWith(persister.QuerySpaces); + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + supportsQueryCache = supportsQueryCache && persister.SupportsQueryCache(); includeInResultRowList.Add(true); } else if (rtn is CollectionReturn) @@ -115,6 +129,8 @@ public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory entityowners.Add(-1); entityaliases.Add(collRtn.ElementEntityAliases); querySpaces.UnionWith(elementPersister.QuerySpaces); + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + supportsQueryCache = supportsQueryCache && elementPersister.SupportsQueryCache(); } includeInResultRowList.Add(true); } @@ -134,6 +150,8 @@ public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory specifiedAliases.Add(fetchRtn.Alias); entityaliases.Add(fetchRtn.EntityAliases); querySpaces.UnionWith(persister.QuerySpaces); + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + supportsQueryCache = supportsQueryCache && persister.SupportsQueryCache(); includeInResultRowList.Add(false); } else if (rtn is CollectionFetchReturn) @@ -159,6 +177,8 @@ public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory entityowners.Add(ownerIndex); entityaliases.Add(fetchRtn.ElementEntityAliases); querySpaces.UnionWith(elementPersister.QuerySpaces); + // 6.0 TODO: Use IPersister.SupportsQueryCache property once IPersister's todo is done. + supportsQueryCache = supportsQueryCache && elementPersister.SupportsQueryCache(); } includeInResultRowList.Add(false); } @@ -187,6 +207,16 @@ public ISet QuerySpaces get { return querySpaces; } } + internal override bool IsCacheable(QueryParameters queryParameters) + { + return IsCacheable( + queryParameters, + supportsQueryCache, + entityPersisters + .OfType() + .Union(customPersisters ?? Enumerable.Empty())); + } + protected override int[] CollectionOwners { get { return collectionOwners; } diff --git a/src/NHibernate/Loader/Hql/QueryLoader.cs b/src/NHibernate/Loader/Hql/QueryLoader.cs index 5fdda0cde17..17fd0066a40 100644 --- a/src/NHibernate/Loader/Hql/QueryLoader.cs +++ b/src/NHibernate/Loader/Hql/QueryLoader.cs @@ -109,6 +109,11 @@ protected override string[] Aliases get { return _sqlAliases; } } + internal override bool IsCacheable(QueryParameters queryParameters) + { + return IsCacheable(queryParameters, _queryTranslator.SupportsQueryCache, _queryTranslator.Persisters); + } + protected override int[] CollectionOwners { get { return _collectionOwners; } diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index 8069cc9a544..6a262b8a6ad 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -18,6 +18,7 @@ using NHibernate.Hql.Util; using NHibernate.Impl; using NHibernate.Param; +using NHibernate.Persister; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Proxy; @@ -1827,9 +1828,32 @@ protected IList List(ISessionImplementor session, QueryParameters queryParameter return ListIgnoreQueryCache(session, queryParameters); } - internal bool IsCacheable(QueryParameters queryParameters) + internal virtual bool IsCacheable(QueryParameters queryParameters) { - return _factory.Settings.IsQueryCacheEnabled && queryParameters.Cacheable; + return IsCacheable(queryParameters, true, Enumerable.Empty()); + } + + internal bool IsCacheable(QueryParameters queryParameters, bool supportsQueryCache, IEnumerable persisters) + { + bool isCacheable = Factory.Settings.IsQueryCacheEnabled && queryParameters.Cacheable; + if (isCacheable && !supportsQueryCache) + { + if (Factory.Settings.QueryThrowNeverCached) + { + throw new QueryException( + "Never cached entities/collections cannot be used in a cacheable query: " + + string.Join(", ", persisters.Where(o => !o.SupportsQueryCache).Select(o => o.Name))); + } + else if (Log.IsWarnEnabled()) + { + Log.Warn( + "Never cached entities/collections ({0}) are included in a cacheable query: the query '{1}' will not be cached.", + string.Join(", ", persisters.Where(o => !o.SupportsQueryCache).Select(p => p.Name)), + ToString()); + } + } + + return isCacheable && supportsQueryCache; } private IList ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) diff --git a/src/NHibernate/Mapping/ByCode/CacheUsage.cs b/src/NHibernate/Mapping/ByCode/CacheUsage.cs index 6bbb70b2271..34ce821d2fd 100644 --- a/src/NHibernate/Mapping/ByCode/CacheUsage.cs +++ b/src/NHibernate/Mapping/ByCode/CacheUsage.cs @@ -8,6 +8,7 @@ public abstract class CacheUsage public static CacheUsage ReadWrite = new ReadWriteUsage(); public static CacheUsage NonstrictReadWrite = new NonstrictReadWriteUsage(); public static CacheUsage Transactional = new TransactionalUsage(); + public static CacheUsage Never = new NeverUsage(); internal abstract HbmCacheUsage ToHbm(); @@ -58,5 +59,17 @@ internal override HbmCacheUsage ToHbm() } #endregion + + #region Nested type: NeverUsage + + private class NeverUsage : CacheUsage + { + internal override HbmCacheUsage ToHbm() + { + return HbmCacheUsage.Never; + } + } + + #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs index 033673f9656..52b7f4595ba 100644 --- a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs @@ -30,8 +30,14 @@ namespace NHibernate.Persister.Collection /// /// Summary description for AbstractCollectionPersister. /// - public abstract partial class AbstractCollectionPersister : ICollectionMetadata, ISqlLoadableCollection, - IPostInsertIdentityPersister, ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable + public abstract partial class AbstractCollectionPersister : + ICollectionMetadata, + ISqlLoadableCollection, + IPostInsertIdentityPersister, + ISupportSelectModeJoinable, + ICompositeKeyPostInsertIdentityPersister, + ISupportLazyPropsJoinable, + IPersister { protected static readonly object NotFoundPlaceHolder = new object(); private readonly string role; @@ -91,6 +97,7 @@ public abstract partial class AbstractCollectionPersister : ICollectionMetadata, protected readonly string qualifiedTableName; private readonly string queryLoaderName; + private readonly bool supportsQueryCache; private readonly bool isPrimitiveArray; private readonly bool isArray; @@ -530,6 +537,8 @@ public AbstractCollectionPersister(Mapping.Collection collection, ICacheConcurre : Template.RenderOrderByStringTemplate(manyToManyOrderByString, factory.Dialect, factory.SQLFunctionRegistry); InitCollectionPropertyMap(); + + supportsQueryCache = collection.CacheConcurrencyStrategy != CacheFactory.Never; } public void PostInstantiate() @@ -636,6 +645,12 @@ public bool HasCache get { return cache != null; } } + /// + public bool SupportsQueryCache + { + get { return supportsQueryCache; } + } + public string GetSQLWhereString(string alias) { return Template.ReplacePlaceholder(sqlWhereStringTemplate, alias); diff --git a/src/NHibernate/Persister/Collection/ICollectionPersister.cs b/src/NHibernate/Persister/Collection/ICollectionPersister.cs index 8f813f0ce09..e5910b281e2 100644 --- a/src/NHibernate/Persister/Collection/ICollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/ICollectionPersister.cs @@ -305,5 +305,11 @@ public static int GetBatchSize(this ICollectionPersister persister) return 1; } + + // 6.0 TODO: Remove once IPersister's todo is done. + internal static bool SupportsQueryCache(this ICollectionPersister persister) + { + return (persister as IPersister)?.SupportsQueryCache ?? true; + } } } diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 05f84dfae89..409808945c9 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -40,7 +40,8 @@ namespace NHibernate.Persister.Entity /// public abstract partial class AbstractEntityPersister : IOuterJoinLoadable, IQueryable, IClassMetadata, IUniqueKeyLoadable, ISqlLoadable, ILazyPropertyInitializer, IPostInsertIdentityPersister, ILockable, - ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable + ISupportSelectModeJoinable, ICompositeKeyPostInsertIdentityPersister, ISupportLazyPropsJoinable, + IPersister { #region InclusionChecker @@ -248,6 +249,8 @@ public virtual void BindValues(DbCommand ps) private readonly string loaderName; + private readonly bool supportsQueryCache; + private IUniqueEntityLoader queryLoader; private readonly string temporaryIdTableName; @@ -548,6 +551,8 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr } return uniqueKeyPropertyNames; }); + + supportsQueryCache = persistentClass.CacheConcurrencyStrategy != CacheFactory.Never; } protected abstract int[] SubclassColumnTableNumberClosure { get; } @@ -4196,6 +4201,11 @@ public virtual bool HasCache get { return cache != null; } } + public bool SupportsQueryCache + { + get { return supportsQueryCache; } + } + private string GetSubclassEntityName(System.Type clazz) { string result; diff --git a/src/NHibernate/Persister/Entity/IEntityPersister.cs b/src/NHibernate/Persister/Entity/IEntityPersister.cs index 495e6147ddd..40394c72173 100644 --- a/src/NHibernate/Persister/Entity/IEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/IEntityPersister.cs @@ -640,5 +640,11 @@ public static void AfterInitialize(this IEntityPersister persister, object entit persister.AfterInitialize(entity, true, session); #pragma warning restore 618 } + + // 6.0 TODO: Remove once IPersister's todo is done. + internal static bool SupportsQueryCache(this IEntityPersister persister) + { + return (persister as IPersister)?.SupportsQueryCache ?? true; + } } } diff --git a/src/NHibernate/Persister/IPersister.cs b/src/NHibernate/Persister/IPersister.cs new file mode 100644 index 00000000000..6cd5673c2fb --- /dev/null +++ b/src/NHibernate/Persister/IPersister.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NHibernate.Persister +{ + // TODO 6.0: Make this public and make IEntityPersister and ICollectionPersister derive it. + internal interface IPersister + { + /// + /// The unique name of the persister. + /// + string Name { get; } + + /// + /// Whether the persister supports query cache. + /// + bool SupportsQueryCache { get; } + } +} diff --git a/src/NHibernate/nhibernate-configuration.xsd b/src/NHibernate/nhibernate-configuration.xsd index 69529ca43c0..4d6022543af 100644 --- a/src/NHibernate/nhibernate-configuration.xsd +++ b/src/NHibernate/nhibernate-configuration.xsd @@ -158,6 +158,14 @@ + + + + Should queries set as cacheable raise an error if they reference an entity using the cache + strategy "never" (the default is enabled). + + + @@ -410,6 +418,7 @@ + diff --git a/src/NHibernate/nhibernate-mapping.xsd b/src/NHibernate/nhibernate-mapping.xsd index ed1ce498221..301f820ad33 100644 --- a/src/NHibernate/nhibernate-mapping.xsd +++ b/src/NHibernate/nhibernate-mapping.xsd @@ -107,6 +107,7 @@ +