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