|
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.
|