From: <ric...@us...> - 2010-01-10 19:01:49
|
Revision: 4916 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4916&view=rev Author: ricbrown Date: 2010-01-10 19:01:42 +0000 (Sun, 10 Jan 2010) Log Message: ----------- Fix NH-1989 (Future queries not using second level cache) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs trunk/nhibernate/src/NHibernate/Impl/DelayedEnumerator.cs trunk/nhibernate/src/NHibernate/Impl/FutureBatch.cs trunk/nhibernate/src/NHibernate/Impl/FutureCriteriaBatch.cs trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs trunk/nhibernate/src/NHibernate/Impl/FutureValue.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Model.cs Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -56,6 +56,16 @@ this.parameterMetadata = parameterMetadata; } + public bool Cacheable + { + get { return cacheable; } + } + + public string CacheRegion + { + get { return cacheRegion; } + } + public bool HasNamedParameters { get { return parameterMetadata.NamedParameterNames.Count > 0; } Modified: trunk/nhibernate/src/NHibernate/Impl/DelayedEnumerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/DelayedEnumerator.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/DelayedEnumerator.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -5,7 +5,7 @@ { internal class DelayedEnumerator<T> : IEnumerable<T> { - public delegate IList<T> GetResult(); + public delegate IEnumerable<T> GetResult(); private readonly GetResult result; Modified: trunk/nhibernate/src/NHibernate/Impl/FutureBatch.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/FutureBatch.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/FutureBatch.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; namespace NHibernate.Impl { @@ -9,6 +10,8 @@ private readonly IList<System.Type> resultTypes = new List<System.Type>(); private int index; private IList results; + private bool isCacheable = true; + private string cacheRegion; protected readonly SessionImpl session; @@ -31,9 +34,16 @@ public void Add<TResult>(TQueryApproach query) { + if (queries.Count == 0) + { + cacheRegion = CacheRegion(query); + } + queries.Add(query); resultTypes.Add(typeof(TResult)); index = queries.Count - 1; + isCacheable = isCacheable && IsQueryCacheable(query); + isCacheable = isCacheable && (cacheRegion == CacheRegion(query)); } public void Add(TQueryApproach query) @@ -55,7 +65,7 @@ private void GetResults() { - var multiApproach = CreateMultiApproach(); + var multiApproach = CreateMultiApproach(isCacheable, cacheRegion); for (int i = 0; i < queries.Count; i++) { AddTo(multiApproach, queries[i], resultTypes[i]); @@ -64,14 +74,16 @@ ClearCurrentFutureBatch(); } - private IList<TResult> GetCurrentResult<TResult>(int currentIndex) + private IEnumerable<TResult> GetCurrentResult<TResult>(int currentIndex) { - return (IList<TResult>)Results[currentIndex]; + return ((IList)Results[currentIndex]).Cast<TResult>(); } - protected abstract TMultiApproach CreateMultiApproach(); + protected abstract TMultiApproach CreateMultiApproach(bool isCacheable, string cacheRegion); protected abstract void AddTo(TMultiApproach multiApproach, TQueryApproach query, System.Type resultType); protected abstract IList GetResultsFrom(TMultiApproach multiApproach); protected abstract void ClearCurrentFutureBatch(); + protected abstract bool IsQueryCacheable(TQueryApproach query); + protected abstract string CacheRegion(TQueryApproach query); } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Impl/FutureCriteriaBatch.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/FutureCriteriaBatch.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/FutureCriteriaBatch.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -6,9 +6,12 @@ { public FutureCriteriaBatch(SessionImpl session) : base(session) {} - protected override IMultiCriteria CreateMultiApproach() + protected override IMultiCriteria CreateMultiApproach(bool isCacheable, string cacheRegion) { - return session.CreateMultiCriteria(); + return + session.CreateMultiCriteria() + .SetCacheable(isCacheable) + .SetCacheRegion(cacheRegion); } protected override void AddTo(IMultiCriteria multiApproach, ICriteria query, System.Type resultType) @@ -25,5 +28,15 @@ { session.FutureCriteriaBatch = null; } + + protected override bool IsQueryCacheable(ICriteria query) + { + return ((CriteriaImpl)query).Cacheable; + } + + protected override string CacheRegion(ICriteria query) + { + return ((CriteriaImpl)query).CacheRegion; + } } } Modified: trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -6,9 +6,12 @@ { public FutureQueryBatch(SessionImpl session) : base(session) {} - protected override IMultiQuery CreateMultiApproach() + protected override IMultiQuery CreateMultiApproach(bool isCacheable, string cacheRegion) { - return session.CreateMultiQuery(); + return + session.CreateMultiQuery() + .SetCacheable(isCacheable) + .SetCacheRegion(cacheRegion); } protected override void AddTo(IMultiQuery multiApproach, IQuery query, System.Type resultType) @@ -25,5 +28,15 @@ { session.FutureQueryBatch = null; } + + protected override bool IsQueryCacheable(IQuery query) + { + return ((AbstractQueryImpl)query).Cacheable; + } + + protected override string CacheRegion(IQuery query) + { + return ((AbstractQueryImpl)query).CacheRegion; + } } } Modified: trunk/nhibernate/src/NHibernate/Impl/FutureValue.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/FutureValue.cs 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate/Impl/FutureValue.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -5,7 +5,7 @@ { internal class FutureValue<T> : IFutureValue<T> { - public delegate IList<T> GetResult(); + public delegate IEnumerable<T> GetResult(); private readonly GetResult getResult; @@ -19,13 +19,14 @@ get { var result = getResult(); + var enumerator = result.GetEnumerator(); - if (result.Count == 0) - { + if (!enumerator.MoveNext()) + { return default(T); } - return result[0]; + return enumerator.Current; } } } Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989 ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -0,0 +1,274 @@ +using System.Data; + +using NUnit.Framework; + +using NHibernate.Cache; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NHibernate.Engine; + +using System.Collections.Generic; +using System.Linq; + +namespace NHibernate.Test.NHSpecificTest.NH1989 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + cfg.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; + cfg.Properties[Environment.UseQueryCache] = "true"; + sessions = (ISessionFactoryImplementor)cfg.BuildSessionFactory(); + } + + protected override void OnTearDown() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + s.Delete("from User"); + tx.Commit(); + } + } + + private static void DeleteObjectsOutsideCache(ISession s) + { + using (IDbCommand cmd = s.Connection.CreateCommand()) + { + cmd.CommandText = "DELETE FROM UserTable"; + cmd.ExecuteNonQuery(); + } + } + + [Test] + public void SecondLevelCacheWithSingleCacheableFuture() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + User user = new User() { Name="test" }; + s.Save(user); + tx.Commit(); + } + + using (ISession s = OpenSession()) + { + // Query results should be cached + User user = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Not.Null); + + DeleteObjectsOutsideCache(s); + } + + using (ISession s = OpenSession()) + { + User user = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Not.Null, + "entity not retrieved from cache"); + } + } + + [Test] + public void SecondLevelCacheWithDifferentRegionsFuture() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + User user = new User() { Name="test" }; + s.Save(user); + tx.Commit(); + } + + using (ISession s = OpenSession()) + { + // Query results should be cached + User user = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .SetCacheRegion("region1") + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Not.Null); + + DeleteObjectsOutsideCache(s); + } + + using (ISession s = OpenSession()) + { + User user = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .SetCacheRegion("region2") + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Null, + "entity from different region should not be retrieved"); + } + } + + [Test] + public void SecondLevelCacheWithMixedCacheableAndNonCacheableFuture() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + User user = new User() { Name="test" }; + s.Save(user); + tx.Commit(); + } + + using (ISession s = OpenSession()) + { + // cacheable Future, not evaluated yet + IFutureValue<User> userFuture = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .FutureValue<User>(); + + // non cacheable Future causes batch to be non-cacheable + int count = + s.CreateCriteria<User>() + .SetProjection(Projections.RowCount()) + .FutureValue<int>() + .Value; + + Assert.That(userFuture.Value, Is.Not.Null); + Assert.That(count, Is.EqualTo(1)); + + DeleteObjectsOutsideCache(s); + } + + using (ISession s = OpenSession()) + { + IFutureValue<User> userFuture = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .FutureValue<User>(); + + int count = + s.CreateCriteria<User>() + .SetProjection(Projections.RowCount()) + .FutureValue<int>() + .Value; + + Assert.That(userFuture.Value, Is.Null, + "query results should not come from cache"); + } + } + + [Test] + public void SecondLevelCacheWithMixedCacheRegionsFuture() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + User user = new User() { Name="test" }; + s.Save(user); + tx.Commit(); + } + + using (ISession s = OpenSession()) + { + // cacheable Future, not evaluated yet + IFutureValue<User> userFuture = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .SetCacheRegion("region1") + .FutureValue<User>(); + + // different cache-region causes batch to be non-cacheable + int count = + s.CreateCriteria<User>() + .SetProjection(Projections.RowCount()) + .SetCacheable(true) + .SetCacheRegion("region2") + .FutureValue<int>() + .Value; + + Assert.That(userFuture.Value, Is.Not.Null); + Assert.That(count, Is.EqualTo(1)); + + DeleteObjectsOutsideCache(s); + } + + using (ISession s = OpenSession()) + { + IFutureValue<User> userFuture = + s.CreateCriteria<User>() + .Add(Restrictions.NaturalId().Set("Name", "test")) + .SetCacheable(true) + .SetCacheRegion("region1") + .FutureValue<User>(); + + int count = + s.CreateCriteria<User>() + .SetProjection(Projections.RowCount()) + .SetCacheable(true) + .SetCacheRegion("region2") + .FutureValue<int>() + .Value; + + Assert.That(userFuture.Value, Is.Null, + "query results should not come from cache"); + } + } + + [Test] + public void SecondLevelCacheWithSingleCacheableQueryFuture() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + User user = new User() { Name="test" }; + s.Save(user); + tx.Commit(); + } + + using (ISession s = OpenSession()) + { + // Query results should be cached + User user = + s.CreateQuery("from User u where u.Name='test'") + .SetCacheable(true) + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Not.Null); + + DeleteObjectsOutsideCache(s); + } + + using (ISession s = OpenSession()) + { + User user = + s.CreateQuery("from User u where u.Name='test'") + .SetCacheable(true) + .FutureValue<User>() + .Value; + + Assert.That(user, Is.Not.Null, + "entity not retrieved from cache"); + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Mappings.hbm.xml 2010-01-10 19:01:42 UTC (rev 4916) @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.NHSpecificTest.NH1989" + assembly="NHibernate.Test"> + + <class name="User" table="UserTable"> + <cache usage="read-write"/> + <id name="Id"> + <generator class="guid.comb"/> + </id> + <natural-id> + <property name="Name" /> + </natural-id> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Model.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1989/Model.cs 2010-01-10 19:01:42 UTC (rev 4916) @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH1989 +{ + public class User + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-01-08 10:09:47 UTC (rev 4915) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-01-10 19:01:42 UTC (rev 4916) @@ -661,6 +661,8 @@ <Compile Include="NHSpecificTest\NH1978\AliasTest.cs" /> <Compile Include="NHSpecificTest\NH1978\Employee.cs" /> <Compile Include="NHSpecificTest\NH1978\_401k.cs" /> + <Compile Include="NHSpecificTest\NH1989\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1989\Model.cs" /> <Compile Include="NHSpecificTest\NH2044\DomainClass.cs" /> <Compile Include="NHSpecificTest\NH2044\SampleTest.cs" /> <Compile Include="NHSpecificTest\NH2055\AuxType.cs" /> @@ -2103,6 +2105,7 @@ <EmbeddedResource Include="CfgTest\Loquacious\EntityToCache.hbm.xml" /> <EmbeddedResource Include="DriverTest\SqlServerCeEntity.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1989\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1978\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2044\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2030\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |