From: <ric...@us...> - 2009-11-05 17:46:42
|
Revision: 4821 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4821&view=rev Author: ricbrown Date: 2009-11-05 17:46:33 +0000 (Thu, 05 Nov 2009) Log Message: ----------- Initial stab at sub-query syntax for QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/DetachedCriteria.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/DetachedCriteria.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/DetachedCriteria.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate/Criterion/DetachedCriteria.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -45,7 +45,7 @@ criteria = impl; } - protected DetachedCriteria(CriteriaImpl impl, ICriteria criteria) + protected internal DetachedCriteria(CriteriaImpl impl, ICriteria criteria) { this.impl = impl; this.criteria = criteria; Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -9,16 +9,34 @@ namespace NHibernate.Criterion { + [Serializable] + public class QueryOver + { + + protected ICriteria _criteria; + protected CriteriaImpl _impl; + + protected QueryOver() { } + + public ICriteria UnderlyingCriteria + { + get { return _criteria; } + } + + public DetachedCriteria DetachedCriteria + { + get { return new DetachedCriteria(_impl, _impl); } + } + + } + /// <summary> /// Implementation of the <see cref="IQueryOver<T>"/> interface /// </summary> [Serializable] - public class QueryOver<T> : IQueryOver<T> + public class QueryOver<T> : QueryOver, IQueryOver<T> { - private ICriteria _criteria; - private CriteriaImpl _impl; - public QueryOver() { _impl = new CriteriaImpl(typeof(T), null); @@ -44,9 +62,15 @@ _criteria = criteria; } - public ICriteria UnderlyingCriteria + /// <summary> + /// Method to allow comparison of detached query in Lambda expression + /// e.g., p => p.Name == myQuery.As<string> + /// </summary> + /// <typeparam name="T">type returned by query</typeparam> + /// <returns>throws an exception if evaluated directly at runtime.</returns> + public R As<R>() { - get { return _criteria; } + throw new HibernateException("Incorrect syntax; .As<T> method is for use in Lambda expressions only."); } public QueryOver<T> And(Expression<Func<T, bool>> expression) @@ -146,6 +170,11 @@ return this; } + QueryOverSubqueryBuilder<T> WithSubquery + { + get { return new QueryOverSubqueryBuilder<T>(this); } + } + public QueryOverFetchBuilder<T> Fetch(Expression<Func<T, object>> path) { return new QueryOverFetchBuilder<T>(this, path); @@ -469,6 +498,9 @@ IQueryOver<T> IQueryOver<T>.CacheRegion(string cacheRegion) { return CacheRegion(cacheRegion); } + IQueryOverSubqueryBuilder<T> IQueryOver<T>.WithSubquery + { get { return new IQueryOverSubqueryBuilder<T>(this); } } + IQueryOverFetchBuilder<T> IQueryOver<T>.Fetch(Expression<Func<T, object>> path) { return new IQueryOverFetchBuilder<T>(this, path); } Added: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -0,0 +1,59 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion +{ + + public class QueryOverSubqueryBuilder<T> : QueryOverSubqueryBuilderBase<QueryOver<T>, T, QueryOverSubqueryPropertyBuilder<T>> + { + + public QueryOverSubqueryBuilder(QueryOver<T> root) + : base(root) { } + + } + + public class IQueryOverSubqueryBuilder<T> : QueryOverSubqueryBuilderBase<IQueryOver<T>, T, IQueryOverSubqueryPropertyBuilder<T>> + { + + public IQueryOverSubqueryBuilder(IQueryOver<T> root) + : base(root) { } + + } + + public class QueryOverSubqueryBuilderBase<R, T, S> + where R : IQueryOver<T> + where S : QueryOverSubqueryPropertyBuilderBase, new() + { + + protected R root; + + protected QueryOverSubqueryBuilderBase(R root) + { + this.root = root; + } + + /// <summary> + /// Subquery expression in the format + /// .Where(t => t.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R Where(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.Exact, expression); + root.And(criterion); + return root; + } + + public S WhereProperty(Expression<Func<T, object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return (S) new S().Set(root, property); + } + + } + +} Added: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -0,0 +1,65 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion +{ + + public class QueryOverSubqueryPropertyBuilder<T> : QueryOverSubqueryPropertyBuilderBase<QueryOver<T>, T> + { + + public QueryOverSubqueryPropertyBuilder() + : base() { } + + } + + public class IQueryOverSubqueryPropertyBuilder<T> : QueryOverSubqueryPropertyBuilderBase<IQueryOver<T>, T> + { + + public IQueryOverSubqueryPropertyBuilder() + : base() { } + + } + + public abstract class QueryOverSubqueryPropertyBuilderBase + { + protected QueryOverSubqueryPropertyBuilderBase() { } + + public abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path); + } + + public class QueryOverSubqueryPropertyBuilderBase<R, T> : QueryOverSubqueryPropertyBuilderBase + where R : IQueryOver<T> + { + + protected R root; + protected string path; + + protected QueryOverSubqueryPropertyBuilderBase() + { + } + + public override QueryOverSubqueryPropertyBuilderBase Set(object root, string path) + { + this.root = (R)root; + this.path = path; + return this; + } + + /// <summary> + /// Add a property equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Eq(QueryOver<T> detachedCriteria) + { + root.Where(Subqueries.PropertyEq(path, detachedCriteria.DetachedCriteria)); + return root; + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -137,6 +137,11 @@ IQueryOver<T> CacheRegion(string cacheRegion); /// <summary> + /// Add a subquery expression + /// </summary> + IQueryOverSubqueryBuilder<T> WithSubquery { get; } + + /// <summary> /// Specify an association fetching strategy. Currently, only /// one-to-many and one-to-one associations are supported. /// </summary> Modified: trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -176,11 +176,11 @@ MethodCallExpression methodCallExpression = expression as MethodCallExpression; if (methodCallExpression == null) - throw new Exception("right operand should be detachedCriteriaInstance.As<T>() - " + expression.ToString()); + throw new Exception("right operand should be detachedQueryInstance.As<T>() - " + expression.ToString()); - var criteriaExpression = Expression.Lambda(methodCallExpression.Arguments[0]).Compile(); - object detachedCriteria = criteriaExpression.DynamicInvoke(); - return (DetachedCriteria)detachedCriteria; + var criteriaExpression = Expression.Lambda(methodCallExpression.Object).Compile(); + QueryOver detachedQuery = (QueryOver)criteriaExpression.DynamicInvoke(); + return detachedQuery.DetachedCriteria; } private static bool EvaluatesToNull(Expression expression) Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-05 17:46:33 UTC (rev 4821) @@ -509,6 +509,8 @@ <Compile Include="Criterion\QueryOverJoinBuilder.cs" /> <Compile Include="Criterion\QueryOverLockBuilder.cs" /> <Compile Include="Criterion\QueryOverOrderBuilder.cs" /> + <Compile Include="Criterion\QueryOverSubqueryBuilder.cs" /> + <Compile Include="Criterion\QueryOverSubqueryPropertyBuilder.cs" /> <Compile Include="Dialect\MsSql2008Dialect.cs" /> <Compile Include="Dialect\InformixDialect0940.cs" /> <Compile Include="Dialect\InformixDialect1000.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -12,7 +12,7 @@ { [TestFixture] - public class TestExpressionProcessor + public class ExpressionProcessorFixture { [Test] Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -60,17 +60,21 @@ AssertObjectsAreEqual(expected, ((QueryOver<T>)actual).UnderlyingCriteria); } - protected void AssertCriteriaAreEqual<T>(DetachedCriteria expected, QueryOver<T> actual) + protected DetachedCriteria ToDetachedCriteria<T>(QueryOver<T> actual) { ICriteria criteria = actual.UnderlyingCriteria; CriteriaImpl criteriaImpl = (CriteriaImpl) typeof(QueryOver<T>).GetField("_impl", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(actual); - DetachedCriteria actualDetached = (DetachedCriteria) + return (DetachedCriteria) typeof(DetachedCriteria).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new System.Type[] { typeof(CriteriaImpl), typeof(ICriteria) }, null) .Invoke(new object[] { criteriaImpl, criteria }); + } + protected void AssertCriteriaAreEqual<T>(DetachedCriteria expected, QueryOver<T> actual) + { + DetachedCriteria actualDetached = ToDetachedCriteria(actual); AssertObjectsAreEqual(expected, actualDetached); } Added: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-05 17:46:33 UTC (rev 4821) @@ -0,0 +1,88 @@ +using System; +using System.Collections; + +using NUnit.Framework; + +using NHibernate.Criterion; +using NHibernate.SqlCommand; +using NHibernate.Transform; +using NHibernate.Type; +using NHibernate.Util; + +namespace NHibernate.Test.Criteria.Lambda +{ + + [TestFixture] + public class SubqueryFixture : LambdaFixtureBase + { + + private Person _subqueryPersonAlias = null; + + private DetachedCriteria DetachedCriteriaPerson + { + get + { + return ToDetachedCriteria(DetachedQueryOverPerson); + } + } + + private DetachedCriteria DetachedCriteriaName + { + get + { + return ToDetachedCriteria(DetachedQueryOverName); + } + } + + private QueryOver<Person> DetachedQueryOverPerson + { + get + { + return + new QueryOver<Person>(() => _subqueryPersonAlias) + .Where(() => _subqueryPersonAlias.Name == "subquery name"); + } + } + + private QueryOver<Person> DetachedQueryOverName + { + get + { + return + new QueryOver<Person>(() => _subqueryPersonAlias) + .Where(() => _subqueryPersonAlias.Name == "subquery name") + .Select(p => p.Name); + } + } + + [Test] + public void Property() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereProperty(p => p.Name).Eq(DetachedQueryOverName); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void PropertyAsSyntax() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.Where(p => p.Name == DetachedQueryOverName.As<string>()); + + AssertCriteriaAreEqual(expected, actual); + } + + } + +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-05 17:19:23 UTC (rev 4820) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-05 17:46:33 UTC (rev 4821) @@ -160,6 +160,7 @@ <Compile Include="Criteria\Lambda\IntegrationFixture.cs" /> <Compile Include="Criteria\Lambda\LambdaFixtureBase.cs" /> <Compile Include="Criteria\Lambda\Model.cs" /> + <Compile Include="Criteria\Lambda\SubqueryFixture.cs" /> <Compile Include="Criteria\MaterialResource.cs" /> <Compile Include="Criteria\ProjectionsTest.cs" /> <Compile Include="Criteria\Reptile.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |