From: <dar...@us...> - 2009-01-27 03:49:30
|
Revision: 4003 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4003&view=rev Author: darioquintana Date: 2009-01-27 03:49:11 +0000 (Tue, 27 Jan 2009) Log Message: ----------- Adding support for IQuery.Future<T>() Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs trunk/nhibernate/src/NHibernate/IQuery.cs trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/Futures/FutureQueryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -285,5 +285,7 @@ int ExecuteUpdate(string query, QueryParameters queryParameters); FutureCriteriaBatch FutureCriteriaBatch { get; } + + FutureQueryBatch FutureQueryBatch { get; } } } Modified: trunk/nhibernate/src/NHibernate/IQuery.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQuery.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/IQuery.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -584,5 +584,22 @@ /// "shape" of the query result. /// </summary> IQuery SetResultTransformer(IResultTransformer resultTransformer); + + /// <summary> + /// Get a enumerable that when enumerated will execute + /// a batch of queries in a single database roundtrip + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns></returns> + IEnumerable<T> Future<T>(); + + /// Get an IFutureValue instance, whose value can be retrieved through + /// its Value property. The query is not executed until the Value property + /// is retrieved, which will execute other Future queries as well in a + /// single roundtrip + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns></returns> + IFutureValue<T> FutureValue<T>(); } } Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -826,7 +826,19 @@ return this; } - /// <summary> Override the current session cache mode, just for this query. + public IEnumerable<T> Future<T>() + { + session.FutureQueryBatch.Add(this); + return session.FutureQueryBatch.GetEnumerator<T>(); + } + + public IFutureValue<T> FutureValue<T>() + { + session.FutureQueryBatch.Add(this); + return session.FutureQueryBatch.GetFutureValue<T>(); + } + + /// <summary> Override the current session cache mode, just for this query. /// </summary> /// <param name="cacheMode">The cache mode to use. </param> /// <returns> this (for method chaining) </returns> Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -129,6 +129,7 @@ public abstract int ExecuteNativeUpdate(NativeSQLQuerySpecification specification, QueryParameters queryParameters); public abstract int ExecuteUpdate(string query, QueryParameters queryParameters); public abstract FutureCriteriaBatch FutureCriteriaBatch { get; internal set; } + public abstract FutureQueryBatch FutureQueryBatch { get; internal set; } public virtual IQuery GetNamedQuery(string queryName) { Added: trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Impl/FutureQueryBatch.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -0,0 +1,126 @@ +using System.Collections; +using System.Collections.Generic; + +namespace NHibernate.Impl +{ + public class FutureQueryBatch + { + private readonly List<IQuery> queries = new List<IQuery>(); + private int index; + private IList results; + private readonly ISession session; + + public FutureQueryBatch(ISession session) + { + this.session = session; + } + + public IList Results + { + get + { + if (results == null) + { + var multiQuery = session.CreateMultiQuery(); + foreach (var crit in queries) + { + multiQuery.Add(crit); + } + results = multiQuery.List(); + ((SessionImpl)session).FutureQueryBatch = null; + } + return results; + } + } + + public void Add(IQuery query) + { + queries.Add(query); + index = queries.Count - 1; + } + + public IFutureValue<T> GetFutureValue<T>() + { + int currentIndex = index; + return new FutureValue<T>(() => (IList)Results[currentIndex]); + } + + public IEnumerable<T> GetEnumerator<T>() + { + int currentIndex = index; + return new DelayedEnumerator<T>(() => (IList)Results[currentIndex]); + } + + #region Nested type: FutureValue + + private class FutureValue<T> : IFutureValue<T> + { + public delegate IList GetResult(); + + private readonly GetResult getResult; + + public FutureValue(GetResult result) + { + getResult = result; + } + + public T Value + { + get + { + var result = getResult(); + + if (result.Count == 0) + { + return default(T); + } + + return (T)result[0]; + } + } + } + + #endregion + + #region Nested type: DelayedEnumerator + + private class DelayedEnumerator<T> : IEnumerable<T> + { + public delegate IList GetResult(); + + private readonly GetResult result; + + public DelayedEnumerator(GetResult result) + { + this.result = result; + } + + public IEnumerable<T> Enumerable + { + get + { + foreach (T item in result()) + { + yield return item; + } + } + } + + #region IEnumerable<T> Members + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)Enumerable).GetEnumerator(); + } + + public IEnumerator<T> GetEnumerator() + { + return Enumerable.GetEnumerator(); + } + + #endregion + } + + #endregion + } +} Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -50,6 +50,7 @@ [NonSerialized] private readonly EntityMode entityMode = EntityMode.Poco; [NonSerialized] private FutureCriteriaBatch futureCriteriaBatch; + [NonSerialized] private FutureQueryBatch futureQueryBatch; [NonSerialized] private readonly EventListeners listeners; @@ -264,6 +265,20 @@ } } + public override FutureQueryBatch FutureQueryBatch + { + get + { + if (futureQueryBatch == null) + futureQueryBatch = new FutureQueryBatch(this); + return futureQueryBatch; + } + internal set + { + futureQueryBatch = value; + } + } + /// <summary></summary> public override IBatcher Batcher { Modified: trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -819,6 +819,12 @@ internal set { throw new System.NotSupportedException("future queries are not supported for stateless session"); } } + public override FutureQueryBatch FutureQueryBatch + { + get { throw new System.NotSupportedException("future queries are not supported for stateless session"); } + internal set { throw new System.NotSupportedException("future queries are not supported for stateless session"); } + } + public override IEntityPersister GetEntityPersister(string entityName, object obj) { CheckAndUpdateSessionStatus(); Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-01-27 03:49:11 UTC (rev 4003) @@ -2,7 +2,7 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.30729</ProductVersion> + <ProductVersion>9.0.21022</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{5909BFE7-93CF-4E5F-BE22-6293368AF01D}</ProjectGuid> <OutputType>Library</OutputType> @@ -458,6 +458,7 @@ <Compile Include="Exceptions\TemplatedViolatedConstraintNameExtracter.cs" /> <Compile Include="Id\SelectGenerator.cs" /> <Compile Include="IFutureValue.cs" /> + <Compile Include="Impl\FutureQueryBatch.cs" /> <Compile Include="Impl\FutureCriteriaBatch.cs" /> <Compile Include="Properties\BackFieldStrategy.cs" /> <Compile Include="Bytecode\CodeDom\BytecodeProviderImpl.cs" /> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/Futures/FutureQueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/Futures/FutureQueryFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/Futures/FutureQueryFixture.cs 2009-01-27 03:49:11 UTC (rev 4003) @@ -0,0 +1,122 @@ +using NHibernate.Criterion; +using NHibernate.Impl; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.Futures +{ + using System.Collections; + + [TestFixture] + public class FutureQueryFixture : TestCase + { + + protected override IList Mappings + { + get { return new string[] { "NHSpecificTest.Futures.Mappings.hbm.xml" }; } + } + + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + [Test] + public void CanUseFutureQuery() + { + using (var s = sessions.OpenSession()) + { + if (((SessionFactoryImpl)sessions) + .ConnectionProvider.Driver.SupportsMultipleQueries == false) + { + Assert.Ignore("Not applicable for dialects that do not support multiple queries"); + } + + var persons10 = s.CreateQuery("from Person") + .SetMaxResults(10) + .Future<Person>(); + var persons5 = s.CreateQuery("from Person") + .SetMaxResults(5) + .Future<int>(); + + using (var logSpy = new SqlLogSpy()) + { + foreach (var person in persons5) + { + + } + + foreach (var person in persons10) + { + + } + + var events = logSpy.Appender.GetEvents(); + Assert.AreEqual(1, events.Length); + } + } + } + + [Test] + public void TwoFuturesRunInTwoRoundTrips() + { + using (var s = sessions.OpenSession()) + { + if (((SessionFactoryImpl)sessions) + .ConnectionProvider.Driver.SupportsMultipleQueries == false) + { + Assert.Ignore("Not applicable for dialects that do not support multiple queries"); + } + + using (var logSpy = new SqlLogSpy()) + { + var persons10 = s.CreateQuery("from Person") + .SetMaxResults(10) + .Future<Person>(); + + foreach (var person in persons10) { } // fire first future round-trip + + var persons5 = s.CreateQuery("from Person") + .SetMaxResults(5) + .Future<int>(); + + foreach (var person in persons5) { } // fire second future round-trip + + var events = logSpy.Appender.GetEvents(); + Assert.AreEqual(2, events.Length); + } + } + } + + [Test] + public void CanCombineSingleFutureValueWithEnumerableFutures() + { + using (var s = sessions.OpenSession()) + { + if (((SessionFactoryImpl)sessions) + .ConnectionProvider.Driver.SupportsMultipleQueries == false) + { + Assert.Ignore("Not applicable for dialects that do not support multiple queries"); + } + + var persons = s.CreateQuery("from Person") + .SetMaxResults(10) + .Future<Person>(); + + var personCount = s.CreateQuery("select count(*) from Person") + .FutureValue<long>(); + + using (var logSpy = new SqlLogSpy()) + { + long count = personCount.Value; + + foreach (var person in persons) + { + } + + var events = logSpy.Appender.GetEvents(); + Assert.AreEqual(1, events.Length); + } + } + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-01-26 23:00:00 UTC (rev 4002) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-01-27 03:49:11 UTC (rev 4003) @@ -2,7 +2,7 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.30729</ProductVersion> + <ProductVersion>9.0.21022</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{7AEE5B37-C552-4E59-9B6F-88755BCB5070}</ProjectGuid> <OutputType>Library</OutputType> @@ -373,6 +373,7 @@ <Compile Include="NHSpecificTest\BasicTimeFixture.cs" /> <Compile Include="NHSpecificTest\BugTestCase.cs" /> <Compile Include="NHSpecificTest\CollectionFixture.cs" /> + <Compile Include="NHSpecificTest\Futures\FutureQueryFixture.cs" /> <Compile Include="NHSpecificTest\Futures\Fixture.cs" /> <Compile Include="NHSpecificTest\Futures\Person.cs" /> <Compile Include="NHSpecificTest\NH1274ExportExclude\Home.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |