You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(248) |
May
(82) |
Jun
(90) |
Jul
(177) |
Aug
(253) |
Sep
(157) |
Oct
(151) |
Nov
(143) |
Dec
(278) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(152) |
Feb
(107) |
Mar
(177) |
Apr
(133) |
May
(259) |
Jun
(81) |
Jul
(119) |
Aug
(306) |
Sep
(416) |
Oct
(240) |
Nov
(329) |
Dec
(206) |
2006 |
Jan
(466) |
Feb
(382) |
Mar
(153) |
Apr
(162) |
May
(133) |
Jun
(21) |
Jul
(18) |
Aug
(37) |
Sep
(97) |
Oct
(114) |
Nov
(110) |
Dec
(28) |
2007 |
Jan
(74) |
Feb
(65) |
Mar
(49) |
Apr
(76) |
May
(43) |
Jun
(15) |
Jul
(68) |
Aug
(55) |
Sep
(63) |
Oct
(59) |
Nov
(70) |
Dec
(66) |
2008 |
Jan
(71) |
Feb
(60) |
Mar
(120) |
Apr
(31) |
May
(48) |
Jun
(81) |
Jul
(107) |
Aug
(51) |
Sep
(80) |
Oct
(83) |
Nov
(83) |
Dec
(79) |
2009 |
Jan
(83) |
Feb
(110) |
Mar
(97) |
Apr
(91) |
May
(291) |
Jun
(250) |
Jul
(197) |
Aug
(58) |
Sep
(54) |
Oct
(122) |
Nov
(68) |
Dec
(34) |
2010 |
Jan
(50) |
Feb
(17) |
Mar
(63) |
Apr
(61) |
May
(84) |
Jun
(81) |
Jul
(138) |
Aug
(144) |
Sep
(78) |
Oct
(26) |
Nov
(30) |
Dec
(61) |
2011 |
Jan
(33) |
Feb
(35) |
Mar
(166) |
Apr
(221) |
May
(109) |
Jun
(76) |
Jul
(27) |
Aug
(37) |
Sep
(1) |
Oct
(4) |
Nov
(2) |
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
(2) |
Apr
(2) |
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2013 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(1) |
Sep
(3) |
Oct
(2) |
Nov
|
Dec
(1) |
2014 |
Jan
(1) |
Feb
(1) |
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <ric...@us...> - 2009-11-19 16:04:51
|
Revision: 4839 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4839&view=rev Author: ricbrown Date: 2009-11-19 16:04:43 +0000 (Thu, 19 Nov 2009) Log Message: ----------- Added typed inline restrictions to QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs Added: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs 2009-11-19 16:04:43 UTC (rev 4839) @@ -0,0 +1,169 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class QueryOverRestrictionBuilder<T> : QueryOverRestrictionBuilderBase<QueryOver<T>, T> + { + + public QueryOverRestrictionBuilder(QueryOver<T> root, string propertyName) + : base(root, propertyName) { } + + } + + public class IQueryOverRestrictionBuilder<T> : QueryOverRestrictionBuilderBase<IQueryOver<T>, T> + { + + public IQueryOverRestrictionBuilder(IQueryOver<T> root, string propertyName) + : base(root, propertyName) { } + + } + + public class QueryOverRestrictionBuilderBase<R, T> + where R : IQueryOver<T> + { + public class LambdaBetweenBuilder + { + private R root; + private string propertyName; + private object lo; + + public LambdaBetweenBuilder(R root, string propertyName, object lo) + { + this.root = root; + this.propertyName = propertyName; + this.lo = lo; + } + + public R And(object hi) + { + return (R)root.And(Restrictions.Between(propertyName, lo, hi)); + } + } + + private R root; + private string propertyName; + + /// <summary> + /// Constructed with property name + /// </summary> + public QueryOverRestrictionBuilderBase(R root, string propertyName) + { + this.root = root; + this.propertyName = propertyName; + } + + /// <summary> + /// Apply a "between" constraint to the named property + /// </summary> + public LambdaBetweenBuilder IsBetween(object lo) + { + return new LambdaBetweenBuilder(root, propertyName, lo); + } + + /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public R IsIn(ICollection values) + { + return (R)root.And(Restrictions.In(propertyName, values)); + } + + /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public R IsIn(object[] values) + { + return (R)root.And(Restrictions.In(propertyName, values)); + } + + /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public R IsInG<T>(ICollection<T> values) + { + return (R)root.And(Restrictions.InG(propertyName, values)); + } + + /// <summary> + /// A case-insensitive "like", similar to Postgres "ilike" operator + /// </summary> + public R IsInsensitiveLike(object value) + { + return (R)root.And(Restrictions.InsensitiveLike(propertyName, value)); + } + + /// <summary> + /// A case-insensitive "like", similar to Postgres "ilike" operator + /// </summary> + public R IsInsensitiveLike(string value, MatchMode matchMode) + { + return (R)root.And(Restrictions.InsensitiveLike(propertyName, value, matchMode)); + } + + /// <summary> + /// Apply an "is empty" constraint to the named property + /// </summary> + public R IsEmpty + { + get { return (R)root.And(Restrictions.IsEmpty(propertyName)); } + } + + /// <summary> + /// Apply a "not is empty" constraint to the named property + /// </summary> + public R IsNotEmpty + { + get { return (R)root.And(Restrictions.IsNotEmpty(propertyName)); } + } + + /// <summary> + /// Apply an "is null" constraint to the named property + /// </summary> + public R IsNull + { + get { return (R)root.And(Restrictions.IsNull(propertyName)); } + } + + /// <summary> + /// Apply an "not is null" constraint to the named property + /// </summary> + public R IsNotNull + { + get { return (R)root.And(Restrictions.IsNotNull(propertyName)); } + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public R IsLike(object value) + { + return (R)root.And(Restrictions.Like(propertyName, value)); + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public R IsLike(string value, MatchMode matchMode) + { + return (R)root.And(Restrictions.Like(propertyName, value, matchMode)); + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public R IsLike(string value, MatchMode matchMode, char? escapeChar) + { + return (R)root.And(Restrictions.Like(propertyName, value, matchMode, escapeChar)); + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-19 14:46:12 UTC (rev 4838) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-19 16:04:43 UTC (rev 4839) @@ -89,6 +89,16 @@ return Add(expression); } + public QueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<T, object>> expression) + { + return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + public QueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<object>> expression) + { + return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + } + public QueryOver<T> Where(Expression<Func<T, bool>> expression) { return Add(expression); @@ -104,6 +114,16 @@ return Add(expression); } + public QueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<T, object>> expression) + { + return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + public QueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<object>> expression) + { + return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + } + public QueryOver<T> Select(params Expression<Func<T, object>>[] projections) { List<IProjection> projectionList = new List<IProjection>(); @@ -457,6 +477,12 @@ IQueryOver<T> IQueryOver<T>.And(ICriterion expression) { return And(expression); } + IQueryOverRestrictionBuilder<T> IQueryOver<T>.AndRestrictionOn(Expression<Func<T, object>> expression) + { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + + IQueryOverRestrictionBuilder<T> IQueryOver<T>.AndRestrictionOn(Expression<Func<object>> expression) + { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOver<T> IQueryOver<T>.Where(Expression<Func<T, bool>> expression) { return Where(expression); } @@ -466,6 +492,12 @@ IQueryOver<T> IQueryOver<T>.Where(ICriterion expression) { return Where(expression); } + IQueryOverRestrictionBuilder<T> IQueryOver<T>.WhereRestrictionOn(Expression<Func<T, object>> expression) + { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + + IQueryOverRestrictionBuilder<T> IQueryOver<T>.WhereRestrictionOn(Expression<Func<object>> expression) + { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOver<T> IQueryOver<T>.Select(params Expression<Func<T, object>>[] projections) { return Select(projections); } Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-19 14:46:12 UTC (rev 4838) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-19 16:04:43 UTC (rev 4839) @@ -50,6 +50,20 @@ IQueryOver<T> And(ICriterion expression); /// <summary> + /// Add restriction to a property + /// </summary> + /// <param name="expression">Lambda expression containing path to property</param> + /// <returns>criteria instance</returns> + IQueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<T, object>> expression); + + /// <summary> + /// Add restriction to a property + /// </summary> + /// <param name="expression">Lambda expression containing path to property</param> + /// <returns>criteria instance</returns> + IQueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<object>> expression); + + /// <summary> /// Identical semantics to Add() to allow more readable queries /// </summary> /// <param name="expression">Lambda expression</param> @@ -69,6 +83,20 @@ IQueryOver<T> Where(ICriterion expression); /// <summary> + /// Identical semantics to AndRestrictionOn() to allow more readable queries + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<T, object>> expression); + + /// <summary> + /// Identical semantics to AndRestrictionOn() to allow more readable queries + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<object>> expression); + + /// <summary> /// Add projection expressed as a lambda expression /// </summary> /// <param name="projections">Lambda expressions</param> Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 14:46:12 UTC (rev 4838) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 16:04:43 UTC (rev 4839) @@ -512,6 +512,7 @@ <Compile Include="Criterion\Lambda\QueryOverJoinBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverLockBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverOrderBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverRestrictionBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryPropertyBuilder.cs" /> <Compile Include="Dialect\MsSql2008Dialect.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 14:46:12 UTC (rev 4838) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 16:04:43 UTC (rev 4839) @@ -105,6 +105,68 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void SqlOperatorsInline() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Restrictions.Between("Age", 18, 65)) + .Add(Restrictions.Between("personAlias.Age", 18, 65)) + .Add(Restrictions.In("Name", new string[] { "name1", "name2", "name3" })) + .Add(Restrictions.In("personAlias.Name", new ArrayList() { "name1", "name2", "name3" })) + .Add(Restrictions.InG<int>("Age", new int[] { 1, 2, 3 })) + .Add(Restrictions.InsensitiveLike("Name", "test")) + .Add(Restrictions.InsensitiveLike("Name", "tEsT", MatchMode.Anywhere)) + .Add(Restrictions.IsEmpty("Children")) + .Add(Restrictions.IsNotEmpty("Children")) + .Add(Restrictions.IsNotNull("Name")) + .Add(Restrictions.IsNull("Name")) + .Add(Restrictions.Like("Name", "%test%")) + .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere)) + .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere, '?')); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .WhereRestrictionOn(p => p.Age).IsBetween(18).And(65) + .WhereRestrictionOn(() => personAlias.Age).IsBetween(18).And(65) + .AndRestrictionOn(p => p.Name).IsIn(new string[] { "name1", "name2", "name3" }) + .AndRestrictionOn(() => personAlias.Name).IsIn(new ArrayList() { "name1", "name2", "name3" }) + .AndRestrictionOn(p => p.Age).IsInG<int>(new int[] { 1, 2, 3 }) + .AndRestrictionOn(p => p.Name).IsInsensitiveLike("test") + .AndRestrictionOn(p => p.Name).IsInsensitiveLike("tEsT", MatchMode.Anywhere) + .AndRestrictionOn(p => p.Children).IsEmpty + .AndRestrictionOn(p => p.Children).IsNotEmpty + .AndRestrictionOn(p => p.Name).IsNotNull + .AndRestrictionOn(p => p.Name).IsNull + .AndRestrictionOn(p => p.Name).IsLike("%test%") + .AndRestrictionOn(p => p.Name).IsLike("test", MatchMode.Anywhere) + .AndRestrictionOn(p => p.Name).IsLike("test", MatchMode.Anywhere, '?'); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void DetachedRestrictions() + { + DetachedCriteria expected = + DetachedCriteria.For<Person>("personAlias") + .Add(Restrictions.Between("Age", 18, 65)) + .Add(Restrictions.Between("personAlias.Age", 18, 65)) + .Add(Restrictions.In("Name", new string[] { "name1", "name2", "name3" })) + .Add(Restrictions.In("personAlias.Name", new ArrayList() { "name1", "name2", "name3" })); + + Person personAlias = null; + QueryOver<Person> actual = + new QueryOver<Person>(() => personAlias) + .WhereRestrictionOn(p => p.Age).IsBetween(18).And(65) + .WhereRestrictionOn(() => personAlias.Age).IsBetween(18).And(65) + .AndRestrictionOn(p => p.Name).IsIn(new string[] { "name1", "name2", "name3" }) + .AndRestrictionOn(() => personAlias.Name).IsIn(new ArrayList() { "name1", "name2", "name3" }); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-19 14:46:25
|
Revision: 4838 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4838&view=rev Author: ricbrown Date: 2009-11-19 14:46:12 +0000 (Thu, 19 Nov 2009) Log Message: ----------- Added remaining Restrictions overloads for lambda expressions. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Junction.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/NaturalIdentifier.cs trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaNaturalIdentifierBuilder.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/Junction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Junction.cs 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate/Criterion/Junction.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -1,9 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; using NHibernate.Engine; +using NHibernate.Impl; using NHibernate.SqlCommand; using NHibernate.Util; -using System.Collections.Generic; namespace NHibernate.Criterion { @@ -31,6 +33,28 @@ } /// <summary> + /// Adds an <see cref="ICriterion"/> to the list of <see cref="ICriterion"/>s + /// to junction together. + /// </summary> + public Junction Add<T>(Expression<Func<T, bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression<T>(expression); + criteria.Add(criterion); + return this; + } + + /// <summary> + /// Adds an <see cref="ICriterion"/> to the list of <see cref="ICriterion"/>s + /// to junction together. + /// </summary> + public Junction Add(Expression<Func<bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression(expression); + criteria.Add(criterion); + return this; + } + + /// <summary> /// Get the Sql operator to put between multiple <see cref="ICriterion"/>s. /// </summary> protected abstract String Op { get; } Added: trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaNaturalIdentifierBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaNaturalIdentifierBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaNaturalIdentifierBuilder.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -0,0 +1,31 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class LambdaNaturalIdentifierBuilder + { + private NaturalIdentifier naturalIdentifier; + private string propertyName; + + public LambdaNaturalIdentifierBuilder(NaturalIdentifier naturalIdentifier, string propertyName) + { + this.naturalIdentifier = naturalIdentifier; + this.propertyName = propertyName; + } + + public NaturalIdentifier Is(object value) + { + return naturalIdentifier.Set(propertyName, value); + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -1,5 +1,6 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq.Expressions; @@ -47,6 +48,30 @@ } /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public AbstractCriterion IsIn(ICollection values) + { + return Restrictions.In(propertyName, values); + } + + /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public AbstractCriterion IsIn(object[] values) + { + return Restrictions.In(propertyName, values); + } + + /// <summary> + /// Apply an "in" constraint to the named property + /// </summary> + public AbstractCriterion IsInG<T>(ICollection<T> values) + { + return Restrictions.InG(propertyName, values); + } + + /// <summary> /// A case-insensitive "like", similar to Postgres "ilike" operator /// </summary> public AbstractCriterion IsInsensitiveLike(object value) Modified: trunk/nhibernate/src/NHibernate/Criterion/NaturalIdentifier.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/NaturalIdentifier.cs 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate/Criterion/NaturalIdentifier.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Criterion.Lambda; using NHibernate.Engine; +using NHibernate.Impl; using NHibernate.SqlCommand; namespace NHibernate.Criterion @@ -31,5 +34,17 @@ conjunction.Add(Restrictions.Eq(property, value)); return this; } + + public LambdaNaturalIdentifierBuilder Set<T>(Expression<Func<T, object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaNaturalIdentifierBuilder(this, property); + } + + public LambdaNaturalIdentifierBuilder Set(Expression<Func<object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaNaturalIdentifierBuilder(this, property); + } } } Modified: trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -760,11 +760,34 @@ } /// <summary> + /// Create an ICriterion for the negation of the supplied LambdaExpression + /// </summary> + /// <typeparam name="T">generic type</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>return NHibernate.Criterion.ICriterion</returns> + public static ICriterion WhereNot<T>(Expression<Func<T, bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression<T>(expression); + return Restrictions.Not(criterion); + } + + /// <summary> + /// Create an ICriterion for the negation of the supplied LambdaExpression + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>return NHibernate.Criterion.ICriterion</returns> + public static ICriterion WhereNot(Expression<Func<bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression(expression); + return Restrictions.Not(criterion); + } + + /// <summary> /// Build an ICriterion for the given property /// </summary> /// <param name="expression">lambda expression identifying property</param> /// <returns>returns LambdaRestrictionBuilder</returns> - public static LambdaRestrictionBuilder WhereProperty<T>(Expression<Func<T, object>> expression) + public static LambdaRestrictionBuilder On<T>(Expression<Func<T, object>> expression) { string property = ExpressionProcessor.FindMemberExpression(expression.Body); return new LambdaRestrictionBuilder(property); @@ -775,7 +798,7 @@ /// </summary> /// <param name="expression">lambda expression identifying property</param> /// <returns>returns LambdaRestrictionBuilder</returns> - public static LambdaRestrictionBuilder WhereProperty(Expression<Func<object>> expression) + public static LambdaRestrictionBuilder On(Expression<Func<object>> expression) { string property = ExpressionProcessor.FindMemberExpression(expression.Body); return new LambdaRestrictionBuilder(property); Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 14:46:12 UTC (rev 4838) @@ -505,6 +505,7 @@ <Compile Include="Context\WcfOperationSessionContext.cs" /> <Compile Include="Criterion\GroupedProjection.cs" /> <Compile Include="Criterion\IPropertyProjection.cs" /> + <Compile Include="Criterion\Lambda\LambdaNaturalIdentifierBuilder.cs" /> <Compile Include="Criterion\Lambda\LambdaRestrictionBuilder.cs" /> <Compile Include="Criterion\Lambda\LambdaSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverFetchBuilder.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 12:31:20 UTC (rev 4837) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 14:46:12 UTC (rev 4838) @@ -18,24 +18,31 @@ ICriteria expected = CreateTestCriteria(typeof(Person), "personAlias") .Add(Restrictions.Lt("Age", 65)) - .Add(Restrictions.Ge("personAlias.Age", 18)); + .Add(Restrictions.Ge("personAlias.Age", 18)) + .Add(Restrictions.Not(Restrictions.Ge("Age", 65))) + .Add(Restrictions.Not(Restrictions.Lt("personAlias.Age", 18))); Person personAlias = null; var actual = CreateTestQueryOver<Person>(() => personAlias) .Where(Restrictions.Where<Person>(p => p.Age < 65)) - .And(Restrictions.Where(() => personAlias.Age >= 18)); + .And(Restrictions.Where(() => personAlias.Age >= 18)) + .And(Restrictions.WhereNot<Person>(p => p.Age >= 65)) + .And(Restrictions.WhereNot(() => personAlias.Age < 18)); AssertCriteriaAreEqual(expected, actual); } [Test] - public void SqlFunctions() + public void SqlOperators() { ICriteria expected = CreateTestCriteria(typeof(Person), "personAlias") .Add(Restrictions.Between("Age", 18, 65)) .Add(Restrictions.Between("personAlias.Age", 18, 65)) + .Add(Restrictions.In("Name", new string[] { "name1", "name2", "name3" })) + .Add(Restrictions.In("Name", new ArrayList() { "name1", "name2", "name3" })) + .Add(Restrictions.InG<int>("Age", new int[] { 1, 2, 3 })) .Add(Restrictions.InsensitiveLike("Name", "test")) .Add(Restrictions.InsensitiveLike("Name", "tEsT", MatchMode.Anywhere)) .Add(Restrictions.IsEmpty("Children")) @@ -44,26 +51,60 @@ .Add(Restrictions.IsNull("Name")) .Add(Restrictions.Like("Name", "%test%")) .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere)) - .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere, '?')); + .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere, '?')) + .Add(Restrictions.NaturalId() + .Set("Name", "my name") + .Set("personAlias.Age", 18)); Person personAlias = null; var actual = CreateTestQueryOver<Person>(() => personAlias) - .Where(Restrictions.WhereProperty<Person>(p => p.Age).IsBetween(18).And(65)) - .And(Restrictions.WhereProperty(() => personAlias.Age).IsBetween(18).And(65)) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsInsensitiveLike("test")) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsInsensitiveLike("tEsT", MatchMode.Anywhere)) - .And(Restrictions.WhereProperty<Person>(p => p.Children).IsEmpty) - .And(Restrictions.WhereProperty<Person>(p => p.Children).IsNotEmpty) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsNotNull) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsNull) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("%test%")) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere)) - .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere, '?')); + .Where(Restrictions.On<Person>(p => p.Age).IsBetween(18).And(65)) + .And(Restrictions.On(() => personAlias.Age).IsBetween(18).And(65)) + .And(Restrictions.On<Person>(p => p.Name).IsIn(new string[] { "name1", "name2", "name3" })) + .And(Restrictions.On<Person>(p => p.Name).IsIn(new ArrayList() { "name1", "name2", "name3" })) + .And(Restrictions.On<Person>(p => p.Age).IsInG<int>(new int[] { 1, 2, 3 })) + .And(Restrictions.On<Person>(p => p.Name).IsInsensitiveLike("test")) + .And(Restrictions.On<Person>(p => p.Name).IsInsensitiveLike("tEsT", MatchMode.Anywhere)) + .And(Restrictions.On<Person>(p => p.Children).IsEmpty) + .And(Restrictions.On<Person>(p => p.Children).IsNotEmpty) + .And(Restrictions.On<Person>(p => p.Name).IsNotNull) + .And(Restrictions.On<Person>(p => p.Name).IsNull) + .And(Restrictions.On<Person>(p => p.Name).IsLike("%test%")) + .And(Restrictions.On<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere)) + .And(Restrictions.On<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere, '?')) + .And(Restrictions.NaturalId() + .Set<Person>(p => p.Name).Is("my name") + .Set(() => personAlias.Age).Is(18)); AssertCriteriaAreEqual(expected, actual); } + [Test] + public void Junction() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Restrictions.Conjunction() + .Add(Restrictions.Eq("Name", "test")) + .Add(Restrictions.Eq("personAlias.Name", "test"))) + .Add(Restrictions.Disjunction() + .Add(Restrictions.Eq("Name", "test")) + .Add(Restrictions.Eq("personAlias.Name", "test"))); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .Where(Restrictions.Conjunction() + .Add<Person>(p => p.Name == "test") + .Add(() => personAlias.Name == "test")) + .And(Restrictions.Disjunction() + .Add<Person>(p => p.Name == "test") + .Add(() => personAlias.Name == "test")); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-19 12:31:29
|
Revision: 4837 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4837&view=rev Author: ricbrown Date: 2009-11-19 12:31:20 +0000 (Thu, 19 Nov 2009) Log Message: ----------- Added more Restrictions overloads for lambda expressions. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs Added: trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaRestrictionBuilder.cs 2009-11-19 12:31:20 UTC (rev 4837) @@ -0,0 +1,123 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class LambdaRestrictionBuilder + { + public class LambdaBetweenBuilder + { + private string propertyName; + private object lo; + + public LambdaBetweenBuilder(string propertyName, object lo) + { + this.propertyName = propertyName; + this.lo = lo; + } + + public AbstractCriterion And(object hi) + { + return Restrictions.Between(propertyName, lo, hi); + } + } + + private string propertyName; + + /// <summary> + /// Constructed with property name + /// </summary> + public LambdaRestrictionBuilder(string propertyName) + { + this.propertyName = propertyName; + } + + /// <summary> + /// Apply a "between" constraint to the named property + /// </summary> + public LambdaBetweenBuilder IsBetween(object lo) + { + return new LambdaBetweenBuilder(propertyName, lo); + } + + /// <summary> + /// A case-insensitive "like", similar to Postgres "ilike" operator + /// </summary> + public AbstractCriterion IsInsensitiveLike(object value) + { + return Restrictions.InsensitiveLike(propertyName, value); + } + + /// <summary> + /// A case-insensitive "like", similar to Postgres "ilike" operator + /// </summary> + public AbstractCriterion IsInsensitiveLike(string value, MatchMode matchMode) + { + return Restrictions.InsensitiveLike(propertyName, value, matchMode); + } + + /// <summary> + /// Apply an "is empty" constraint to the named property + /// </summary> + public AbstractEmptinessExpression IsEmpty + { + get { return Restrictions.IsEmpty(propertyName); } + } + + /// <summary> + /// Apply a "not is empty" constraint to the named property + /// </summary> + public AbstractEmptinessExpression IsNotEmpty + { + get { return Restrictions.IsNotEmpty(propertyName); } + } + + /// <summary> + /// Apply an "is null" constraint to the named property + /// </summary> + public AbstractCriterion IsNull + { + get { return Restrictions.IsNull(propertyName); } + } + + /// <summary> + /// Apply an "not is null" constraint to the named property + /// </summary> + public AbstractCriterion IsNotNull + { + get { return Restrictions.IsNotNull(propertyName); } + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public SimpleExpression IsLike(object value) + { + return Restrictions.Like(propertyName, value); + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public SimpleExpression IsLike(string value, MatchMode matchMode) + { + return Restrictions.Like(propertyName, value, matchMode); + } + + /// <summary> + /// Apply a "like" constraint to the named property + /// </summary> + public AbstractCriterion IsLike(string value, MatchMode matchMode, char? escapeChar) + { + return Restrictions.Like(propertyName, value, matchMode, escapeChar); + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-19 11:15:09 UTC (rev 4836) +++ trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-19 12:31:20 UTC (rev 4837) @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq.Expressions; +using NHibernate.Criterion.Lambda; using NHibernate.Impl; namespace NHibernate.Criterion @@ -758,5 +759,27 @@ return criterion; } + /// <summary> + /// Build an ICriterion for the given property + /// </summary> + /// <param name="expression">lambda expression identifying property</param> + /// <returns>returns LambdaRestrictionBuilder</returns> + public static LambdaRestrictionBuilder WhereProperty<T>(Expression<Func<T, object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaRestrictionBuilder(property); + } + + /// <summary> + /// Build an ICriterion for the given property + /// </summary> + /// <param name="expression">lambda expression identifying property</param> + /// <returns>returns LambdaRestrictionBuilder</returns> + public static LambdaRestrictionBuilder WhereProperty(Expression<Func<object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaRestrictionBuilder(property); + } + } } Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 11:15:09 UTC (rev 4836) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-19 12:31:20 UTC (rev 4837) @@ -505,6 +505,7 @@ <Compile Include="Context\WcfOperationSessionContext.cs" /> <Compile Include="Criterion\GroupedProjection.cs" /> <Compile Include="Criterion\IPropertyProjection.cs" /> + <Compile Include="Criterion\Lambda\LambdaRestrictionBuilder.cs" /> <Compile Include="Criterion\Lambda\LambdaSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverFetchBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverJoinBuilder.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 11:15:09 UTC (rev 4836) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 12:31:20 UTC (rev 4837) @@ -29,6 +29,41 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void SqlFunctions() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Restrictions.Between("Age", 18, 65)) + .Add(Restrictions.Between("personAlias.Age", 18, 65)) + .Add(Restrictions.InsensitiveLike("Name", "test")) + .Add(Restrictions.InsensitiveLike("Name", "tEsT", MatchMode.Anywhere)) + .Add(Restrictions.IsEmpty("Children")) + .Add(Restrictions.IsNotEmpty("Children")) + .Add(Restrictions.IsNotNull("Name")) + .Add(Restrictions.IsNull("Name")) + .Add(Restrictions.Like("Name", "%test%")) + .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere)) + .Add(Restrictions.Like("Name", "test", MatchMode.Anywhere, '?')); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .Where(Restrictions.WhereProperty<Person>(p => p.Age).IsBetween(18).And(65)) + .And(Restrictions.WhereProperty(() => personAlias.Age).IsBetween(18).And(65)) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsInsensitiveLike("test")) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsInsensitiveLike("tEsT", MatchMode.Anywhere)) + .And(Restrictions.WhereProperty<Person>(p => p.Children).IsEmpty) + .And(Restrictions.WhereProperty<Person>(p => p.Children).IsNotEmpty) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsNotNull) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsNull) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("%test%")) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere)) + .And(Restrictions.WhereProperty<Person>(p => p.Name).IsLike("test", MatchMode.Anywhere, '?')); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-19 11:15:19
|
Revision: 4836 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4836&view=rev Author: ricbrown Date: 2009-11-19 11:15:09 +0000 (Thu, 19 Nov 2009) Log Message: ----------- Added missing modifier on QueryOver.WithSubquery. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-19 10:05:05 UTC (rev 4835) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-19 11:15:09 UTC (rev 4836) @@ -171,7 +171,7 @@ return this; } - QueryOverSubqueryBuilder<T> WithSubquery + public QueryOverSubqueryBuilder<T> WithSubquery { get { return new QueryOverSubqueryBuilder<T>(this); } } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-19 10:05:05 UTC (rev 4835) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-19 11:15:09 UTC (rev 4836) @@ -103,6 +103,23 @@ } [Test] + public void DetachedSubquery() + { + DetachedCriteria expected = + DetachedCriteria.For<Person>("personAlias") + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyEq("personAlias.Name", DetachedCriteriaName)); + + Person personAlias = null; + QueryOver<Person> actual = + new QueryOver<Person>(() => personAlias) + .WithSubquery.WhereProperty(p => p.Name).Eq(DetachedQueryOverName) + .WithSubquery.WhereProperty(() => personAlias.Name).Eq(DetachedQueryOverName); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyCriterion() { ICriteria expected = This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-19 10:05:25
|
Revision: 4835 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4835&view=rev Author: ricbrown Date: 2009-11-19 10:05:05 +0000 (Thu, 19 Nov 2009) Log Message: ----------- Added arbitrary ICriterion creation from Lambda expression. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-18 15:17:20 UTC (rev 4834) +++ trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2009-11-19 10:05:05 UTC (rev 4835) @@ -1,5 +1,8 @@ +using System; using System.Collections; using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Impl; namespace NHibernate.Criterion { @@ -731,5 +734,29 @@ { return new NaturalIdentifier(); } + + /// <summary> + /// Create an ICriterion for the supplied LambdaExpression + /// </summary> + /// <typeparam name="T">generic type</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>return NHibernate.Criterion.ICriterion</returns> + public static ICriterion Where<T>(Expression<Func<T, bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression<T>(expression); + return criterion; + } + + /// <summary> + /// Create an ICriterion for the supplied LambdaExpression + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>return NHibernate.Criterion.ICriterion</returns> + public static ICriterion Where(Expression<Func<bool>> expression) + { + ICriterion criterion = ExpressionProcessor.ProcessExpression(expression); + return criterion; + } + } } Added: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-19 10:05:05 UTC (rev 4835) @@ -0,0 +1,34 @@ +using System; +using System.Collections; + +using NUnit.Framework; + +using NHibernate.Criterion; + +namespace NHibernate.Test.Criteria.Lambda +{ + + [TestFixture] + public class RestrictionsFixture : LambdaFixtureBase + { + + [Test] + public void ArbitraryCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Restrictions.Lt("Age", 65)) + .Add(Restrictions.Ge("personAlias.Age", 18)); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .Where(Restrictions.Where<Person>(p => p.Age < 65)) + .And(Restrictions.Where(() => personAlias.Age >= 18)); + + 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-18 15:17:20 UTC (rev 4834) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-19 10:05:05 UTC (rev 4835) @@ -164,6 +164,7 @@ <Compile Include="Criteria\Lambda\IntegrationFixture.cs" /> <Compile Include="Criteria\Lambda\LambdaFixtureBase.cs" /> <Compile Include="Criteria\Lambda\Model.cs" /> + <Compile Include="Criteria\Lambda\RestrictionsFixture.cs" /> <Compile Include="Criteria\Lambda\SubqueryFixture.cs" /> <Compile Include="Criteria\MaterialResource.cs" /> <Compile Include="Criteria\ProjectionsTest.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-18 15:17:28
|
Revision: 4834 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4834&view=rev Author: ricbrown Date: 2009-11-18 15:17:20 +0000 (Wed, 18 Nov 2009) Log Message: ----------- Added Subqueries overloads to create ICriterion for QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaSubqueryBuilder.cs Added: trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaSubqueryBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/LambdaSubqueryBuilder.cs 2009-11-18 15:17:20 UTC (rev 4834) @@ -0,0 +1,195 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class LambdaSubqueryBuilder + { + private string propertyName; + private object value; + + /// <summary> + /// Constructed with property name + /// </summary> + public LambdaSubqueryBuilder(string propertyName, object value) + { + this.propertyName = propertyName; + this.value = value; + } + + private AbstractCriterion CreatePropertyCriterion<U>( Func<string, DetachedCriteria, AbstractCriterion> propertyFactoryMethod, + Func<object, DetachedCriteria, AbstractCriterion> valueFactoryMethod, + QueryOver<U> detachedCriteria) + { + if (propertyName != null) + { + return propertyFactoryMethod(propertyName, detachedCriteria.DetachedCriteria); + } + else + { + return valueFactoryMethod(value, detachedCriteria.DetachedCriteria); + } + } + + /// <summary> + /// Add a property equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Eq<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyEq, Subqueries.Eq, detachedCriteria); + } + + /// <summary> + /// Add a property equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion EqAll<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyEqAll, Subqueries.EqAll, detachedCriteria); + } + + /// <summary> + /// Create a property greater than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Ge<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGe, Subqueries.Ge, detachedCriteria); + } + + /// <summary> + /// Create a property greater than or equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion GeAll<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGeAll, Subqueries.GeAll, detachedCriteria); + } + + /// <summary> + /// Create a property greater than or equal some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion GeSome<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGeSome, Subqueries.GeSome, detachedCriteria); + } + + /// <summary> + /// Create a property greater than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Gt<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGt, Subqueries.Gt, detachedCriteria); + } + + /// <summary> + /// Create a property greater than all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion GtAll<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGtAll, Subqueries.GtAll, detachedCriteria); + } + + /// <summary> + /// Create a property greater than some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion GtSome<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyGtSome, Subqueries.GtSome, detachedCriteria); + } + + /// <summary> + /// Create a property in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion In<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyIn, Subqueries.In, detachedCriteria); + } + + /// <summary> + /// Create a property less than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Le<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLe, Subqueries.Le, detachedCriteria); + } + + /// <summary> + /// Create a property less than or equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion LeAll<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLeAll, Subqueries.LeAll, detachedCriteria); + } + + /// <summary> + /// Create a property less than or equal some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion LeSome<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLeSome, Subqueries.LeSome, detachedCriteria); + } + + /// <summary> + /// Create a property less than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Lt<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLt, Subqueries.Lt, detachedCriteria); + } + + /// <summary> + /// Create a property less than all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion LtAll<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLtAll, Subqueries.LtAll, detachedCriteria); + } + + /// <summary> + /// Create a property less than some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion LtSome<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyLtSome, Subqueries.LtSome, detachedCriteria); + } + + /// <summary> + /// Create a property not equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion Ne<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyNe, Subqueries.Ne, detachedCriteria); + } + + /// <summary> + /// Create a property not in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public AbstractCriterion NotIn<U>(QueryOver<U> detachedCriteria) + { + return CreatePropertyCriterion(Subqueries.PropertyNotIn, Subqueries.NotIn, detachedCriteria); + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs 2009-11-18 12:29:32 UTC (rev 4833) +++ trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs 2009-11-18 15:17:20 UTC (rev 4834) @@ -1,5 +1,9 @@ using System; +using System.Linq.Expressions; +using NHibernate.Criterion.Lambda; +using NHibernate.Impl; + namespace NHibernate.Criterion { /// <summary> @@ -195,5 +199,124 @@ { return new SelectSubqueryExpression(detachedCriteria); } + + /// <summary> + /// Create a ICriterion for the specified property subquery expression + /// </summary> + /// <typeparam name="T">generic type</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>returns LambdaSubqueryBuilder</returns> + public static LambdaSubqueryBuilder WhereProperty<T>(Expression<Func<T, object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaSubqueryBuilder(property, null); + } + + /// <summary> + /// Create a ICriterion for the specified property subquery expression + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>returns LambdaSubqueryBuilder</returns> + public static LambdaSubqueryBuilder WhereProperty(Expression<Func<object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return new LambdaSubqueryBuilder(property, null); + } + + /// <summary> + /// Create a ICriterion for the specified value subquery expression + /// </summary> + /// <param name="value">value</param> + /// <returns>returns LambdaSubqueryBuilder</returns> + public static LambdaSubqueryBuilder WhereValue(object value) + { + return new LambdaSubqueryBuilder(null, value); + } + + /// <summary> + /// Create ICriterion for subquery expression using lambda syntax + /// </summary> + /// <typeparam name="T">type of property</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion Where<T>(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.Exact, expression); + return criterion; + } + + /// <summary> + /// Create ICriterion for (exact) subquery expression using lambda syntax + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion Where(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.Exact, expression); + return criterion; + } + + /// <summary> + /// Create ICriterion for (all) subquery expression using lambda syntax + /// </summary> + /// <typeparam name="T">type of property</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion WhereAll<T>(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.All, expression); + return criterion; + } + + /// <summary> + /// Create ICriterion for (all) subquery expression using lambda syntax + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion WhereAll(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.All, expression); + return criterion; + } + + /// <summary> + /// Create ICriterion for (some) subquery expression using lambda syntax + /// </summary> + /// <typeparam name="T">type of property</typeparam> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion WhereSome<T>(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.Some, expression); + return criterion; + } + + /// <summary> + /// Create ICriterion for (some) subquery expression using lambda syntax + /// </summary> + /// <param name="expression">lambda expression</param> + /// <returns>NHibernate.ICriterion.AbstractCriterion</returns> + public static AbstractCriterion WhereSome(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.Some, expression); + return criterion; + } + + /// <summary> + /// Add an Exists subquery criterion + /// </summary> + public static AbstractCriterion WhereExists<U>(QueryOver<U> detachedQuery) + { + return Subqueries.Exists(detachedQuery.DetachedCriteria); + } + + /// <summary> + /// Add a NotExists subquery criterion + /// </summary> + public static AbstractCriterion WhereNotExists<U>(QueryOver<U> detachedQuery) + { + return Subqueries.NotExists(detachedQuery.DetachedCriteria); + } + } } Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-18 12:29:32 UTC (rev 4833) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-18 15:17:20 UTC (rev 4834) @@ -505,6 +505,7 @@ <Compile Include="Context\WcfOperationSessionContext.cs" /> <Compile Include="Criterion\GroupedProjection.cs" /> <Compile Include="Criterion\IPropertyProjection.cs" /> + <Compile Include="Criterion\Lambda\LambdaSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverFetchBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverJoinBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverLockBuilder.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-18 12:29:32 UTC (rev 4833) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-18 15:17:20 UTC (rev 4834) @@ -103,6 +103,34 @@ } [Test] + public void PropertyCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGt("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyIn("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyLe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLt("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyNe("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyNotIn("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereProperty<Person>(p => p.Name).Eq(DetachedQueryOverName)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).Ge(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).Gt(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Name).In(DetachedQueryOverName)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).Le(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).Lt(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Name).Ne(DetachedQueryOverName)) + .And(Subqueries.WhereProperty<Person>(p => p.Name).NotIn(DetachedQueryOverName)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAlias() { ICriteria expected = @@ -118,6 +146,21 @@ } [Test] + public void PropertyAliasCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Subqueries.PropertyEq("personAlias.Name", DetachedCriteriaName)); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .And(Subqueries.WhereProperty(() => personAlias.Name).Eq(DetachedQueryOverName)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAll() { ICriteria expected = @@ -140,6 +183,28 @@ } [Test] + public void PropertyAllCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereProperty<Person>(p => p.Name).EqAll(DetachedQueryOverName)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).GeAll(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).GtAll(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).LeAll(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).LtAll(DetachedQueryOverAge)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertySome() { ICriteria expected = @@ -160,6 +225,26 @@ } [Test] + public void PropertySomeCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyGeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereProperty<Person>(p => p.Age).GeSome(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).GtSome(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).LeSome(DetachedQueryOverAge)) + .And(Subqueries.WhereProperty<Person>(p => p.Age).LtSome(DetachedQueryOverAge)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAsSyntax() { ICriteria expected = @@ -184,6 +269,20 @@ } [Test] + public void PropertyAsSyntaxCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.Where<Person>(p => p.Name == DetachedQueryOverName.As<string>())); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAsSyntaxAlias() { ICriteria expected = @@ -203,6 +302,25 @@ } [Test] + public void PropertyAsSyntaxAliasCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Subqueries.PropertyEq("personAlias.Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGtSome("personAlias.Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("personAlias.Age", DetachedCriteriaAge)); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .And(Subqueries.Where(() => personAlias.Name == DetachedQueryOverName.As<string>())) + .And(Subqueries.WhereSome(() => personAlias.Age > DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereAll(() => personAlias.Age < DetachedQueryOverAge.As<int>())); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAsAllSyntax() { ICriteria expected = @@ -225,6 +343,28 @@ } [Test] + public void PropertyAsAllSyntaxCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereAll<Person>(p => p.Name == DetachedQueryOverName.As<string>())) + .And(Subqueries.WhereAll<Person>(p => p.Age >= DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereAll<Person>(p => p.Age > DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereAll<Person>(p => p.Age <= DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereAll<Person>(p => p.Age < DetachedQueryOverAge.As<int>())); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAsSomeSyntax() { ICriteria expected = @@ -245,6 +385,26 @@ } [Test] + public void PropertyAsSomeSyntaxCrtierion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyGeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereSome<Person>(p => p.Age >= DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereSome<Person>(p => p.Age > DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereSome<Person>(p => p.Age <= DetachedQueryOverAge.As<int>())) + .And(Subqueries.WhereSome<Person>(p => p.Age < DetachedQueryOverAge.As<int>())); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void Value() { ICriteria expected = @@ -273,6 +433,34 @@ } [Test] + public void ValueCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.Eq("Name", DetachedCriteriaName)) + .Add(Subqueries.Ge("Age", DetachedCriteriaAge)) + .Add(Subqueries.Gt("Age", DetachedCriteriaAge)) + .Add(Subqueries.In("Name", DetachedCriteriaName)) + .Add(Subqueries.Le("Age", DetachedCriteriaAge)) + .Add(Subqueries.Lt("Age", DetachedCriteriaAge)) + .Add(Subqueries.Ne("Name", DetachedCriteriaName)) + .Add(Subqueries.NotIn("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereValue("Name").Eq(DetachedQueryOverName)) + .And(Subqueries.WhereValue("Age").Ge(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").Gt(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Name").In(DetachedQueryOverName)) + .And(Subqueries.WhereValue("Age").Le(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").Lt(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Name").Ne(DetachedQueryOverName)) + .And(Subqueries.WhereValue("Name").NotIn(DetachedQueryOverName)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void ValueAll() { ICriteria expected = @@ -295,6 +483,28 @@ } [Test] + public void ValueAllCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.EqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.GeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.GtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.LeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.LtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereValue("Name").EqAll(DetachedQueryOverName)) + .And(Subqueries.WhereValue("Age").GeAll(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").GtAll(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").LeAll(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").LtAll(DetachedQueryOverAge)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void ValueSome() { ICriteria expected = @@ -315,6 +525,26 @@ } [Test] + public void ValueSomeCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.GeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.GtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.LeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.LtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereValue("Age").GeSome(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").GtSome(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").LeSome(DetachedQueryOverAge)) + .And(Subqueries.WhereValue("Age").LtSome(DetachedQueryOverAge)); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void UntypedSubqueries() { ICriteria expected = @@ -330,6 +560,22 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void UntypedSubqueriesCriterion() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.Exists(DetachedCriteriaChild)) + .Add(Subqueries.NotExists(DetachedCriteriaChild)); + + var actual = + CreateTestQueryOver<Person>() + .And(Subqueries.WhereExists(DetachedQueryOverChild)) + .And(Subqueries.WhereNotExists(DetachedQueryOverChild)); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-18 13:13:32
|
Revision: 4833 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4833&view=rev Author: ricbrown Date: 2009-11-18 12:29:32 +0000 (Wed, 18 Nov 2009) Log Message: ----------- Added extra support for nullable bool and enum to QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs Modified: trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs 2009-11-15 15:39:52 UTC (rev 4832) +++ trunk/nhibernate/src/NHibernate/Impl/ExpressionProcessor.cs 2009-11-18 12:29:32 UTC (rev 4833) @@ -124,6 +124,13 @@ if (memberExpression.Expression.NodeType == ExpressionType.MemberAccess || memberExpression.Expression.NodeType == ExpressionType.Call) { + if (IsNullableOfT(memberExpression.Member.DeclaringType)) + { + // it's a Nullable<T>, so ignore any .Value + if (memberExpression.Member.Name == "Value") + return FindMemberExpression(memberExpression.Expression); + } + return FindMemberExpression(memberExpression.Expression) + "." + memberExpression.Member.Name; } else @@ -258,6 +265,9 @@ if (type.IsAssignableFrom(value.GetType())) return value; + if (IsNullableOfT(type)) + type = Nullable.GetUnderlyingType(type); + if (type.IsEnum) return Enum.ToObject(type, value); @@ -267,6 +277,12 @@ throw new Exception("Cannot convert '" + value.ToString() + "' to " + type.ToString()); } + private static bool IsNullableOfT(System.Type type) + { + return type.IsGenericType + && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); + } + private static ICriterion ProcessSimpleExpression(BinaryExpression be) { string property = FindMemberExpression(be.Left); Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs 2009-11-15 15:39:52 UTC (rev 4832) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFixture.cs 2009-11-18 12:29:32 UTC (rev 4833) @@ -116,6 +116,38 @@ } } + [Test] + public void TestEvaluateNullableIntExpression() + { + ICriterion before = Restrictions.Eq("NullableAge", 5); + ICriterion after = ExpressionProcessor.ProcessExpression<Person>(p => p.NullableAge == 5); + Assert.AreEqual(before.ToString(), after.ToString()); + } + + [Test] + public void TestEvaluateNullableEnumExpression() + { + ICriterion before = Restrictions.Eq("NullableGender", PersonGender.Female); + ICriterion after = ExpressionProcessor.ProcessExpression<Person>(p => p.NullableGender == PersonGender.Female); + Assert.AreEqual(before.ToString(), after.ToString()); + } + + [Test] + public void TestEvaluateNullableEnumValueExpression() + { + ICriterion before = Restrictions.Eq("NullableGender", PersonGender.Female); + ICriterion after = ExpressionProcessor.ProcessExpression<Person>(p => p.NullableGender.Value == PersonGender.Female); + Assert.AreEqual(before.ToString(), after.ToString()); + } + + [Test] + public void TestEvaluateNullableBoolExpression() + { + ICriterion before = Restrictions.Eq("NullableIsParent", true); + ICriterion after = ExpressionProcessor.ProcessExpression<Person>(p => p.NullableIsParent.Value); + Assert.AreEqual(before.ToString(), after.ToString()); + } + } } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs 2009-11-15 15:39:52 UTC (rev 4832) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs 2009-11-18 12:29:32 UTC (rev 4833) @@ -25,6 +25,10 @@ public virtual bool IsParent { get; set; } public virtual char Blood { get; set; } + public virtual int? NullableAge { get; set; } + public virtual PersonGender? NullableGender { get; set; } + public virtual bool? NullableIsParent { get; set; } + public virtual IEnumerable<Child> Children { get; set; } public virtual IList<Person> PersonList { get; set; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-15 15:40:01
|
Revision: 4832 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4832&view=rev Author: ricbrown Date: 2009-11-15 15:39:52 +0000 (Sun, 15 Nov 2009) Log Message: ----------- Added compiler directives to allow tests to pass in Release build. Modified Paths: -------------- trunk/nhibernate/src/NHibernate.ByteCode.Castle.Tests/ProxyInterface/CastleProxyImpl.cs trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests/ProxyInterface/MyProxyImpl.cs trunk/nhibernate/src/NHibernate.ByteCode.Spring.Tests/ProxyInterface/MyProxyImpl.cs Modified: trunk/nhibernate/src/NHibernate.ByteCode.Castle.Tests/ProxyInterface/CastleProxyImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate.ByteCode.Castle.Tests/ProxyInterface/CastleProxyImpl.cs 2009-11-13 16:48:48 UTC (rev 4831) +++ trunk/nhibernate/src/NHibernate.ByteCode.Castle.Tests/ProxyInterface/CastleProxyImpl.cs 2009-11-15 15:39:52 UTC (rev 4832) @@ -9,11 +9,13 @@ [Serializable] public class CastleProxyImpl : CastleProxy { + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level1() { Level2(); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level2() { throw new ArgumentException("thrown from Level2"); Modified: trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests/ProxyInterface/MyProxyImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests/ProxyInterface/MyProxyImpl.cs 2009-11-13 16:48:48 UTC (rev 4831) +++ trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests/ProxyInterface/MyProxyImpl.cs 2009-11-15 15:39:52 UTC (rev 4832) @@ -4,11 +4,13 @@ { public class MyProxyImpl: IMyProxy { + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level1() { Level2(); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level2() { throw new ArgumentException("thrown from Level2"); Modified: trunk/nhibernate/src/NHibernate.ByteCode.Spring.Tests/ProxyInterface/MyProxyImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate.ByteCode.Spring.Tests/ProxyInterface/MyProxyImpl.cs 2009-11-13 16:48:48 UTC (rev 4831) +++ trunk/nhibernate/src/NHibernate.ByteCode.Spring.Tests/ProxyInterface/MyProxyImpl.cs 2009-11-15 15:39:52 UTC (rev 4832) @@ -4,11 +4,13 @@ { public class MyProxyImpl: IMyProxy { + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level1() { Level2(); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void Level2() { throw new ArgumentException("thrown from Level2"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-13 16:48:58
|
Revision: 4831 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4831&view=rev Author: steverstrong Date: 2009-11-13 16:48:48 +0000 (Fri, 13 Nov 2009) Log Message: ----------- Added System.Linq.Dynamic to list of references Modified Paths: -------------- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.build Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.build =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.build 2009-11-13 16:02:56 UTC (rev 4830) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.build 2009-11-13 16:48:48 UTC (rev 4831) @@ -23,6 +23,7 @@ <include name="LinFu.DynamicProxy.dll" /> <include name="nunit.framework.dll" /> <include name="Antlr3.Runtime.dll" /> + <include name="System.Linq.Dynamic.dll" /> </assemblyfileset> <resourcefileset id="project.resources" prefix="NHibernate.Test" dynamicprefix="true"> <include name="**/*.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-13 16:03:07
|
Revision: 4830 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4830&view=rev Author: steverstrong Date: 2009-11-13 16:02:56 +0000 (Fri, 13 Nov 2009) Log Message: ----------- Removed test that was causing compilation issues. To be investigated... Modified Paths: -------------- trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Linq/MethodCallTests.cs Modified: trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs 2009-11-13 15:44:38 UTC (rev 4829) +++ trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs 2009-11-13 16:02:56 UTC (rev 4830) @@ -1,6 +1,6 @@ using System; using System.Linq; -using System.Linq.Dynamic; +//using System.Linq.Dynamic; using NHibernate.Test.Linq.Entities; using NUnit.Framework; @@ -10,8 +10,10 @@ public class DynamicQueryTests : LinqTestCase { [Test] + [Ignore("TODO - works locally, but gives compile errors on teamcity")] public void CanQueryWithDynamicOrderBy() { + /* var query = from user in db.Users select user; @@ -27,6 +29,7 @@ Assert.IsTrue(previousDate <= user.RegisteredAt); previousDate = user.RegisteredAt; }); + */ } } } Added: trunk/nhibernate/src/NHibernate.Test/Linq/MethodCallTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/MethodCallTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/MethodCallTests.cs 2009-11-13 16:02:56 UTC (rev 4830) @@ -0,0 +1,32 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + [Ignore] + public class MethodCallTests : LinqTestCase + { + [Test] + public void CanExecuteAny() + { + bool result = db.Users.Any(); + Assert.IsTrue(result); + } + + [Test] + public void CanExecuteAnyWithArguments() + { + bool result = db.Users.Any(u => u.Name == "user-does-not-exist"); + Assert.IsFalse(result); + } + + [Test] + public void CanExecuteCountWithOrderByArguments() + { + var query = db.Users.OrderBy(u => u.Name); + int count = query.Count(); + Assert.AreEqual(3, count); + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-13 15:44:38 UTC (rev 4829) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-13 16:02:56 UTC (rev 4830) @@ -407,6 +407,7 @@ <Compile Include="Linq\FunctionTests.cs" /> <Compile Include="Linq\LinqQuerySamples.cs" /> <Compile Include="Linq\LinqTestCase.cs" /> + <Compile Include="Linq\MethodCallTests.cs" /> <Compile Include="Linq\MiscellaneousTextFixture.cs" /> <Compile Include="Linq\ObjectDumper.cs" /> <Compile Include="Linq\ParameterisedQueries.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-13 15:44:48
|
Revision: 4829 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4829&view=rev Author: steverstrong Date: 2009-11-13 15:44:38 +0000 (Fri, 13 Nov 2009) Log Message: ----------- More Linq test cases added Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/MsSql2000Dialect.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate.Test/HQL/HQLFunctions.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/lib/net/3.5/System.Linq.Dynamic.dll trunk/nhibernate/src/NHibernate.Test/Linq/BinaryExpressionOrdererTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/EnumTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/ExtensionMethods.cs trunk/nhibernate/src/NHibernate.Test/Linq/FunctionTests.cs Added: trunk/nhibernate/lib/net/3.5/System.Linq.Dynamic.dll =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/lib/net/3.5/System.Linq.Dynamic.dll ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2000Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2000Dialect.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2000Dialect.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -106,7 +106,9 @@ RegisterFunction("left", new SQLFunctionTemplate(NHibernateUtil.String, "left(?1, ?2)")); RegisterFunction("right", new SQLFunctionTemplate(NHibernateUtil.String, "right(?1, ?2)")); + RegisterFunction("locate", new StandardSQLFunction("charindex", NHibernateUtil.Int32)); + RegisterFunction("current_timestamp", new NoArgSQLFunction("getdate", NHibernateUtil.DateTime, true)); RegisterFunction("second", new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(second, ?1)")); RegisterFunction("minute", new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(minute, ?1)")); Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -146,30 +146,28 @@ { return new HqlNull(_factory); } - else + + switch (System.Type.GetTypeCode(value.GetType())) { - switch (System.Type.GetTypeCode(value.GetType())) - { - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - return new HqlIntegerConstant(_factory, value.ToString()); - case TypeCode.Single: - return new HqlFloatConstant(_factory, value.ToString()); - case TypeCode.Double: - return new HqlDoubleConstant(_factory, value.ToString()); - case TypeCode.Decimal: - return new HqlDecimalConstant(_factory, value.ToString()); - case TypeCode.String: - case TypeCode.Char: - return new HqlStringConstant(_factory, "\'" + value + "\'"); - case TypeCode.DateTime: - return new HqlStringConstant(_factory, "\'" + ((DateTime)value).ToString() + "\'"); - case TypeCode.Boolean: - return new HqlStringConstant(_factory, "\'" + (((bool)value) ? "true" : "false") + "\'"); - default: - throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", value)); - } + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + return new HqlIntegerConstant(_factory, value.ToString()); + case TypeCode.Single: + return new HqlFloatConstant(_factory, value.ToString()); + case TypeCode.Double: + return new HqlDoubleConstant(_factory, value.ToString()); + case TypeCode.Decimal: + return new HqlDecimalConstant(_factory, value.ToString()); + case TypeCode.String: + case TypeCode.Char: + return new HqlStringConstant(_factory, "\'" + value + "\'"); + case TypeCode.DateTime: + return new HqlStringConstant(_factory, "\'" + (DateTime)value + "\'"); + case TypeCode.Boolean: + return new HqlStringConstant(_factory, "\'" + ((bool)value ? "true" : "false") + "\'"); + default: + throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", value)); } } @@ -348,11 +346,16 @@ return new HqlExpressionList(_factory); } - public HqlMethodCall MethodCall(string methodName, HqlExpression parameter) + public HqlMethodCall MethodCall(string methodName, IEnumerable<HqlExpression> parameters) { - return new HqlMethodCall(_factory, methodName, parameter); + return new HqlMethodCall(_factory, methodName, parameters); } + public HqlMethodCall MethodCall(string methodName, params HqlExpression[] parameters) + { + return new HqlMethodCall(_factory, methodName, parameters); + } + public HqlDistinctHolder DistinctHolder(params HqlTreeNode[] children) { return new HqlDistinctHolder(_factory, children); Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using NHibernate.Hql.Ast.ANTLR; using NHibernate.Hql.Ast.ANTLR.Tree; @@ -126,6 +127,11 @@ : base(type, text, factory, children) { } + + protected HqlStatement(int type, string text, IASTFactory factory, IEnumerable<HqlTreeNode> children) + : base(type, text, factory, children) + { + } } public abstract class HqlExpression : HqlTreeNode @@ -407,7 +413,7 @@ public class HqlOrderBy : HqlStatement { public HqlOrderBy(IASTFactory factory) - : base(HqlSqlWalker.ORDER, "", factory) + : base(HqlSqlWalker.ORDER, "order by", factory) { } } @@ -559,9 +565,15 @@ public class HqlExpressionList : HqlStatement { - public HqlExpressionList(IASTFactory factory, params HqlTreeNode[] expression) : base(HqlSqlWalker.EXPR_LIST, "expr_list", factory, expression) + public HqlExpressionList(IASTFactory factory, params HqlExpression[] expressions) + : base(HqlSqlWalker.EXPR_LIST, "expr_list", factory, expressions) { } + + public HqlExpressionList(IASTFactory factory, IEnumerable<HqlExpression> expressions) + : base(HqlSqlWalker.EXPR_LIST, "expr_list", factory, expressions.Cast<HqlTreeNode>()) + { + } } public class HqlNot : HqlBooleanExpression @@ -686,11 +698,11 @@ public class HqlMethodCall : HqlExpression { - public HqlMethodCall(IASTFactory factory, string methodName, HqlExpression parameter) + public HqlMethodCall(IASTFactory factory, string methodName, IEnumerable<HqlExpression> parameters) : base(HqlSqlWalker.METHOD_CALL, "method", factory) { AddChild(new HqlIdent(factory, methodName)); - AddChild(new HqlExpressionList(factory, parameter)); + AddChild(new HqlExpressionList(factory, parameters)); } } Modified: trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -1,7 +1,29 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Linq.Expressions; using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; +namespace NHibernate.Linq +{ + public class LinqExtensionMethodAttribute : Attribute + { + public string Name { get; private set; } + + public LinqExtensionMethodAttribute() + { + } + + public LinqExtensionMethodAttribute(string name) + { + Name = name; + } + } +} + namespace NHibernate.Linq.Functions { public class FunctionRegistry @@ -35,6 +57,15 @@ return methodGenerator; } + // No method generator registered. Look to see if it's a standard LinqExtensionMethod + var attr = (LinqExtensionMethodAttribute) method.GetCustomAttributes(typeof (LinqExtensionMethodAttribute), false)[0]; + if (attr != null) + { + // It is + // TODO - cache this? Is it worth it? + return new HqlGeneratorForExtensionMethod(attr, method); + } + throw new NotSupportedException(method.ToString()); } @@ -66,4 +97,36 @@ typeMethodGenerator.Register(this); } } + + public class HqlGeneratorForExtensionMethod : BaseHqlGeneratorForMethod + { + private readonly string _name; + + public HqlGeneratorForExtensionMethod(LinqExtensionMethodAttribute attribute, MethodInfo method) + { + _name = string.IsNullOrEmpty(attribute.Name) ? method.Name : attribute.Name; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + var args = visitor.Visit(targetObject) + .Union(arguments.Select(a => visitor.Visit(a))) + .Cast<HqlExpression>(); + + return treeBuilder.MethodCall(_name, args); + } + } + + static class UnionExtension + { + public static IEnumerable<HqlTreeNode> Union(this HqlTreeNode first, IEnumerable<HqlTreeNode> rest) + { + yield return first; + + foreach (var x in rest) + { + yield return x; + } + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -16,6 +16,9 @@ MethodRegistry.Add(new ContainsGenerator()); MethodRegistry.Add(new EqualsGenerator()); MethodRegistry.Add(new ToUpperLowerGenerator()); + MethodRegistry.Add(new SubStringGenerator()); + MethodRegistry.Add(new IndexOfGenerator()); + MethodRegistry.Add(new ReplaceGenerator()); PropertyRegistry.Add(new LengthGenerator()); } @@ -129,5 +132,78 @@ return treeBuilder.MethodCall(methodName, visitor.Visit(targetObject).AsExpression()); } } + + class SubStringGenerator : BaseHqlGeneratorForMethod + { + public SubStringGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod<string>(s => s.Substring(0)), + ReflectionHelper.GetMethod<string>(s => s.Substring(0, 0)) + }; + } + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + if (arguments.Count == 1) + { + return treeBuilder.MethodCall("substring", visitor.Visit(targetObject).AsExpression(), + treeBuilder.Constant(0), + visitor.Visit(arguments[0]).AsExpression()); + } + + return treeBuilder.MethodCall("substring", visitor.Visit(targetObject).AsExpression(), + visitor.Visit(arguments[0]).AsExpression(), + visitor.Visit(arguments[1]).AsExpression()); + } + } + + class IndexOfGenerator : BaseHqlGeneratorForMethod + { + public IndexOfGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod<string>(s => s.IndexOf(' ')), + ReflectionHelper.GetMethod<string>(s => s.IndexOf(" ")), + ReflectionHelper.GetMethod<string>(s => s.IndexOf(' ', 0)), + ReflectionHelper.GetMethod<string>(s => s.IndexOf(" ", 0)) + }; + } + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + if (arguments.Count == 1) + { + return treeBuilder.MethodCall("locate", + visitor.Visit(arguments[0]).AsExpression(), + visitor.Visit(targetObject).AsExpression(), + treeBuilder.Constant(0)); + } + return treeBuilder.MethodCall("locate", + visitor.Visit(arguments[0]).AsExpression(), + visitor.Visit(targetObject).AsExpression(), + visitor.Visit(arguments[1]).AsExpression()); + } + } + + class ReplaceGenerator : BaseHqlGeneratorForMethod + { + public ReplaceGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod<string>(s => s.Replace(' ', ' ')), + ReflectionHelper.GetMethod<string>(s => s.Replace("", "")) + }; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + return treeBuilder.MethodCall("replace", + visitor.Visit(targetObject).AsExpression(), + visitor.Visit(arguments[0]).AsExpression(), + visitor.Visit(arguments[1]).AsExpression()); + } + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -39,6 +39,8 @@ { _expression = PartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression); + _expression = NameUnNamedParameters.Visit(_expression); + _queryParameters = ExpressionParameterVisitor.Visit(_expression); ParameterValuesByName = _queryParameters.Values.ToDictionary(p => p.Name, p => p.Value); @@ -57,9 +59,10 @@ } } - public IASTNode Translate(ISessionFactory sessionFactory) + public IASTNode Translate(ISessionFactory sessionFactory) { var requiredHqlParameters = new List<NamedParameterDescriptor>(); + // TODO - can we cache any of this? var queryModel = new QueryParser(new ExpressionTreeParser(MethodCallRegistry)).GetParsedQuery(_expression); @@ -89,6 +92,39 @@ } } + public class NameUnNamedParameters : NhExpressionTreeVisitor + { + public static Expression Visit(Expression expression) + { + var visitor = new NameUnNamedParameters(); + + return visitor.VisitExpression(expression); + } + + private readonly Dictionary<ParameterExpression, ParameterExpression> _renamedParameters = new Dictionary<ParameterExpression, ParameterExpression>(); + + protected override Expression VisitParameterExpression(ParameterExpression expression) + { + if (string.IsNullOrEmpty(expression.Name)) + { + ParameterExpression renamed; + + if (_renamedParameters.TryGetValue(expression, out renamed)) + { + return renamed; + } + + renamed = Expression.Parameter(expression.Type, Guid.NewGuid().ToString()); + + _renamedParameters.Add(expression, renamed); + + return renamed; + } + + return base.VisitParameterExpression(expression); + } + } + public class AggregateExpressionNode : ResultOperatorExpressionNodeBase { public MethodCallExpressionParseInfo ParseInfo { get; set; } Modified: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -39,7 +39,9 @@ public IQueryable CreateQuery(Expression expression) { - throw new NotImplementedException(); + var m = ReflectionHelper.GetMethod((NhQueryProvider p) => p.CreateQuery<object>(null)).MakeGenericMethod(expression.Type.GetGenericArguments()[0]); + + return (IQueryable) m.Invoke(this, new[] {expression}); } public IQueryable<T> CreateQuery<T>(Expression expression) Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -264,9 +264,11 @@ { case ExpressionType.Not: return _hqlTreeBuilder.Not(VisitExpression(expression.Operand).AsBooleanExpression()); + case ExpressionType.Convert: + return VisitExpression(expression.Operand); } - - throw new InvalidOperationException(); + + throw new NotSupportedException(expression.ToString()); } protected HqlTreeNode VisitMemberExpression(MemberExpression expression) @@ -313,7 +315,7 @@ _hqlTreeBuilder.Constant(1)); } - return _hqlTreeBuilder.Cast(_hqlTreeBuilder.Parameter(namedParameter.Name).AsExpression(), namedParameter.Value.GetType()); + return _hqlTreeBuilder.Parameter(namedParameter.Name).AsExpression(); } return _hqlTreeBuilder.Constant(expression.Value); @@ -346,7 +348,7 @@ ifFalse = VisitExpression(expression.IfFalse).AsExpression(); } - return _hqlTreeBuilder.Case(new []{when}, ifFalse); + return _hqlTreeBuilder.Cast(_hqlTreeBuilder.Case(new []{when}, ifFalse), expression.Type); } protected HqlTreeNode VisitSubQueryExpression(SubQueryExpression expression) Modified: trunk/nhibernate/src/NHibernate.Test/HQL/HQLFunctions.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQL/HQLFunctions.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate.Test/HQL/HQLFunctions.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -18,7 +18,7 @@ static HQLFunctions() { notSupportedStandardFunction.Add("locate", - new[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(MsSql2008Dialect) ,typeof(FirebirdDialect), typeof(PostgreSQLDialect) }); + new[] { typeof(FirebirdDialect), typeof(PostgreSQLDialect) }); notSupportedStandardFunction.Add("bit_length", new[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(MsSql2008Dialect), typeof(Oracle8iDialect), typeof(Oracle9iDialect), typeof(Oracle10gDialect) }); notSupportedStandardFunction.Add("extract", Added: trunk/nhibernate/src/NHibernate.Test/Linq/BinaryExpressionOrdererTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/BinaryExpressionOrdererTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/BinaryExpressionOrdererTests.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -0,0 +1,90 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class BinaryExpressionOrdererTests : LinqTestCase + { + [Test] + public void ValuePropertySwapsToPropertyValue() + { + var query = (from user in db.Users + where ("ayende" == user.Name) + select user).ToList(); + Assert.AreEqual(1, query.Count); + } + + [Test] + public void PropertyValueDoesntSwaps() + { + var query = (from user in db.Users + where (user.Name == "ayende") + select user).ToList(); + Assert.AreEqual(1, query.Count); + } + + [Test] + public void PropertyPropertyDoesntSwap() + { + var query = (from user in db.Users + where (user.Name == user.Name) + select user).ToList(); + Assert.AreEqual(3, query.Count); + } + + [Test] + public void EqualsSwapsToEquals() + { + var query = (from user in db.Users + where ("ayende" == user.Name) + select user).ToList(); + Assert.AreEqual(1, query.Count); + } + + [Test] + public void NotEqualsSwapsToNotEquals() + { + var query = (from user in db.Users + where ("ayende" != user.Name) + select user).ToList(); + Assert.AreEqual(2, query.Count); + } + + [Test] + public void GreaterThanSwapsToLessThan() + { + var query = (from user in db.Users + where (3 > user.Id) + select user).ToList(); + Assert.AreEqual(2, query.Count); + } + + [Test] + public void GreaterThanOrEqualToSwapsToLessThanOrEqualTo() + { + var query = (from user in db.Users + where (2 >= user.Id) + select user).ToList(); + Assert.AreEqual(2, query.Count); + } + + [Test] + public void LessThanSwapsToGreaterThan() + { + var query = (from user in db.Users + where (1 < user.Id) + select user).ToList(); + Assert.AreEqual(2, query.Count); + } + + [Test] + public void LessThanOrEqualToSwapsToGreaterThanOrEqualTo() + { + var query = (from user in db.Users + where (2 <= user.Id) + select user).ToList(); + Assert.AreEqual(2, query.Count); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/DynamicQueryTests.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -0,0 +1,32 @@ +using System; +using System.Linq; +using System.Linq.Dynamic; +using NHibernate.Test.Linq.Entities; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class DynamicQueryTests : LinqTestCase + { + [Test] + public void CanQueryWithDynamicOrderBy() + { + var query = from user in db.Users + select user; + + //dynamic orderby clause + query = query.OrderBy("RegisteredAt"); + + var list = query.ToList(); + + //assert list was returned in order + DateTime previousDate = DateTime.MinValue; + list.Each(delegate(User user) + { + Assert.IsTrue(previousDate <= user.RegisteredAt); + previousDate = user.RegisteredAt; + }); + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs 2009-11-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -56,5 +56,10 @@ { get { return _session.Query<Mammal>(); } } + + public IQueryable<User> Users + { + get { return _session.Query<User>(); } + } } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Linq/EnumTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/EnumTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/EnumTests.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -0,0 +1,55 @@ +using System.Linq; +using NHibernate.Test.Linq.Entities; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class EnumTests : LinqTestCase + { + [Test] + public void CanQueryOnEnumStoredAsInt32_High_1() + { + CanQueryOnEnumStoredAsInt32(EnumStoredAsInt32.High, 1); + } + + [Test] + public void CanQueryOnEnumStoredAsInt32_Unspecified_2() + { + CanQueryOnEnumStoredAsInt32(EnumStoredAsInt32.Unspecified, 2); + } + + + public void CanQueryOnEnumStoredAsInt32(EnumStoredAsInt32 type, int expectedCount) + { + var query = (from user in db.Users + where user.Enum2 == type + select user).ToList(); + + Assert.AreEqual(expectedCount, query.Count); + } + + [Test] + public void CanQueryOnEnumStoredAsString_Meduim_2() + { + CanQueryOnEnumStoredAsString(EnumStoredAsString.Medium, 2); + + } + + [Test] + public void CanQueryOnEnumStoredAsString_Small_1() + { + CanQueryOnEnumStoredAsString(EnumStoredAsString.Small, 1); + + } + + public void CanQueryOnEnumStoredAsString(EnumStoredAsString type, int expectedCount) + { + var query = (from user in db.Users + where user.Enum1 == type + select user).ToList(); + + Assert.AreEqual(expectedCount, query.Count); + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/Linq/ExtensionMethods.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/ExtensionMethods.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/ExtensionMethods.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -0,0 +1,19 @@ +using NHibernate.Linq; + +namespace NHibernate.Test.Linq +{ + static class ExtensionMethods + { + [LinqExtensionMethod("Replace")] + public static string ReplaceExtension(this string subject, string search, string replaceWith) + { + return null; + } + + [LinqExtensionMethod] + public static string Replace(this string subject, string search, string replaceWith) + { + return null; + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/Linq/FunctionTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/FunctionTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/FunctionTests.cs 2009-11-13 15:44:38 UTC (rev 4829) @@ -0,0 +1,85 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class FunctionTests : LinqTestCase + { + [Test] + public void SubstringFunction() + { + var query = from e in db.Employees + where e.FirstName.Substring(1, 2) == "An" + select e; + + ObjectDumper.Write(query); + } + + [Test] + public void LeftFunction() + { + var query = from e in db.Employees + where e.FirstName.Substring(1, 2) == "An" + select e.FirstName.Substring(3); + + ObjectDumper.Write(query); + } + + [Test] + public void ReplaceFunction() + { + var query = from e in db.Employees + where e.FirstName.StartsWith("An") + select new + { + Before = e.FirstName, + AfterMethod = e.FirstName.Replace("An", "Zan"), + AfterExtension = ExtensionMethods.Replace(e.FirstName, "An", "Zan"), + AfterExtension2 = e.FirstName.ReplaceExtension("An", "Zan") + }; + + string s = ObjectDumper.Write(query); + } + + [Test] + public void CharIndexFunction() + { + var query = from e in db.Employees + where e.FirstName.IndexOf('A') == 1 + select e.FirstName; + + ObjectDumper.Write(query); + } + + [Test] + public void IndexOfFunctionExpression() + { + var query = from e in db.Employees + where e.FirstName.IndexOf("An") == 1 + select e.FirstName; + + ObjectDumper.Write(query); + } + + [Test] + public void IndexOfFunctionProjection() + { + var query = from e in db.Employees + where e.FirstName.Contains("a") + select e.FirstName.IndexOf('A', 3); + + ObjectDumper.Write(query); + } + + [Test] + public void TwoFunctionExpression() + { + var query = from e in db.Employees + where e.FirstName.IndexOf("A") == e.BirthDate.Value.Month + select e.FirstName; + + ObjectDumper.Write(query); + } + } +} \ 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-11 13:37:38 UTC (rev 4828) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-13 15:44:38 UTC (rev 4829) @@ -73,6 +73,10 @@ </Reference> <Reference Include="System.Data" /> <Reference Include="System.Data.OracleClient" /> + <Reference Include="System.Linq.Dynamic, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\lib\net\3.5\System.Linq.Dynamic.dll</HintPath> + </Reference> <Reference Include="System.Transactions" /> <Reference Include="System.Xml" /> </ItemGroup> @@ -377,6 +381,8 @@ <Compile Include="LazyProperty\LazyPropertyFixture.cs" /> <Compile Include="Linq\AggregateTests.cs" /> <Compile Include="Linq\BinaryBooleanExpressionTests.cs" /> + <Compile Include="Linq\BinaryExpressionOrdererTests.cs" /> + <Compile Include="Linq\DynamicQueryTests.cs" /> <Compile Include="Linq\Entities\Address.cs" /> <Compile Include="Linq\Entities\Animal.cs" /> <Compile Include="Linq\Entities\AnotherEntity.cs" /> @@ -396,6 +402,9 @@ <Compile Include="Linq\Entities\Timesheet.cs" /> <Compile Include="Linq\Entities\User.cs" /> <Compile Include="Linq\Entities\UserComponent.cs" /> + <Compile Include="Linq\EnumTests.cs" /> + <Compile Include="Linq\ExtensionMethods.cs" /> + <Compile Include="Linq\FunctionTests.cs" /> <Compile Include="Linq\LinqQuerySamples.cs" /> <Compile Include="Linq\LinqTestCase.cs" /> <Compile Include="Linq\MiscellaneousTextFixture.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-11 13:37:59
|
Revision: 4828 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4828&view=rev Author: steverstrong Date: 2009-11-11 13:37:38 +0000 (Wed, 11 Nov 2009) Log Message: ----------- More Linq tests and improvement to the Hql tree generation code Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ConstructorNode.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/EqualityHqlGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ProjectionEvaluator.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Linq/Functions/ trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForMethod.cs trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForProperty.cs trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForType.cs trunk/nhibernate/src/NHibernate/Linq/Functions/DateTimeGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForMethod.cs trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForProperty.cs trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForType.cs trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/IHqlExpressionVisitor.cs trunk/nhibernate/src/NHibernate.Test/Linq/BinaryBooleanExpressionTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Animal.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/AnotherEntity.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Role.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Timesheet.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/User.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/UserComponent.cs trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Animal.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/AnotherEntity.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Role.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/TimeSheet.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/User.hbm.xml Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/BaseHqlGeneratorForProperty.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-11-10 18:07:01 UTC (rev 4827) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -17,11 +17,6 @@ private readonly IToken _token; private List<IASTNode> _children; - // TODO - currently just used for Constructor stuff in Linq. Should really have a subtype, - // and a new TreeFactory thingy for the Linq AST generator. But for now... - private object _hack; - public object Hack { get { return _hack; } set { _hack = value; } } - public ASTNode() : this((IToken)null) {} Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ConstructorNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ConstructorNode.cs 2009-11-10 18:07:01 UTC (rev 4827) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ConstructorNode.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -109,16 +109,7 @@ } else { - if (Hack != null && Hack is ConstructorInfo) - { - // The Linq parser has the constructor information available, so it can pass it straight through. - // Currently using nasty Hack property :) This *will* be improved! - _constructor = (ConstructorInfo)Hack; - } - else - { - _constructor = ResolveConstructor(path); - } + _constructor = ResolveConstructor(path); } } Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs 2009-11-10 18:07:01 UTC (rev 4827) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/HqlSqlWalkerTreeAdapter.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -176,15 +176,6 @@ { var dupped = (IASTNode) Create(node.Token); - // TODO - nasty hack for Linq. To be removed :). In general, should this just call the copy - // constructor or something? Then this may work for derived classes... (via a Create overload...) - ASTNode x = dupped as ASTNode; - ASTNode y = node as ASTNode; - if (x != null && y != null) - { - x.Hack = y.Hack; - } - dupped.Parent = node.Parent; return dupped; Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-10 18:07:01 UTC (rev 4827) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using NHibernate.Hql.Ast.ANTLR.Tree; namespace NHibernate.Hql.Ast @@ -70,11 +69,6 @@ return new HqlRange(_factory, ident); } - public HqlRange Range() - { - return new HqlRange(_factory); - } - public HqlRange Range(HqlTreeNode ident, HqlAlias alias) { return new HqlRange(_factory, ident, alias); @@ -95,49 +89,44 @@ return new HqlAlias(_factory, alias); } - public HqlEquality Equality() + public HqlEquality Equality(HqlExpression lhs, HqlExpression rhs) { - return new HqlEquality(_factory); - } - - public HqlEquality Equality(HqlTreeNode lhs, HqlTreeNode rhs) - { return new HqlEquality(_factory, lhs, rhs); } - public HqlBooleanAnd BooleanAnd() + public HqlBooleanAnd BooleanAnd(HqlBooleanExpression lhs, HqlBooleanExpression rhs) { - return new HqlBooleanAnd(_factory); + return new HqlBooleanAnd(_factory, lhs, rhs); } - public HqlBooleanOr BooleanOr() + public HqlBooleanOr BooleanOr(HqlBooleanExpression lhs, HqlBooleanExpression rhs) { - return new HqlBooleanOr(_factory); + return new HqlBooleanOr(_factory, lhs, rhs); } - public HqlAdd Add() + public HqlAdd Add(HqlExpression lhs, HqlExpression rhs) { - return new HqlAdd(_factory); + return new HqlAdd(_factory, lhs, rhs); } - public HqlSubtract Subtract() + public HqlSubtract Subtract(HqlExpression lhs, HqlExpression rhs) { - return new HqlSubtract(_factory); + return new HqlSubtract(_factory, lhs, rhs); } - public HqlMultiplty Multiply() + public HqlMultiplty Multiply(HqlExpression lhs, HqlExpression rhs) { - return new HqlMultiplty(_factory); + return new HqlMultiplty(_factory, lhs, rhs); } - public HqlDivide Divide() + public HqlDivide Divide(HqlExpression lhs, HqlExpression rhs) { - return new HqlDivide(_factory); + return new HqlDivide(_factory, lhs, rhs); } - public HqlDot Dot() + public HqlDot Dot(HqlExpression lhs, HqlExpression rhs) { - return new HqlDot(_factory); + return new HqlDot(_factory, lhs, rhs); } public HqlParameter Parameter(string name) @@ -145,16 +134,11 @@ return new HqlParameter(_factory, name); } - public HqlWhere Where(HqlTreeNode expression) + public HqlWhere Where(HqlExpression expression) { return new HqlWhere(_factory, expression); } - public HqlWhere Where() - { - return new HqlWhere(_factory); - } - // TODO - constant will be removed when we have parameter handling done properly. Particularly bad datetime handling here, so it'll be good to delete it :) public HqlConstant Constant(object value) { @@ -194,82 +178,72 @@ return new HqlOrderBy(_factory); } - public HqlOrderBy OrderBy(HqlTreeNode expression, HqlDirection hqlDirection) + public HqlSelect Select(HqlExpression expression) { - return new HqlOrderBy(_factory, expression, hqlDirection); - } - - public HqlSelect Select(HqlTreeNode expression) - { return new HqlSelect(_factory, expression); } - public HqlSelect Select(params HqlTreeNode[] expression) + public HqlSelect Select(params HqlExpression[] expression) { return new HqlSelect(_factory, expression); } - public HqlSelect Select(IEnumerable<HqlTreeNode> expressions) + public HqlSelect Select(IEnumerable<HqlExpression> expressions) { return new HqlSelect(_factory, expressions.ToArray()); } - public HqlConstructor Constructor(ConstructorInfo constructor) + public HqlCase Case(HqlWhen[] whenClauses) { - return new HqlConstructor(_factory, constructor); + return new HqlCase(_factory, whenClauses, null); } - public HqlNill Holder() + public HqlCase Case(HqlWhen[] whenClauses, HqlExpression ifFalse) { - return new HqlNill(_factory); + return new HqlCase(_factory, whenClauses, ifFalse); } - public HqlCase Case() + public HqlWhen When(HqlExpression predicate, HqlExpression ifTrue) { - return new HqlCase(_factory); + return new HqlWhen(_factory, predicate, ifTrue); } - public HqlWhen When() + public HqlElse Else(HqlExpression ifFalse) { - return new HqlWhen(_factory); + return new HqlElse(_factory, ifFalse); } - public HqlElse Else() + public HqlInequality Inequality(HqlExpression lhs, HqlExpression rhs) { - return new HqlElse(_factory); + return new HqlInequality(_factory, lhs, rhs); } - public HqlInequality Inequality() + public HqlLessThan LessThan(HqlExpression lhs, HqlExpression rhs) { - return new HqlInequality(_factory); + return new HqlLessThan(_factory, lhs, rhs); } - public HqlLessThan LessThan() + public HqlLessThanOrEqual LessThanOrEqual(HqlExpression lhs, HqlExpression rhs) { - return new HqlLessThan(_factory); + return new HqlLessThanOrEqual(_factory, lhs, rhs); } - public HqlLessThanOrEqual LessThanOrEqual() + public HqlGreaterThan GreaterThan(HqlExpression lhs, HqlExpression rhs) { - return new HqlLessThanOrEqual(_factory); + return new HqlGreaterThan(_factory, lhs, rhs); } - public HqlGreaterThan GreaterThan() + public HqlGreaterThanOrEqual GreaterThanOrEqual(HqlExpression lhs, HqlExpression rhs) { - return new HqlGreaterThan(_factory); + return new HqlGreaterThanOrEqual(_factory, lhs, rhs); } - public HqlGreaterThanOrEqual GreaterThanOrEqual() - { - return new HqlGreaterThanOrEqual(_factory); - } - public HqlCount Count() { return new HqlCount(_factory); } - public HqlCount Count(HqlTreeNode child) + public HqlCount Count(HqlExpression child) { return new HqlCount(_factory, child); } @@ -279,7 +253,7 @@ return new HqlRowStar(_factory); } - public HqlCast Cast(HqlTreeNode expression, System.Type type) + public HqlCast Cast(HqlExpression expression, System.Type type) { return new HqlCast(_factory, expression, type); } @@ -289,58 +263,33 @@ return new HqlBitwiseNot(_factory); } - public HqlNot Not() + public HqlNot Not(HqlBooleanExpression operand) { - return new HqlNot(_factory); + return new HqlNot(_factory, operand); } - public HqlAverage Average() + public HqlAverage Average(HqlExpression expression) { - return new HqlAverage(_factory); - } - - public HqlAverage Average(HqlTreeNode expression) - { return new HqlAverage(_factory, expression); } - public HqlSum Sum() + public HqlSum Sum(HqlExpression expression) { - return new HqlSum(_factory); - } - - public HqlSum Sum(HqlTreeNode expression) - { return new HqlSum(_factory, expression); } - public HqlMin Min() + public HqlMin Min(HqlExpression expression) { - return new HqlMin(_factory); - } - - public HqlMin Min(HqlTreeNode expression) - { return new HqlMin(_factory, expression); } - public HqlMax Max() + public HqlMax Max(HqlExpression expression) { - return new HqlMax(_factory); - } - - public HqlMax Max(HqlTreeNode expression) - { return new HqlMax(_factory, expression); } - public HqlAnd And(HqlTreeNode left, HqlTreeNode right) + public HqlJoin Join(HqlExpression expression, HqlAlias @alias) { - return new HqlAnd(_factory, left, right); - } - - public HqlJoin Join(HqlTreeNode expression, HqlAlias @alias) - { return new HqlJoin(_factory, expression, @alias); } @@ -349,9 +298,9 @@ return new HqlAny(_factory); } - public HqlExists Exists() + public HqlExists Exists(HqlQuery query) { - return new HqlExists(_factory); + return new HqlExists(_factory, query); } public HqlElements Elements() @@ -374,9 +323,9 @@ return new HqlDirectionDescending(_factory); } - public HqlGroupBy GroupBy() + public HqlGroupBy GroupBy(HqlExpression expression) { - return new HqlGroupBy(_factory); + return new HqlGroupBy(_factory, expression); } public HqlAll All() @@ -384,14 +333,14 @@ return new HqlAll(_factory); } - public HqlLike Like() + public HqlLike Like(HqlExpression lhs, HqlExpression rhs) { - return new HqlLike(_factory); + return new HqlLike(_factory, lhs, rhs); } - public HqlConcat Concat() + public HqlConcat Concat(params HqlExpression[] args) { - return new HqlConcat(_factory); + return new HqlConcat(_factory, args); } public HqlExpressionList ExpressionList() @@ -399,9 +348,14 @@ return new HqlExpressionList(_factory); } - public HqlMethodCall MethodCall() + public HqlMethodCall MethodCall(string methodName, HqlExpression parameter) { - return new HqlMethodCall(_factory); + return new HqlMethodCall(_factory, methodName, parameter); } + + public HqlDistinctHolder DistinctHolder(params HqlTreeNode[] children) + { + return new HqlDistinctHolder(_factory, children); + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-10 18:07:01 UTC (rev 4827) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using NHibernate.Hql.Ast.ANTLR; using NHibernate.Hql.Ast.ANTLR.Tree; @@ -8,18 +7,37 @@ { public class HqlTreeNode { - protected readonly IASTNode _node; - protected readonly List<HqlTreeNode> _children; + private readonly IASTNode _node; + private readonly List<HqlTreeNode> _children; - protected HqlTreeNode(int type, string text, IASTFactory factory, params HqlTreeNode[] children) + protected HqlTreeNode(int type, string text, IASTFactory factory, IEnumerable<HqlTreeNode> children) { _node = factory.CreateNode(type, text); _children = new List<HqlTreeNode>(); + AddChildren(children); + } + + protected HqlTreeNode(int type, string text, IASTFactory factory, params HqlTreeNode[] children) : this(type, text, factory, (IEnumerable<HqlTreeNode>) children) + { + } + + private void AddChildren(IEnumerable<HqlTreeNode> children) + { foreach (var child in children) { - _children.Add(child); - _node.AddChild(child.AstNode); + if (child != null) + { + if (child is HqlDistinctHolder) + { + AddChildren(child.Children); + } + else + { + _children.Add(child); + _node.AddChild(child.AstNode); + } + } } } @@ -57,13 +75,7 @@ public IEnumerable<HqlTreeNode> Children { - get - { - foreach (var child in _children) - { - yield return child; - } - } + get { return _children; } } public void ClearChildren() @@ -72,6 +84,11 @@ _node.ClearChildren(); } + protected void SetText(string text) + { + _node.Text = text; + } + internal IASTNode AstNode { get { return _node; } @@ -79,28 +96,74 @@ internal void AddChild(HqlTreeNode child) { - _children.Add(child); - _node.AddChild(child.AstNode); + if (child is HqlDistinctHolder) + { + AddChildren(child.Children); + } + else + { + _children.Add(child); + _node.AddChild(child.AstNode); + } } - public void AddChild(int index, HqlTreeNode node) + public HqlExpression AsExpression() { - _children.Insert(index, node); - _node.InsertChild(index, node.AstNode); + // TODO - nice error handling if cast fails + return (HqlExpression) this; } + public virtual HqlBooleanExpression AsBooleanExpression() + { + // TODO - nice error handling if cast fails + return (HqlBooleanExpression)this; + } } - public class HqlQuery : HqlTreeNode + public abstract class HqlStatement : HqlTreeNode { - internal HqlQuery(IASTFactory factory, params HqlTreeNode[] children) + protected HqlStatement(int type, string text, IASTFactory factory, params HqlTreeNode[] children) + : base(type, text, factory, children) + { + } + } + + public abstract class HqlExpression : HqlTreeNode + { + protected HqlExpression(int type, string text, IASTFactory factory, IEnumerable<HqlTreeNode> children) + : base(type, text, factory, children) + { + } + + protected HqlExpression(int type, string text, IASTFactory factory, params HqlTreeNode[] children) + : base(type, text, factory, children) + { + } + } + + public abstract class HqlBooleanExpression : HqlExpression + { + protected HqlBooleanExpression(int type, string text, IASTFactory factory, IEnumerable<HqlTreeNode> children) + : base(type, text, factory, children) + { + } + + protected HqlBooleanExpression(int type, string text, IASTFactory factory, params HqlTreeNode[] children) + : base(type, text, factory, children) + { + } + } + + public class HqlQuery : HqlExpression + { + internal HqlQuery(IASTFactory factory, params HqlStatement[] children) : base(HqlSqlWalker.QUERY, "query", factory, children) { } } - public class HqlIdent : HqlTreeNode + public class HqlIdent : HqlExpression { internal HqlIdent(IASTFactory factory, string ident) : base(HqlSqlWalker.IDENT, ident, factory) @@ -118,24 +181,24 @@ switch (System.Type.GetTypeCode(type)) { case TypeCode.Boolean: - _node.Text = "bool"; + SetText("bool"); break; case TypeCode.Int32: - _node.Text = "integer"; + SetText("integer"); break; case TypeCode.Decimal: - _node.Text = "decimal"; + SetText("decimal"); break; case TypeCode.DateTime: - _node.Text = "datetime"; + SetText("datetime"); break; case TypeCode.String: - _node.Text = "string"; + SetText("string"); break; default: if (type == typeof(Guid)) { - _node.Text = "guid"; + SetText("guid"); break; } throw new NotSupportedException(string.Format("Don't currently support idents of type {0}", type.Name)); @@ -155,7 +218,7 @@ } - public class HqlRange : HqlTreeNode + public class HqlRange : HqlStatement { internal HqlRange(IASTFactory factory, params HqlTreeNode[] children) : base(HqlSqlWalker.RANGE, "range", factory, children) @@ -163,7 +226,7 @@ } } - public class HqlFrom : HqlTreeNode + public class HqlFrom : HqlStatement { internal HqlFrom(IASTFactory factory, params HqlTreeNode[] children) : base(HqlSqlWalker.FROM, "from", factory, children) @@ -171,7 +234,7 @@ } } - public class HqlSelectFrom : HqlTreeNode + public class HqlSelectFrom : HqlStatement { internal HqlSelectFrom(IASTFactory factory, params HqlTreeNode[] children) : base(HqlSqlWalker.SELECT_FROM, "select_from", factory, children) @@ -179,7 +242,7 @@ } } - public class HqlAlias : HqlTreeNode + public class HqlAlias : HqlExpression { public HqlAlias(IASTFactory factory, string @alias) : base(HqlSqlWalker.ALIAS, alias, factory) @@ -187,68 +250,63 @@ } } - public class HqlDivide : HqlTreeNode + public class HqlDivide : HqlExpression { - public HqlDivide(IASTFactory factory) - : base(HqlSqlWalker.DIV, "/", factory) + public HqlDivide(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.DIV, "/", factory, lhs, rhs) { } } - public class HqlMultiplty : HqlTreeNode + public class HqlMultiplty : HqlExpression { - public HqlMultiplty(IASTFactory factory) - : base(HqlSqlWalker.STAR, "*", factory) + public HqlMultiplty(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.STAR, "*", factory, lhs, rhs) { } } - public class HqlSubtract : HqlTreeNode + public class HqlSubtract : HqlExpression { - public HqlSubtract(IASTFactory factory) - : base(HqlSqlWalker.MINUS, "-", factory) + public HqlSubtract(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.MINUS, "-", factory, lhs, rhs) { } } - public class HqlAdd : HqlTreeNode + public class HqlAdd : HqlExpression { - public HqlAdd(IASTFactory factory) - : base(HqlSqlWalker.PLUS, "+", factory) + public HqlAdd(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.PLUS, "+", factory, lhs, rhs) { } } - public class HqlBooleanOr : HqlTreeNode + public class HqlBooleanOr : HqlBooleanExpression { - public HqlBooleanOr(IASTFactory factory) - : base(HqlSqlWalker.OR, "or", factory) + public HqlBooleanOr(IASTFactory factory, HqlBooleanExpression lhs, HqlBooleanExpression rhs) + : base(HqlSqlWalker.OR, "or", factory, lhs, rhs) { } } - public class HqlBooleanAnd : HqlTreeNode + public class HqlBooleanAnd : HqlBooleanExpression { - public HqlBooleanAnd(IASTFactory factory) - : base(HqlSqlWalker.AND, "/", factory) + public HqlBooleanAnd(IASTFactory factory, HqlBooleanExpression lhs, HqlBooleanExpression rhs) + : base(HqlSqlWalker.AND, "/", factory, lhs, rhs) { } } - public class HqlEquality : HqlTreeNode + public class HqlEquality : HqlBooleanExpression { - public HqlEquality(IASTFactory factory) - : base(HqlSqlWalker.EQ, "==", factory) - { - } - - public HqlEquality(IASTFactory factory, HqlTreeNode lhs, HqlTreeNode rhs) + public HqlEquality(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) : base(HqlSqlWalker.EQ, "==", factory, lhs, rhs) { } } - public class HqlParameter : HqlTreeNode + public class HqlParameter : HqlExpression { public HqlParameter(IASTFactory factory, string name) : base(HqlSqlWalker.COLON, ":", factory) @@ -257,28 +315,40 @@ } } - public class HqlDot : HqlTreeNode + public class HqlDot : HqlExpression { - public HqlDot(IASTFactory factory) - : base(HqlSqlWalker.DOT, ".", factory) + private readonly IASTFactory _factory; + + public HqlDot(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.DOT, ".", factory, lhs, rhs) { + _factory = factory; } + + public override HqlBooleanExpression AsBooleanExpression() + { + // If we are of boolean type, then we can acts as boolean expression + // TODO - implement type check + return new HqlBooleanDot(_factory, this); + } } - public class HqlWhere : HqlTreeNode + public class HqlBooleanDot : HqlBooleanExpression { - public HqlWhere(IASTFactory factory) - : base(HqlSqlWalker.WHERE, "where", factory) + public HqlBooleanDot(IASTFactory factory, HqlDot dot) : base(dot.AstNode.Type, dot.AstNode.Text, factory, dot.Children) { } + } - public HqlWhere(IASTFactory factory, HqlTreeNode expression) + public class HqlWhere : HqlStatement + { + public HqlWhere(IASTFactory factory, HqlExpression expression) : base(HqlSqlWalker.WHERE, "where", factory, expression) { } } - public class HqlConstant : HqlTreeNode + public class HqlConstant : HqlExpression { public HqlConstant(IASTFactory factory, int type, string value) : base(type, value, factory) @@ -334,19 +404,12 @@ } } - public class HqlOrderBy : HqlTreeNode + public class HqlOrderBy : HqlStatement { public HqlOrderBy(IASTFactory factory) : base(HqlSqlWalker.ORDER, "", factory) { } - - public HqlOrderBy(IASTFactory factory, HqlTreeNode expression, HqlDirection hqlDirection) - : base(HqlSqlWalker.ORDER, "", factory, expression, - hqlDirection == HqlDirection.Ascending ? - (HqlTreeNode)new HqlDirectionAscending(factory) : (HqlTreeNode)new HqlDirectionDescending(factory)) - { - } } public enum HqlDirection @@ -355,7 +418,7 @@ Descending } - public class HqlDirectionAscending : HqlTreeNode + public class HqlDirectionAscending : HqlStatement { public HqlDirectionAscending(IASTFactory factory) : base(HqlSqlWalker.ASCENDING, "asc", factory) @@ -363,7 +426,7 @@ } } - public class HqlDirectionDescending : HqlTreeNode + public class HqlDirectionDescending : HqlStatement { public HqlDirectionDescending(IASTFactory factory) : base(HqlSqlWalker.DESCENDING, "desc", factory) @@ -371,120 +434,107 @@ } } - public class HqlSelect : HqlTreeNode + public class HqlSelect : HqlStatement { - public HqlSelect(IASTFactory factory, params HqlTreeNode[] expression) + public HqlSelect(IASTFactory factory, params HqlExpression[] expression) : base(HqlSqlWalker.SELECT, "select", factory, expression) { } } - public class HqlConstructor : HqlTreeNode + public class HqlElse : HqlStatement { - public HqlConstructor(IASTFactory factory, ConstructorInfo ctor) - : base(HqlSqlWalker.CONSTRUCTOR, "ctor", factory) + public HqlElse(IASTFactory factory, HqlExpression ifFalse) + : base(HqlSqlWalker.ELSE, "else", factory, ifFalse) { - ((ASTNode)_node).Hack = ctor; } } - public class HqlNill : HqlTreeNode + public class HqlWhen : HqlStatement { - public HqlNill(IASTFactory factory) - : base(0, "nill", factory) + public HqlWhen(IASTFactory factory, HqlExpression predicate, HqlExpression ifTrue) + : base(HqlSqlWalker.WHEN, "when", factory, predicate, ifTrue) { } } - public class HqlElse : HqlTreeNode + public class HqlCase : HqlExpression { - public HqlElse(IASTFactory factory) - : base(HqlSqlWalker.ELSE, "else", factory) + public HqlCase(IASTFactory factory, HqlWhen[] whenClauses, HqlExpression ifFalse) + : base(HqlSqlWalker.CASE, "case", factory, whenClauses) { + if (ifFalse != null) + { + AddChild(new HqlElse(factory, ifFalse)); + } } } - public class HqlWhen : HqlTreeNode + public class HqlGreaterThanOrEqual : HqlBooleanExpression { - public HqlWhen(IASTFactory factory) - : base(HqlSqlWalker.WHEN, "when", factory) + public HqlGreaterThanOrEqual(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.GE, "ge", factory, lhs, rhs) { } } - public class HqlCase : HqlTreeNode + public class HqlGreaterThan : HqlBooleanExpression { - public HqlCase(IASTFactory factory) - : base(HqlSqlWalker.CASE, "case", factory) + public HqlGreaterThan(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.GT, "gt", factory, lhs, rhs) { } } - public class HqlGreaterThanOrEqual : HqlTreeNode + public class HqlLessThanOrEqual : HqlBooleanExpression { - public HqlGreaterThanOrEqual(IASTFactory factory) - : base(HqlSqlWalker.GE, "ge", factory) + public HqlLessThanOrEqual(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.LE, "le", factory, lhs, rhs) { } } - public class HqlGreaterThan : HqlTreeNode + public class HqlLessThan : HqlBooleanExpression { - public HqlGreaterThan(IASTFactory factory) - : base(HqlSqlWalker.GT, "gt", factory) + public HqlLessThan(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.LT, "lt", factory, lhs, rhs) { } } - public class HqlLessThanOrEqual : HqlTreeNode + public class HqlInequality : HqlBooleanExpression { - public HqlLessThanOrEqual(IASTFactory factory) - : base(HqlSqlWalker.LE, "le", factory) + public HqlInequality(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.NE, "ne", factory, lhs, rhs) { } } - public class HqlLessThan : HqlTreeNode + public class HqlRowStar : HqlStatement { - public HqlLessThan(IASTFactory factory) - : base(HqlSqlWalker.LT, "lt", factory) - { - } - } - - public class HqlInequality : HqlTreeNode - { - public HqlInequality(IASTFactory factory) - : base(HqlSqlWalker.NE, "ne", factory) - { - } - } - - public class HqlRowStar : HqlTreeNode - { public HqlRowStar(IASTFactory factory) : base(HqlSqlWalker.ROW_STAR, "*", factory) { } } - public class HqlCount : HqlTreeNode + public class HqlCount : HqlExpression { - public HqlCount(IASTFactory factory) : base(HqlSqlWalker.COUNT, "count", factory) { } - - public HqlCount(IASTFactory factory, HqlTreeNode child) + + public HqlCount(IASTFactory factory, HqlExpression child) : base(HqlSqlWalker.COUNT, "count", factory, child) { } } - public class HqlAs : HqlTreeNode + public class HqlAs : HqlExpression { - public HqlAs(IASTFactory factory, HqlTreeNode expression, System.Type type) : base(HqlSqlWalker.AS, "as", factory, expression) + public HqlAs(IASTFactory factory, HqlExpression expression, System.Type type) + : base(HqlSqlWalker.AS, "as", factory, expression) { switch (System.Type.GetTypeCode(type)) { @@ -497,136 +547,118 @@ } } - public class HqlCast : HqlTreeNode + public class HqlCast : HqlExpression { - public HqlCast(IASTFactory factory, HqlTreeNode expression, System.Type type) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + public HqlCast(IASTFactory factory, HqlExpression expression, System.Type type) + : base(HqlSqlWalker.METHOD_CALL, "method", factory) { AddChild(new HqlIdent(factory, "cast")); AddChild(new HqlExpressionList(factory, expression, new HqlIdent(factory, type))); } } - public class HqlExpressionList : HqlTreeNode + public class HqlExpressionList : HqlStatement { public HqlExpressionList(IASTFactory factory, params HqlTreeNode[] expression) : base(HqlSqlWalker.EXPR_LIST, "expr_list", factory, expression) { } } - public class HqlNot : HqlTreeNode + public class HqlNot : HqlBooleanExpression { - public HqlNot(IASTFactory factory) : base(HqlSqlWalker.NOT, "not", factory) + public HqlNot(IASTFactory factory, HqlBooleanExpression operand) + : base(HqlSqlWalker.NOT, "not", factory, operand) { } } - public class HqlAverage : HqlTreeNode + public class HqlAverage : HqlExpression { - public HqlAverage(IASTFactory factory) - : base(HqlSqlWalker.AGGREGATE, "avg", factory) + public HqlAverage(IASTFactory factory, HqlExpression expression) + : base(HqlSqlWalker.AGGREGATE, "avg", factory, expression) { } - - public HqlAverage(IASTFactory factory, HqlTreeNode expression) : base(HqlSqlWalker.AGGREGATE, "avg", factory, expression) - { - } } - public class HqlBitwiseNot : HqlTreeNode + public class HqlBitwiseNot : HqlExpression { public HqlBitwiseNot(IASTFactory factory) : base(HqlSqlWalker.BNOT, "not", factory) { } } - public class HqlSum : HqlTreeNode + public class HqlSum : HqlExpression { public HqlSum(IASTFactory factory) : base(HqlSqlWalker.AGGREGATE, "sum", factory) { } - public HqlSum(IASTFactory factory, HqlTreeNode expression) + public HqlSum(IASTFactory factory, HqlExpression expression) : base(HqlSqlWalker.AGGREGATE, "sum", factory, expression) { } } - public class HqlMax : HqlTreeNode + public class HqlMax : HqlExpression { - public HqlMax(IASTFactory factory) : base(HqlSqlWalker.AGGREGATE, "max", factory) - { - } - - public HqlMax(IASTFactory factory, HqlTreeNode expression) + public HqlMax(IASTFactory factory, HqlExpression expression) : base(HqlSqlWalker.AGGREGATE, "max", factory, expression) { } } - public class HqlMin : HqlTreeNode + public class HqlMin : HqlExpression { - public HqlMin(IASTFactory factory) - : base(HqlSqlWalker.AGGREGATE, "min", factory) - { - } - - public HqlMin(IASTFactory factory, HqlTreeNode expression) + public HqlMin(IASTFactory factory, HqlExpression expression) : base(HqlSqlWalker.AGGREGATE, "min", factory, expression) { } } - public class HqlAnd : HqlTreeNode + public class HqlJoin : HqlStatement { - public HqlAnd(IASTFactory factory, HqlTreeNode left, HqlTreeNode right) : base(HqlSqlWalker.AND, "and", factory, left, right) + public HqlJoin(IASTFactory factory, HqlExpression expression, HqlAlias @alias) : base(HqlSqlWalker.JOIN, "join", factory, expression, @alias) { } } - public class HqlJoin : HqlTreeNode + public class HqlAny : HqlBooleanExpression { - public HqlJoin(IASTFactory factory, HqlTreeNode expression, HqlAlias @alias) : base(HqlSqlWalker.JOIN, "join", factory, expression, @alias) - { - } - } - - public class HqlAny : HqlTreeNode - { public HqlAny(IASTFactory factory) : base(HqlSqlWalker.ANY, "any", factory) { } } - public class HqlExists : HqlTreeNode + public class HqlExists : HqlBooleanExpression { - public HqlExists(IASTFactory factory) : base(HqlSqlWalker.EXISTS, "exists", factory) + public HqlExists(IASTFactory factory, HqlQuery query) : base(HqlSqlWalker.EXISTS, "exists", factory, query) { } } - public class HqlElements : HqlTreeNode + public class HqlElements : HqlBooleanExpression { public HqlElements(IASTFactory factory) : base(HqlSqlWalker.ELEMENTS, "elements", factory) { } } - public class HqlDistinct : HqlTreeNode + public class HqlDistinct : HqlStatement { public HqlDistinct(IASTFactory factory) : base(HqlSqlWalker.DISTINCT, "distinct", factory) { } } - public class HqlGroupBy : HqlTreeNode + public class HqlGroupBy : HqlStatement { - public HqlGroupBy(IASTFactory factory) : base(HqlSqlWalker.GROUP, "group by", factory) + public HqlGroupBy(IASTFactory factory, HqlExpression expression) : base(HqlSqlWalker.GROUP, "group by", factory, expression) { } } - public class HqlAll : HqlTreeNode + public class HqlAll : HqlBooleanExpression { public HqlAll(IASTFactory factory) : base(HqlSqlWalker.ALL, "all", factory) @@ -634,24 +666,38 @@ } } - public class HqlLike : HqlTreeNode + public class HqlLike : HqlBooleanExpression { - public HqlLike(IASTFactory factory) : base(HqlSqlWalker.LIKE, "like", factory) + public HqlLike(IASTFactory factory, HqlExpression lhs, HqlExpression rhs) + : base(HqlSqlWalker.LIKE, "like", factory, lhs, rhs) { } } - public class HqlConcat : HqlTreeNode + public class HqlConcat : HqlExpression { - public HqlConcat(IASTFactory factory) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + public HqlConcat(IASTFactory factory, params HqlExpression[] args) + : base(HqlSqlWalker.METHOD_CALL, "method", factory) { + AddChild(new HqlIdent(factory, "concat")); + AddChild(new HqlExpressionList(factory, args)); } } - public class HqlMethodCall : HqlTreeNode + public class HqlMethodCall : HqlExpression { - public HqlMethodCall(IASTFactory factory) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + public HqlMethodCall(IASTFactory factory, string methodName, HqlExpression parameter) + : base(HqlSqlWalker.METHOD_CALL, "method", factory) { + AddChild(new HqlIdent(factory, methodName)); + AddChild(new HqlExpressionList(factory, parameter)); } } + + public class HqlDistinctHolder : HqlExpression + { + public HqlDistinctHolder(IASTFactory factory, HqlTreeNode[] children) : base(int.MinValue, "distinct holder", factory, children) + { + } + } } \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/Functions ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Added: trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForMethod.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForMethod.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForMethod.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public abstract class BaseHqlGeneratorForMethod : IHqlGeneratorForMethod + { + public IEnumerable<MethodInfo> SupportedMethods { get; protected set; } + + public abstract HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForProperty.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForProperty.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForProperty.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public abstract class BaseHqlGeneratorForProperty : IHqlGeneratorForProperty + { + public IEnumerable<MemberInfo> SupportedProperties { get; protected set; } + public abstract HqlTreeNode BuildHql(MemberInfo member, Expression expression, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/BaseHqlGeneratorForType.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + abstract public class BaseHqlGeneratorForType : IHqlGeneratorForType + { + protected readonly List<IHqlGeneratorForMethod> MethodRegistry = new List<IHqlGeneratorForMethod>(); + protected readonly List<IHqlGeneratorForProperty> PropertyRegistry = new List<IHqlGeneratorForProperty>(); + + public void Register(FunctionRegistry functionRegistry) + { + foreach (var generator in MethodRegistry) + { + foreach (var method in generator.SupportedMethods) + { + functionRegistry.RegisterMethodGenerator(method, generator); + } + } + + foreach (var generator in PropertyRegistry) + { + foreach (var property in generator.SupportedProperties) + { + functionRegistry.RegisterPropertyGenerator(property, generator); + } + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/DateTimeGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/DateTimeGenerator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/DateTimeGenerator.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,38 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public class DateTimeGenerator : BaseHqlGeneratorForType + { + public DateTimeGenerator() + { + PropertyRegistry.Add(new DatePartGenerator()); + } + + public class DatePartGenerator : BaseHqlGeneratorForProperty + { + public DatePartGenerator() + { + SupportedProperties = new[] + { + ReflectionHelper.GetProperty((DateTime x) => x.Year), + ReflectionHelper.GetProperty((DateTime x) => x.Month), + ReflectionHelper.GetProperty((DateTime x) => x.Day), + ReflectionHelper.GetProperty((DateTime x) => x.Hour), + ReflectionHelper.GetProperty((DateTime x) => x.Minute), + ReflectionHelper.GetProperty((DateTime x) => x.Second), + }; + } + + public override HqlTreeNode BuildHql(MemberInfo member, Expression expression, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + return treeBuilder.MethodCall(member.Name.ToLowerInvariant(), + visitor.Visit(expression).AsExpression()); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/FunctionRegistry.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace NHibernate.Linq.Functions +{ + public class FunctionRegistry + { + public static FunctionRegistry Initialise() + { + var registry = new FunctionRegistry(); + + // TODO - could use reflection here + registry.Register(new QueryableGenerator()); + registry.Register(new StringGenerator()); + registry.Register(new DateTimeGenerator()); + + return registry; + } + + private readonly Dictionary<MethodInfo, IHqlGeneratorForMethod> _registeredMethods = new Dictionary<MethodInfo, IHqlGeneratorForMethod>(); + private readonly Dictionary<MemberInfo, IHqlGeneratorForProperty> _registeredProperties = new Dictionary<MemberInfo, IHqlGeneratorForProperty>(); + + public IHqlGeneratorForMethod GetMethodGenerator(MethodInfo method) + { + IHqlGeneratorForMethod methodGenerator; + + if (method.IsGenericMethod) + { + method = method.GetGenericMethodDefinition(); + } + + if (_registeredMethods.TryGetValue(method, out methodGenerator)) + { + return methodGenerator; + } + + throw new NotSupportedException(method.ToString()); + } + + public IHqlGeneratorForProperty GetPropertyGenerator(MemberInfo member) + { + IHqlGeneratorForProperty propertyGenerator; + + if (_registeredProperties.TryGetValue(member, out propertyGenerator)) + { + return propertyGenerator; + } + + // TODO - different usage pattern to method generator + return null; + } + + public void RegisterMethodGenerator(MethodInfo method, IHqlGeneratorForMethod generator) + { + _registeredMethods.Add(method, generator); + } + + public void RegisterPropertyGenerator(MemberInfo property, IHqlGeneratorForProperty generator) + { + _registeredProperties.Add(property, generator); + } + + private void Register(IHqlGeneratorForType typeMethodGenerator) + { + typeMethodGenerator.Register(this); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForMethod.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForMethod.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForMethod.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public interface IHqlGeneratorForMethod + { + IEnumerable<MethodInfo> SupportedMethods { get; } + HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForProperty.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForProperty.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForProperty.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public interface IHqlGeneratorForProperty + { + IEnumerable<MemberInfo> SupportedProperties { get; } + HqlTreeNode BuildHql(MemberInfo member, Expression expression, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/IHqlGeneratorForType.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,7 @@ +namespace NHibernate.Linq.Functions +{ + public interface IHqlGeneratorForType + { + void Register(FunctionRegistry functionRegistry); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,129 @@ +using System.Collections.ObjectModel; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public class QueryableGenerator : BaseHqlGeneratorForType + { + public QueryableGenerator() + { + // TODO - could use reflection + MethodRegistry.Add(new AnyGenerator()); + MethodRegistry.Add(new AllGenerator()); + MethodRegistry.Add(new MinGenerator()); + MethodRegistry.Add(new MaxGenerator()); + } + + class AnyGenerator : BaseHqlGeneratorForMethod + { + public AnyGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Any<object>(null)), + ReflectionHelper.GetMethod(() => Queryable.Any<object>(null, null)), + ReflectionHelper.GetMethod(() => Enumerable.Any<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Any<object>(null, null)) + }; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + HqlAlias alias = null; + HqlWhere where = null; + + if (arguments.Count > 1) + { + var expr = (LambdaExpression)arguments[1]; + + alias = treeBuilder.Alias(expr.Parameters[0].Name); + where = treeBuilder.Where(visitor.Visit(arguments[1]).AsExpression()); + } + + return treeBuilder.Exists( + treeBuilder.Query( + treeBuilder.SelectFrom( + treeBuilder.From( + treeBuilder.Range( + visitor.Visit(arguments[0]), + alias) + ) + ), + where)); + } + } + + class AllGenerator : BaseHqlGeneratorForMethod + { + public AllGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.All<object>(null, null)), + ReflectionHelper.GetMethod(() => Enumerable.All<object>(null, null)) + }; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + // All has two arguments. Arg 1 is the source and arg 2 is the predicate + var predicate = (LambdaExpression)arguments[1]; + + return treeBuilder.Not( + treeBuilder.Exists( + treeBuilder.Query( + treeBuilder.SelectFrom( + treeBuilder.From( + treeBuilder.Range( + visitor.Visit(arguments[0]), + treeBuilder.Alias(predicate.Parameters[0].Name)) + ) + ), + treeBuilder.Where( + treeBuilder.Not(visitor.Visit(arguments[1]).AsBooleanExpression()) + ) + ) + ) + ); + } + } + + class MinGenerator : BaseHqlGeneratorForMethod + { + public MinGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Min<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Min<object>(null)) + }; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + return treeBuilder.Min(visitor.Visit(arguments[1]).AsExpression()); + } + } + + class MaxGenerator : BaseHqlGeneratorForMethod + { + public MaxGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Max<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Max<object>(null)) + }; + } + + public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) + { + return treeBuilder.Max(visitor.Visit(arguments[1]).AsExpression()); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/StringGenerator.cs 2009-11-11 13:37:38 UTC (rev 4828) @@ -0,0 +1,133 @@ +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Hql.Ast; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq.Functions +{ + public class StringGenerator : BaseHqlGeneratorForType + { + public StringGenerator() + { + // TODO - could use reflection + MethodRegistry.Add(new StartsWithGenerator()); + MethodRegistry.Add(new EndsWithGenerator()); + MethodRegistry.Add(new ContainsGenerator()); + MethodRegistry.Add(new EqualsGenerator()); + MethodRegistry.Add(new ToUpperLowerGenerator()); + + PropertyRegistry.Add(new LengthGenerator()); + } + + public class LengthGenerator : BaseHqlGeneratorForProperty + { + public LengthGenerator() + {... [truncated message content] |
From: <ric...@us...> - 2009-11-10 18:07:33
|
Revision: 4827 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4827&view=rev Author: ricbrown Date: 2009-11-10 18:07:01 +0000 (Tue, 10 Nov 2009) Log Message: ----------- Added remaining (inline) QueryOver subquery overloads. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs 2009-11-10 14:19:09 UTC (rev 4826) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs 2009-11-10 18:07:01 UTC (rev 4827) @@ -38,6 +38,24 @@ } /// <summary> + /// Add an Exists subquery criterion + /// </summary> + public R WhereExists<U>(QueryOver<U> detachedQuery) + { + root.And(Subqueries.Exists(detachedQuery.DetachedCriteria)); + return root; + } + + /// <summary> + /// Add a NotExists subquery criterion + /// </summary> + public R WhereNotExists<U>(QueryOver<U> detachedQuery) + { + root.And(Subqueries.NotExists(detachedQuery.DetachedCriteria)); + return root; + } + + /// <summary> /// Subquery expression in the format /// .Where(t => t.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) /// </summary> @@ -48,12 +66,73 @@ return root; } + /// <summary> + /// Subquery expression in the format + /// .Where(() => alias.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R Where(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.Exact, expression); + root.And(criterion); + return root; + } + + /// <summary> + /// Subquery expression in the format + /// .WhereAll(t => t.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R WhereAll(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.All, expression); + root.And(criterion); + return root; + } + + /// <summary> + /// Subquery expression in the format + /// .WhereAll(() => alias.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R WhereAll(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.All, expression); + root.And(criterion); + return root; + } + + /// <summary> + /// Subquery expression in the format + /// .WhereSome(t => t.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R WhereSome(Expression<Func<T, bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery<T>(LambdaSubqueryType.Some, expression); + root.And(criterion); + return root; + } + + /// <summary> + /// Subquery expression in the format + /// .WhereSome(() => alias.Property [==, !=, >, etc.] detachedQueryOver.As<propertyType>()) + /// </summary> + public R WhereSome(Expression<Func<bool>> expression) + { + AbstractCriterion criterion = ExpressionProcessor.ProcessSubquery(LambdaSubqueryType.Some, 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, null); } + public S WhereProperty(Expression<Func<object>> expression) + { + string property = ExpressionProcessor.FindMemberExpression(expression.Body); + return (S)new S().Set(root, property, null); + } + public S WhereValue(object value) { return (S)new S().Set(root, null, value); Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs 2009-11-10 14:19:09 UTC (rev 4826) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs 2009-11-10 18:07:01 UTC (rev 4827) @@ -78,6 +78,16 @@ } /// <summary> + /// Add a property equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R EqAll<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyEqAll, Subqueries.EqAll, detachedCriteria); + return root; + } + + /// <summary> /// Create a property greater than or equal subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> @@ -88,6 +98,26 @@ } /// <summary> + /// Create a property greater than or equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R GeAll<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGeAll, Subqueries.GeAll, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property greater than or equal some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R GeSome<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGeSome, Subqueries.GeSome, detachedCriteria); + return root; + } + + /// <summary> /// Create a property greater than subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> @@ -98,6 +128,26 @@ } /// <summary> + /// Create a property greater than all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R GtAll<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGtAll, Subqueries.GtAll, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property greater than some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R GtSome<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGtSome, Subqueries.GtSome, detachedCriteria); + return root; + } + + /// <summary> /// Create a property in subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> @@ -118,6 +168,26 @@ } /// <summary> + /// Create a property less than or equal all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R LeAll<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLeAll, Subqueries.LeAll, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than or equal some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R LeSome<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLeSome, Subqueries.LeSome, detachedCriteria); + return root; + } + + /// <summary> /// Create a property less than subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> @@ -128,6 +198,26 @@ } /// <summary> + /// Create a property less than all subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R LtAll<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLtAll, Subqueries.LtAll, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than some subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R LtSome<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLtSome, Subqueries.LtSome, detachedCriteria); + return root; + } + + /// <summary> /// Create a property not equal subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-10 14:19:09 UTC (rev 4826) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-10 18:07:01 UTC (rev 4827) @@ -103,6 +103,63 @@ } [Test] + public void PropertyAlias() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Subqueries.PropertyEq("personAlias.Name", DetachedCriteriaName)); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .WithSubquery.WhereProperty(() => personAlias.Name).Eq(DetachedQueryOverName); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void PropertyAll() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereProperty(p => p.Name).EqAll(DetachedQueryOverName) + .WithSubquery.WhereProperty(p => p.Age).GeAll(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).GtAll(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).LeAll(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).LtAll(DetachedQueryOverAge); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void PropertySome() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyGeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereProperty(p => p.Age).GeSome(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).GtSome(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).LeSome(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).LtSome(DetachedQueryOverAge); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void PropertyAsSyntax() { ICriteria expected = @@ -127,6 +184,67 @@ } [Test] + public void PropertyAsSyntaxAlias() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Subqueries.PropertyEq("personAlias.Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGtSome("personAlias.Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("personAlias.Age", DetachedCriteriaAge)); + + Person personAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .WithSubquery.Where(() => personAlias.Name == DetachedQueryOverName.As<string>()) + .WithSubquery.WhereSome(() => personAlias.Age > DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereAll(() => personAlias.Age < DetachedQueryOverAge.As<int>()); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void PropertyAsAllSyntax() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyEqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereAll(p => p.Name == DetachedQueryOverName.As<string>()) + .WithSubquery.WhereAll(p => p.Age >= DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereAll(p => p.Age > DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereAll(p => p.Age <= DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereAll(p => p.Age < DetachedQueryOverAge.As<int>()); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void PropertyAsSomeSyntax() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.PropertyGeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereSome(p => p.Age >= DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereSome(p => p.Age > DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereSome(p => p.Age <= DetachedQueryOverAge.As<int>()) + .WithSubquery.WhereSome(p => p.Age < DetachedQueryOverAge.As<int>()); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void Value() { ICriteria expected = @@ -154,6 +272,64 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void ValueAll() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.EqAll("Name", DetachedCriteriaName)) + .Add(Subqueries.GeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.GtAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.LeAll("Age", DetachedCriteriaAge)) + .Add(Subqueries.LtAll("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereValue("Name").EqAll(DetachedQueryOverName) + .WithSubquery.WhereValue("Age").GeAll(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").GtAll(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").LeAll(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").LtAll(DetachedQueryOverAge); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void ValueSome() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.GeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.GtSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.LeSome("Age", DetachedCriteriaAge)) + .Add(Subqueries.LtSome("Age", DetachedCriteriaAge)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereValue("Age").GeSome(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").GtSome(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").LeSome(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").LtSome(DetachedQueryOverAge); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] + public void UntypedSubqueries() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.Exists(DetachedCriteriaChild)) + .Add(Subqueries.NotExists(DetachedCriteriaChild)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereExists(DetachedQueryOverChild) + .WithSubquery.WhereNotExists(DetachedQueryOverChild); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-10 14:19:22
|
Revision: 4826 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4826&view=rev Author: steverstrong Date: 2009-11-10 14:19:09 +0000 (Tue, 10 Nov 2009) Log Message: ----------- Added more tests and support (in a semi-extensible way) for constructs such as string.ToUpper and datetime.Year Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Linq/Visitors/BaseHqlGeneratorForProperty.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -398,5 +398,10 @@ { return new HqlExpressionList(_factory); } + + public HqlMethodCall MethodCall() + { + return new HqlMethodCall(_factory); + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -147,6 +147,7 @@ return type.GetGenericArguments()[0]; } + // TODO - code duplicated in LinqExtensionMethods private static bool IsNullableType(System.Type type) { return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); @@ -646,4 +647,11 @@ { } } + + public class HqlMethodCall : HqlTreeNode + { + public HqlMethodCall(IASTFactory factory) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + { + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -20,6 +20,11 @@ var methodInfo = ((MethodCallExpression)method.Body).Method; return methodInfo.IsGenericMethod ? methodInfo.GetGenericMethodDefinition() : methodInfo; } + + public static MemberInfo GetProperty<TSource, TResult>(Expression<Func<TSource, TResult>> property) + { + return ((MemberExpression) property.Body).Member; + } } // TODO rename / remove - reflection helper above is better Modified: trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace NHibernate.Linq @@ -17,5 +18,11 @@ method(item); } } + + public static bool IsNullable(this System.Type type) + { + return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Visitors/BaseHqlGeneratorForProperty.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/BaseHqlGeneratorForProperty.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/BaseHqlGeneratorForProperty.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace NHibernate.Linq.Visitors +{ + public abstract class BaseHqlGeneratorForProperty : IHqlGeneratorForProperty + { + public IEnumerable<MemberInfo> SupportedProperties { get; protected set; } + public abstract void BuildHql(MemberInfo member, Expression expression, HqlGeneratorExpressionTreeVisitor hqlGeneratorExpressionTreeVisitor); + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -7,7 +7,6 @@ using NHibernate.Engine.Query; using NHibernate.Hql.Ast; using NHibernate.Linq.Expressions; -using Remotion.Data.Linq; using Remotion.Data.Linq.Clauses.Expressions; using Remotion.Data.Linq.Clauses.ExpressionTreeVisitors; @@ -206,16 +205,28 @@ protected override Expression VisitMemberExpression(MemberExpression expression) { + // Strip out the .Value property of a nullable type, HQL doesn't need that + if (expression.Member.Name == "Value" && expression.Expression.Type.IsNullable()) + { + VisitExpression(expression.Expression); + return expression; + } + + // Look for "special" properties (DateTime.Month etc) + var generator = _methodGeneratorRegistry.GetPropertyGenerator(expression.Expression.Type, expression.Member); + + if (generator != null) + { + generator.BuildHql(expression.Member, expression.Expression, this); + return expression; + } + + // Else just emit standard HQL for a property reference using (_stack.PushNode(_hqlTreeBuilder.Dot())) { - Expression newExpression = VisitExpression(expression.Expression); + VisitExpression(expression.Expression); _stack.PushLeaf(_hqlTreeBuilder.Ident(expression.Member.Name)); - - if (newExpression != expression.Expression) - { - return Expression.MakeMemberAccess(newExpression, expression.Member); - } } return expression; @@ -253,7 +264,7 @@ { var generator = _methodGeneratorRegistry.GetMethodGenerator(expression.Method); - generator.BuildHql(expression.Object, expression.Arguments, this); + generator.BuildHql(expression.Method, expression.Object, expression.Arguments, this); return expression; } @@ -320,6 +331,12 @@ } } + public interface IHqlGeneratorForProperty + { + IEnumerable<MemberInfo> SupportedProperties { get; } + void BuildHql(MemberInfo member, Expression expression, HqlGeneratorExpressionTreeVisitor hqlGeneratorExpressionTreeVisitor); + } + public class MethodGeneratorRegistry { public static MethodGeneratorRegistry Initialise() @@ -329,11 +346,13 @@ // TODO - could use reflection here registry.Register(new QueryableMethodsGenerator()); registry.Register(new StringMethodsGenerator()); + registry.Register(new DateTimePropertyGenerator()); return registry; } private readonly Dictionary<MethodInfo, IHqlGeneratorForMethod> _registeredMethods = new Dictionary<MethodInfo, IHqlGeneratorForMethod>(); + private readonly Dictionary<MemberInfo, IHqlGeneratorForProperty> _registeredProperties = new Dictionary<MemberInfo, IHqlGeneratorForProperty>(); public IHqlGeneratorForMethod GetMethodGenerator(MethodInfo method) { @@ -349,37 +368,55 @@ return methodGenerator; } - throw new NotSupportedException(); + throw new NotSupportedException(method.ToString()); } + public IHqlGeneratorForProperty GetPropertyGenerator(System.Type type, MemberInfo member) + { + IHqlGeneratorForProperty propertyGenerator; + + if (_registeredProperties.TryGetValue(member, out propertyGenerator)) + { + return propertyGenerator; + } + + // TODO - different usage pattern to method generator + return null; + } + public void RegisterMethodGenerator(MethodInfo method, IHqlGeneratorForMethod generator) { _registeredMethods.Add(method, generator); } + public void RegisterPropertyGenerator(MemberInfo property, IHqlGeneratorForProperty generator) + { + _registeredProperties.Add(property, generator); + } + private void Register(IHqlGeneratorForType typeMethodGenerator) { - typeMethodGenerator.RegisterMethods(this); + typeMethodGenerator.Register(this); } - } public interface IHqlGeneratorForMethod { IEnumerable<MethodInfo> SupportedMethods { get; } - void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); + void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); } public interface IHqlGeneratorForType { - void RegisterMethods(MethodGeneratorRegistry methodGeneratorRegistry); + void Register(MethodGeneratorRegistry methodGeneratorRegistry); } abstract public class BaseHqlGeneratorForType : IHqlGeneratorForType { protected readonly List<IHqlGeneratorForMethod> MethodRegistry = new List<IHqlGeneratorForMethod>(); + protected readonly List<IHqlGeneratorForProperty> PropertyRegistry = new List<IHqlGeneratorForProperty>(); - public void RegisterMethods(MethodGeneratorRegistry methodGeneratorRegistry) + public void Register(MethodGeneratorRegistry methodGeneratorRegistry) { foreach (var generator in MethodRegistry) { @@ -388,6 +425,14 @@ methodGeneratorRegistry.RegisterMethodGenerator(method, generator); } } + + foreach (var generator in PropertyRegistry) + { + foreach (var property in generator.SupportedProperties) + { + methodGeneratorRegistry.RegisterPropertyGenerator(property, generator); + } + } } } @@ -395,9 +440,46 @@ { public IEnumerable<MethodInfo> SupportedMethods { get; protected set; } - public abstract void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); + public abstract void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); } + public class DateTimePropertyGenerator : BaseHqlGeneratorForType + { + public DateTimePropertyGenerator() + { + PropertyRegistry.Add(new DatePartGenerator()); + } + + public class DatePartGenerator : BaseHqlGeneratorForProperty + { + public DatePartGenerator() + { + SupportedProperties = new[] + { + ReflectionHelper.GetProperty((DateTime x) => x.Year), + ReflectionHelper.GetProperty((DateTime x) => x.Month), + ReflectionHelper.GetProperty((DateTime x) => x.Day), + ReflectionHelper.GetProperty((DateTime x) => x.Hour), + ReflectionHelper.GetProperty((DateTime x) => x.Minute), + ReflectionHelper.GetProperty((DateTime x) => x.Second), + }; + } + + public override void BuildHql(MemberInfo member, Expression expression, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.MethodCall())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident(member.Name.ToLowerInvariant())); + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Visit(expression); + } + } + } + } + } + public class StringMethodsGenerator : BaseHqlGeneratorForType { public StringMethodsGenerator() @@ -407,8 +489,32 @@ MethodRegistry.Add(new EndsWithGenerator()); MethodRegistry.Add(new ContainsGenerator()); MethodRegistry.Add(new EqualsGenerator()); + MethodRegistry.Add(new ToUpperLowerGenerator()); + + PropertyRegistry.Add(new LengthGenerator()); } + public class LengthGenerator : BaseHqlGeneratorForProperty + { + public LengthGenerator() + { + SupportedProperties = new[] {ReflectionHelper.GetProperty((string x) => x.Length)}; + } + + public override void BuildHql(MemberInfo member, Expression expression, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.MethodCall())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("length")); + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Visit(expression); + } + } + } + } + class StartsWithGenerator : BaseHqlGeneratorForMethod { public StartsWithGenerator() @@ -416,7 +522,7 @@ SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.StartsWith(null)) }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) { @@ -446,7 +552,7 @@ SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.EndsWith(null)) }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) { @@ -476,7 +582,7 @@ SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.Contains(null)) }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) { @@ -508,7 +614,7 @@ SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.Equals((string)null)) }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Equality())) { @@ -518,6 +624,40 @@ } } } + + class ToUpperLowerGenerator : BaseHqlGeneratorForMethod + { + public ToUpperLowerGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod<string>(x => x.ToUpper()), + ReflectionHelper.GetMethod<string>(x => x.ToUpperInvariant()), + ReflectionHelper.GetMethod<string>(x => x.ToLower()), + ReflectionHelper.GetMethod<string>(x => x.ToLowerInvariant()) + }; + } + + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.MethodCall())) + { + if (((method.Name == "ToUpper") || (method.Name == "ToUpperInvariant"))) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("lower")); + } + else + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("upper")); + } + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Visit(targetObject); + } + } + } + } } public class QueryableMethodsGenerator : BaseHqlGeneratorForType @@ -544,7 +684,7 @@ }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { // Any has one or two arguments. Arg 1 is the source and arg 2 is the optional predicate using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Exists())) @@ -590,7 +730,7 @@ }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { // All has two arguments. Arg 1 is the source and arg 2 is the predicate using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Not())) @@ -638,7 +778,7 @@ }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Min())) { @@ -658,7 +798,7 @@ }; } - public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + public override void BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) { using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Max())) { Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-10 14:19:09 UTC (rev 4826) @@ -585,6 +585,7 @@ <Compile Include="Linq\GroupJoin\GroupJoinSelectClauseRewriter.cs" /> <Compile Include="Linq\GroupJoin\LocateGroupJoinQuerySource.cs" /> <Compile Include="Linq\GroupJoin\NonAggregatingGroupJoinRewriter.cs" /> + <Compile Include="Linq\Visitors\BaseHqlGeneratorForProperty.cs" /> <Compile Include="Linq\Visitors\SwapQuerySourceVisitor.cs" /> <Compile Include="Linq\Visitors\EqualityHqlGenerator.cs" /> <Compile Include="Linq\Visitors\ExpressionParameterVisitor.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs 2009-11-10 13:32:28 UTC (rev 4825) +++ trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs 2009-11-10 14:19:09 UTC (rev 4826) @@ -61,15 +61,14 @@ Console.WriteLine(query); Assert.AreEqual("ALFKI,AROUT,", query.ToString()); } - /* - [Test] - [Ignore("TODO")] + + [Test] public void AggregateWithMonthFunction() { var date = new DateTime(2007, 1, 1); var query = (from e in db.Employees - where db.Methods.Month(e.BirthDate) == date.Month + where e.BirthDate.Value.Month == date.Month select e.FirstName) .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); @@ -77,15 +76,14 @@ Console.WriteLine(query); } - [Test] - [Ignore("TODO")] + [Test] public void AggregateWithBeforeYearFunction() { var date = new DateTime(1960, 1, 1); var query = (from e in db.Employees - where db.Methods.Year(e.BirthDate) < date.Year - select db.Methods.Upper(e.FirstName)) + where e.BirthDate.Value.Year < date.Year + select e.FirstName.ToUpper()) .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); Console.WriteLine("Birthdays before {0}:", date.ToString("yyyy")); @@ -93,13 +91,12 @@ } [Test] - [Ignore("TODO")] public void AggregateWithOnOrAfterYearFunction() { var date = new DateTime(1960, 1, 1); var query = (from e in db.Employees - where db.Methods.Year(e.BirthDate) >= date.Year && db.Methods.Len(e.FirstName) > 4 + where e.BirthDate.Value.Year >= date.Year && e.FirstName.Length > 4 select e.FirstName) .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); @@ -108,14 +105,13 @@ } [Test] - [Ignore("TODO")] public void AggregateWithUpperAndLowerFunctions() { var date = new DateTime(2007, 1, 1); var query = (from e in db.Employees - where db.Methods.Month(e.BirthDate) == date.Month - select new { First = e.FirstName.ToUpper(), Last = db.Methods.Lower(e.LastName) }) + where e.BirthDate.Value.Month == date.Month + select new { First = e.FirstName.ToUpper(), Last = e.LastName.ToLower() }) .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); Console.WriteLine("{0} Birthdays:", date.ToString("MMMM")); @@ -123,17 +119,19 @@ } [Test] - [Ignore("TODO")] + [Ignore("TODO: Custom functions")] public void AggregateWithCustomFunction() { + /* var date = new DateTime(1960, 1, 1); var query = (from e in db.Employees - where db.Methods.Year(e.BirthDate) < date.Year + where e.BirthDate.Value.Year < date.Year select db.Methods.fnEncrypt(e.FirstName)) .Aggregate(new StringBuilder(), (sb, name) => sb.AppendLine(BitConverter.ToString(name))); Console.WriteLine(query); - }*/ + */ + } } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-10 13:32:39
|
Revision: 4825 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4825&view=rev Author: ricbrown Date: 2009-11-10 13:32:28 +0000 (Tue, 10 Nov 2009) Log Message: ----------- Tidied QueryOver builder classes inside separate folder/namespace. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOverFetchBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverLockBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverOrderBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs (from rev 4822, trunk/nhibernate/src/NHibernate/Criterion/QueryOverFetchBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,69 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion +{ + + public class QueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<QueryOver<T>, T> + { + + public QueryOverFetchBuilder(QueryOver<T> root, Expression<Func<T, object>> path) + : base(root, path) { } + + } + + public class IQueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<IQueryOver<T>, T> + { + + public IQueryOverFetchBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) + : base(root, path) { } + + } + + public class QueryOverFetchBuilderBase<R, T> where R : IQueryOver<T> + { + + protected R root; + protected string path; + + protected QueryOverFetchBuilderBase(R root, Expression<Func<T, object>> path) + { + this.root = root; + this.path = ExpressionProcessor.FindMemberExpression(path.Body); + } + + public R Eager + { + get + { + this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Eager); + return this.root; + } + } + + public R Lazy + { + get + { + this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Lazy); + return this.root; + } + } + + public R Default + { + get + { + this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Default); + return this.root; + } + } + + } + +} Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs (from rev 4824, trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,128 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class QueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<QueryOver<T>, T> + { + public QueryOverJoinBuilder(QueryOver<T> root, JoinType joinType) : base(root, joinType) { } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + } + + public class IQueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<IQueryOver<T>, T> + { + public IQueryOverJoinBuilder(IQueryOver<T> root, JoinType joinType) : base(root, joinType) { } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + + } + + public class QueryOverJoinBuilderBase<R, T> where R : IQueryOver<T> + { + + protected R root; + protected JoinType joinType; + + public QueryOverJoinBuilderBase(R root, JoinType joinType) + { + this.root = root; + this.joinType = joinType; + } + + public R JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) + { + return (R)root.JoinAlias(path, alias, joinType); + } + + public R JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) + { + return (R)root.JoinAlias(path, alias, joinType); + } + + } + +} Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs (from rev 4822, trunk/nhibernate/src/NHibernate/Criterion/QueryOverLockBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,106 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class QueryOverLockBuilder<T> : QueryOverLockBuilderBase<QueryOver<T>, T> + { + + public QueryOverLockBuilder(QueryOver<T> root, Expression<Func<object>> alias) + : base(root, alias) { } + + } + + public class IQueryOverLockBuilder<T> : QueryOverLockBuilderBase<IQueryOver<T>, T> + { + + public IQueryOverLockBuilder(IQueryOver<T> root, Expression<Func<object>> alias) + : base(root, alias) { } + + } + + public class QueryOverLockBuilderBase<R, T> where R : IQueryOver<T> + { + + protected R root; + protected string alias; + + protected QueryOverLockBuilderBase(R root, Expression<Func<object>> alias) + { + this.root = root; + + if (alias != null) + this.alias = ExpressionProcessor.FindMemberExpression(alias.Body); + } + + private void SetLockMode(LockMode lockMode) + { + if (alias != null) + root.UnderlyingCriteria.SetLockMode(alias, lockMode); + else + root.UnderlyingCriteria.SetLockMode(lockMode); + } + + public R Force + { + get + { + SetLockMode(LockMode.Force); + return this.root; + } + } + + public R None + { + get + { + SetLockMode(LockMode.None); + return this.root; + } + } + + public R Read + { + get + { + SetLockMode(LockMode.Read); + return this.root; + } + } + + public R Upgrade + { + get + { + SetLockMode(LockMode.Upgrade); + return this.root; + } + } + + public R UpgradeNoWait + { + get + { + SetLockMode(LockMode.UpgradeNoWait); + return this.root; + } + } + + public R Write + { + get + { + SetLockMode(LockMode.Write); + return this.root; + } + } + + } + +} Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs (from rev 4822, trunk/nhibernate/src/NHibernate/Criterion/QueryOverOrderBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,72 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class QueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<QueryOver<T>, T> + { + + public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) + {} + + public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<object>> path) : base(root, path) + {} + + } + + public class IQueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<IQueryOver<T>, T> + { + + public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) + {} + + public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<object>> path) : base(root, path) + {} + + } + + public class QueryOverOrderBuilderBase<R, T> where R : IQueryOver<T> + { + + protected R root; + protected LambdaExpression path; + + protected QueryOverOrderBuilderBase(R root, Expression<Func<T, object>> path) + { + this.root = root; + this.path = path; + } + + protected QueryOverOrderBuilderBase(R root, Expression<Func<object>> path) + { + this.root = root; + this.path = path; + } + + public R Asc + { + get + { + this.root.UnderlyingCriteria.AddOrder(ExpressionProcessor.ProcessOrder(path, Order.Asc)); + return this.root; + } + } + + public R Desc + { + get + { + this.root.UnderlyingCriteria.AddOrder(ExpressionProcessor.ProcessOrder(path, Order.Desc)); + return this.root; + } + } + + } + +} Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs (from rev 4823, trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,64 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + 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, null); + } + + public S WhereValue(object value) + { + return (S)new S().Set(root, null, value); + } + + } + +} Copied: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs (from rev 4823, trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -0,0 +1,152 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + 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() { } + + internal abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value); + } + + public class QueryOverSubqueryPropertyBuilderBase<R, T> : QueryOverSubqueryPropertyBuilderBase + where R : IQueryOver<T> + { + + protected R root; + protected string path; + protected object value; + + protected QueryOverSubqueryPropertyBuilderBase() + { + } + + internal override QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value) + { + this.root = (R)root; + this.path = path; + this.value = value; + return this; + } + + private void AddSubquery<U>( + Func<string, DetachedCriteria, AbstractCriterion> propertyMethod, + Func<object, DetachedCriteria, AbstractCriterion> valueMethod, + QueryOver<U> detachedCriteria) + { + if (path != null) + { + root.And(propertyMethod(path, detachedCriteria.DetachedCriteria)); + } + else + { + root.And(valueMethod(value, detachedCriteria.DetachedCriteria)); + } + } + + /// <summary> + /// Add a property equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Eq<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyEq, Subqueries.Eq, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property greater than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Ge<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGe, Subqueries.Ge, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property greater than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Gt<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGt, Subqueries.Gt, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R In<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyIn, Subqueries.In, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Le<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLe, Subqueries.Le, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Lt<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLt, Subqueries.Lt, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property not equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Ne<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyNe, Subqueries.Ne, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property not in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R NotIn<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyNotIn, Subqueries.NotIn, detachedCriteria); + return root; + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq.Expressions; +using NHibernate.Criterion.Lambda; using NHibernate.Impl; using NHibernate.SqlCommand; Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverFetchBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverFetchBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverFetchBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,69 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -using NHibernate.Impl; -using NHibernate.SqlCommand; - -namespace NHibernate.Criterion -{ - - public class QueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<QueryOver<T>, T> - { - - public QueryOverFetchBuilder(QueryOver<T> root, Expression<Func<T, object>> path) - : base(root, path) { } - - } - - public class IQueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<IQueryOver<T>, T> - { - - public IQueryOverFetchBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) - : base(root, path) { } - - } - - public class QueryOverFetchBuilderBase<R, T> where R : IQueryOver<T> - { - - protected R root; - protected string path; - - protected QueryOverFetchBuilderBase(R root, Expression<Func<T, object>> path) - { - this.root = root; - this.path = ExpressionProcessor.FindMemberExpression(path.Body); - } - - public R Eager - { - get - { - this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Eager); - return this.root; - } - } - - public R Lazy - { - get - { - this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Lazy); - return this.root; - } - } - - public R Default - { - get - { - this.root.UnderlyingCriteria.SetFetchMode(path, FetchMode.Default); - return this.root; - } - } - - } - -} Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,128 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -using NHibernate.Impl; -using NHibernate.SqlCommand; - -namespace NHibernate.Criterion -{ - - public class QueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<QueryOver<T>, T> - { - public QueryOverJoinBuilder(QueryOver<T> root, JoinType joinType) : base(root, joinType) { } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - } - - public class IQueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<IQueryOver<T>, T> - { - public IQueryOverJoinBuilder(IQueryOver<T> root, JoinType joinType) : base(root, joinType) { } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) - { - return root.JoinQueryOver<U>(path, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) - { - return root.JoinQueryOver<U>(path, alias, joinType); - } - - } - - public class QueryOverJoinBuilderBase<R, T> where R : IQueryOver<T> - { - - protected R root; - protected JoinType joinType; - - public QueryOverJoinBuilderBase(R root, JoinType joinType) - { - this.root = root; - this.joinType = joinType; - } - - public R JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) - { - return (R)root.JoinAlias(path, alias, joinType); - } - - public R JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) - { - return (R)root.JoinAlias(path, alias, joinType); - } - - } - -} Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverLockBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverLockBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverLockBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,106 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -using NHibernate.Impl; -using NHibernate.SqlCommand; - -namespace NHibernate.Criterion -{ - - public class QueryOverLockBuilder<T> : QueryOverLockBuilderBase<QueryOver<T>, T> - { - - public QueryOverLockBuilder(QueryOver<T> root, Expression<Func<object>> alias) - : base(root, alias) { } - - } - - public class IQueryOverLockBuilder<T> : QueryOverLockBuilderBase<IQueryOver<T>, T> - { - - public IQueryOverLockBuilder(IQueryOver<T> root, Expression<Func<object>> alias) - : base(root, alias) { } - - } - - public class QueryOverLockBuilderBase<R, T> where R : IQueryOver<T> - { - - protected R root; - protected string alias; - - protected QueryOverLockBuilderBase(R root, Expression<Func<object>> alias) - { - this.root = root; - - if (alias != null) - this.alias = ExpressionProcessor.FindMemberExpression(alias.Body); - } - - private void SetLockMode(LockMode lockMode) - { - if (alias != null) - root.UnderlyingCriteria.SetLockMode(alias, lockMode); - else - root.UnderlyingCriteria.SetLockMode(lockMode); - } - - public R Force - { - get - { - SetLockMode(LockMode.Force); - return this.root; - } - } - - public R None - { - get - { - SetLockMode(LockMode.None); - return this.root; - } - } - - public R Read - { - get - { - SetLockMode(LockMode.Read); - return this.root; - } - } - - public R Upgrade - { - get - { - SetLockMode(LockMode.Upgrade); - return this.root; - } - } - - public R UpgradeNoWait - { - get - { - SetLockMode(LockMode.UpgradeNoWait); - return this.root; - } - } - - public R Write - { - get - { - SetLockMode(LockMode.Write); - return this.root; - } - } - - } - -} Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverOrderBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverOrderBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverOrderBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,72 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -using NHibernate.Impl; -using NHibernate.SqlCommand; - -namespace NHibernate.Criterion -{ - - public class QueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<QueryOver<T>, T> - { - - public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) - {} - - public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<object>> path) : base(root, path) - {} - - } - - public class IQueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<IQueryOver<T>, T> - { - - public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) - {} - - public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<object>> path) : base(root, path) - {} - - } - - public class QueryOverOrderBuilderBase<R, T> where R : IQueryOver<T> - { - - protected R root; - protected LambdaExpression path; - - protected QueryOverOrderBuilderBase(R root, Expression<Func<T, object>> path) - { - this.root = root; - this.path = path; - } - - protected QueryOverOrderBuilderBase(R root, Expression<Func<object>> path) - { - this.root = root; - this.path = path; - } - - public R Asc - { - get - { - this.root.UnderlyingCriteria.AddOrder(ExpressionProcessor.ProcessOrder(path, Order.Asc)); - return this.root; - } - } - - public R Desc - { - get - { - this.root.UnderlyingCriteria.AddOrder(ExpressionProcessor.ProcessOrder(path, Order.Desc)); - return this.root; - } - } - - } - -} Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,64 +0,0 @@ - -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, null); - } - - public S WhereValue(object value) - { - return (S)new S().Set(root, null, value); - } - - } - -} Deleted: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -1,152 +0,0 @@ - -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() { } - - internal abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value); - } - - public class QueryOverSubqueryPropertyBuilderBase<R, T> : QueryOverSubqueryPropertyBuilderBase - where R : IQueryOver<T> - { - - protected R root; - protected string path; - protected object value; - - protected QueryOverSubqueryPropertyBuilderBase() - { - } - - internal override QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value) - { - this.root = (R)root; - this.path = path; - this.value = value; - return this; - } - - private void AddSubquery<U>( - Func<string, DetachedCriteria, AbstractCriterion> propertyMethod, - Func<object, DetachedCriteria, AbstractCriterion> valueMethod, - QueryOver<U> detachedCriteria) - { - if (path != null) - { - root.And(propertyMethod(path, detachedCriteria.DetachedCriteria)); - } - else - { - root.And(valueMethod(value, detachedCriteria.DetachedCriteria)); - } - } - - /// <summary> - /// Add a property equal subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Eq<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyEq, Subqueries.Eq, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property greater than or equal subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Ge<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyGe, Subqueries.Ge, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property greater than subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Gt<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyGt, Subqueries.Gt, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property in subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R In<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyIn, Subqueries.In, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property less than or equal subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Le<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyLe, Subqueries.Le, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property less than subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Lt<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyLt, Subqueries.Lt, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property not equal subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R Ne<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyNe, Subqueries.Ne, detachedCriteria); - return root; - } - - /// <summary> - /// Create a property not in subquery criterion - /// </summary> - /// <param name="detachedCriteria">detached subquery</param> - public R NotIn<U>(QueryOver<U> detachedCriteria) - { - AddSubquery(Subqueries.PropertyNotIn, Subqueries.NotIn, detachedCriteria); - return root; - } - - } - -} Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-10 13:32:28 UTC (rev 4825) @@ -4,6 +4,7 @@ using System.Linq.Expressions; using NHibernate.Criterion; +using NHibernate.Criterion.Lambda; using NHibernate.SqlCommand; namespace NHibernate Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-08 10:58:42 UTC (rev 4824) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-10 13:32:28 UTC (rev 4825) @@ -505,12 +505,12 @@ <Compile Include="Context\WcfOperationSessionContext.cs" /> <Compile Include="Criterion\GroupedProjection.cs" /> <Compile Include="Criterion\IPropertyProjection.cs" /> - <Compile Include="Criterion\QueryOverFetchBuilder.cs" /> - <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="Criterion\Lambda\QueryOverFetchBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverJoinBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverLockBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverOrderBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverSubqueryBuilder.cs" /> + <Compile Include="Criterion\Lambda\QueryOverSubqueryPropertyBuilder.cs" /> <Compile Include="Dialect\MsSql2008Dialect.cs" /> <Compile Include="Dialect\InformixDialect0940.cs" /> <Compile Include="Dialect\InformixDialect1000.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-08 10:58:56
|
Revision: 4824 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4824&view=rev Author: ricbrown Date: 2009-11-08 10:58:42 +0000 (Sun, 08 Nov 2009) Log Message: ----------- Minor change to QueryOver CreateAlias() syntax. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-07 12:43:07 UTC (rev 4823) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-08 10:58:42 UTC (rev 4824) @@ -318,7 +318,7 @@ joinType)); } - public QueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias) + public QueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -326,7 +326,7 @@ JoinType.InnerJoin); } - public QueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias) + public QueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -334,7 +334,7 @@ JoinType.InnerJoin); } - public QueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) + public QueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -342,7 +342,7 @@ joinType); } - public QueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + public QueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -558,17 +558,17 @@ IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { return JoinQueryOver(path, alias, joinType); } - IQueryOver<T> IQueryOver<T>.Join(Expression<Func<T, object>> path, Expression<Func<object>> alias) - { return Join(path, alias); } + IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) + { return JoinAlias(path, alias); } - IQueryOver<T> IQueryOver<T>.Join(Expression<Func<object>> path, Expression<Func<object>> alias) - { return Join(path, alias); } + IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) + { return JoinAlias(path, alias); } - IQueryOver<T> IQueryOver<T>.Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) - { return Join(path, alias, joinType); } + IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) + { return JoinAlias(path, alias, joinType); } - IQueryOver<T> IQueryOver<T>.Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) - { return Join(path, alias, joinType); } + IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + { return JoinAlias(path, alias, joinType); } IQueryOverJoinBuilder<T> IQueryOver<T>.Inner { get { return new IQueryOverJoinBuilder<T>(this, JoinType.InnerJoin); } } Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-11-07 12:43:07 UTC (rev 4823) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-11-08 10:58:42 UTC (rev 4824) @@ -113,14 +113,14 @@ this.joinType = joinType; } - public R Join(Expression<Func<T, object>> path, Expression<Func<object>> alias) + public R JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) { - return (R)root.Join(path, alias, joinType); + return (R)root.JoinAlias(path, alias, joinType); } - public R Join(Expression<Func<object>> path, Expression<Func<object>> alias) + public R JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) { - return (R)root.Join(path, alias, joinType); + return (R)root.JoinAlias(path, alias, joinType); } } Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-07 12:43:07 UTC (rev 4823) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-08 10:58:42 UTC (rev 4824) @@ -317,7 +317,7 @@ /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <returns>criteria instance</returns> - IQueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias); + IQueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias); /// <summary> /// Join an association, assigning an alias to the joined entity @@ -325,7 +325,7 @@ /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <returns>criteria instance</returns> - IQueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias); + IQueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias); /// <summary> /// Join an association, assigning an alias to the joined entity @@ -334,7 +334,7 @@ /// <param name="alias">Lambda expression returning alias reference</param> /// <param name="joinType">Type of join</param> /// <returns>criteria instance</returns> - IQueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType); + IQueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType); /// <summary> /// Join an association, assigning an alias to the joined entity @@ -343,7 +343,7 @@ /// <param name="alias">Lambda expression returning alias reference</param> /// <param name="joinType">Type of join</param> /// <returns>criteria instance</returns> - IQueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType); + IQueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType); IQueryOverJoinBuilder<T> Inner { get; } IQueryOverJoinBuilder<T> Left { get; } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-07 12:43:07 UTC (rev 4823) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-08 10:58:42 UTC (rev 4824) @@ -270,8 +270,8 @@ Child childAlias = null; IQueryOver<Person> actual = CreateTestQueryOver<Person>() - .Join(p => p.Father, () => fatherAlias) - .Join(p => p.Children, () => childAlias); + .JoinAlias(p => p.Father, () => fatherAlias) + .JoinAlias(p => p.Children, () => childAlias); AssertCriteriaAreEqual(expected, actual); } @@ -289,8 +289,8 @@ Child childAlias = null; IQueryOver<Person> actual = CreateTestQueryOver<Person>(() => personAlias) - .Join(() => personAlias.Father, () => fatherAlias) - .Inner.Join(() => personAlias.Children, () => childAlias); + .JoinAlias(() => personAlias.Father, () => fatherAlias) + .Inner.JoinAlias(() => personAlias.Children, () => childAlias); AssertCriteriaAreEqual(expected, actual); } @@ -313,14 +313,14 @@ Relation collection1Alias = null, collection2Alias = null, collection3Alias = null, collection4Alias = null; IQueryOver<Relation> actual = CreateTestQueryOver<Relation>() - .Inner.Join(r => r.Related1, () => related1Alias) - .Inner.Join(r => r.Collection1, () => collection1Alias) - .Left.Join(r => r.Related2, () => related2Alias) - .Left.Join(r => r.Collection2, () => collection2Alias) - .Right.Join(r => r.Related3, () => related3Alias) - .Right.Join(r => r.Collection3, () => collection3Alias) - .Full.Join(r => r.Related4, () => related4Alias) - .Full.Join(r => r.Collection4, () => collection4Alias); + .Inner.JoinAlias(r => r.Related1, () => related1Alias) + .Inner.JoinAlias(r => r.Collection1, () => collection1Alias) + .Left.JoinAlias(r => r.Related2, () => related2Alias) + .Left.JoinAlias(r => r.Collection2, () => collection2Alias) + .Right.JoinAlias(r => r.Related3, () => related3Alias) + .Right.JoinAlias(r => r.Collection3, () => collection3Alias) + .Full.JoinAlias(r => r.Related4, () => related4Alias) + .Full.JoinAlias(r => r.Collection4, () => collection4Alias); AssertCriteriaAreEqual(expected, actual); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-07 12:43:19
|
Revision: 4823 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4823&view=rev Author: ricbrown Date: 2009-11-07 12:43:07 +0000 (Sat, 07 Nov 2009) Log Message: ----------- Fleshed out Subquery overloads for QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-06 22:50:19 UTC (rev 4822) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-07 12:43:07 UTC (rev 4823) @@ -66,7 +66,7 @@ /// 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> + /// <typeparam name="R">type returned by query</typeparam> /// <returns>throws an exception if evaluated directly at runtime.</returns> public R As<R>() { Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs 2009-11-06 22:50:19 UTC (rev 4822) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryBuilder.cs 2009-11-07 12:43:07 UTC (rev 4823) @@ -51,9 +51,14 @@ public S WhereProperty(Expression<Func<T, object>> expression) { string property = ExpressionProcessor.FindMemberExpression(expression.Body); - return (S) new S().Set(root, property); + return (S)new S().Set(root, property, null); } + public S WhereValue(object value) + { + return (S)new S().Set(root, null, value); + } + } } Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs 2009-11-06 22:50:19 UTC (rev 4822) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverSubqueryPropertyBuilder.cs 2009-11-07 12:43:07 UTC (rev 4823) @@ -29,7 +29,7 @@ { protected QueryOverSubqueryPropertyBuilderBase() { } - public abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path); + internal abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value); } public class QueryOverSubqueryPropertyBuilderBase<R, T> : QueryOverSubqueryPropertyBuilderBase @@ -38,28 +38,115 @@ protected R root; protected string path; + protected object value; protected QueryOverSubqueryPropertyBuilderBase() { } - public override QueryOverSubqueryPropertyBuilderBase Set(object root, string path) + internal override QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value) { this.root = (R)root; this.path = path; + this.value = value; return this; } + private void AddSubquery<U>( + Func<string, DetachedCriteria, AbstractCriterion> propertyMethod, + Func<object, DetachedCriteria, AbstractCriterion> valueMethod, + QueryOver<U> detachedCriteria) + { + if (path != null) + { + root.And(propertyMethod(path, detachedCriteria.DetachedCriteria)); + } + else + { + root.And(valueMethod(value, detachedCriteria.DetachedCriteria)); + } + } + /// <summary> /// Add a property equal subquery criterion /// </summary> /// <param name="detachedCriteria">detached subquery</param> - public R Eq(QueryOver<T> detachedCriteria) + public R Eq<U>(QueryOver<U> detachedCriteria) { - root.Where(Subqueries.PropertyEq(path, detachedCriteria.DetachedCriteria)); + AddSubquery(Subqueries.PropertyEq, Subqueries.Eq, detachedCriteria); return root; } + /// <summary> + /// Create a property greater than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Ge<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGe, Subqueries.Ge, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property greater than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Gt<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyGt, Subqueries.Gt, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R In<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyIn, Subqueries.In, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than or equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Le<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLe, Subqueries.Le, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property less than subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Lt<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyLt, Subqueries.Lt, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property not equal subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R Ne<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyNe, Subqueries.Ne, detachedCriteria); + return root; + } + + /// <summary> + /// Create a property not in subquery criterion + /// </summary> + /// <param name="detachedCriteria">detached subquery</param> + public R NotIn<U>(QueryOver<U> detachedCriteria) + { + AddSubquery(Subqueries.PropertyNotIn, Subqueries.NotIn, detachedCriteria); + return root; + } + } } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs 2009-11-06 22:50:19 UTC (rev 4822) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs 2009-11-07 12:43:07 UTC (rev 4823) @@ -35,6 +35,7 @@ { public virtual int Id { get; set; } public virtual string Nickname { get; set; } + public virtual int Age { get; set; } } public class Relation Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-06 22:50:19 UTC (rev 4822) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-07 12:43:07 UTC (rev 4823) @@ -16,13 +16,13 @@ public class SubqueryFixture : LambdaFixtureBase { - private Person _subqueryPersonAlias = null; + private Child _subqueryChildAlias = null; - private DetachedCriteria DetachedCriteriaPerson + private DetachedCriteria DetachedCriteriaChild { get { - return ToDetachedCriteria(DetachedQueryOverPerson); + return ToDetachedCriteria(DetachedQueryOverChild); } } @@ -34,37 +34,70 @@ } } - private QueryOver<Person> DetachedQueryOverPerson + private DetachedCriteria DetachedCriteriaAge { get { + return ToDetachedCriteria(DetachedQueryOverAge); + } + } + + private QueryOver<Child> DetachedQueryOverChild + { + get + { return - new QueryOver<Person>(() => _subqueryPersonAlias) - .Where(() => _subqueryPersonAlias.Name == "subquery name"); + new QueryOver<Child>(() => _subqueryChildAlias) + .Where(() => _subqueryChildAlias.Nickname == "subquery name"); } } - private QueryOver<Person> DetachedQueryOverName + private QueryOver<Child> DetachedQueryOverName { get { return - new QueryOver<Person>(() => _subqueryPersonAlias) - .Where(() => _subqueryPersonAlias.Name == "subquery name") - .Select(p => p.Name); + new QueryOver<Child>(() => _subqueryChildAlias) + .Where(() => _subqueryChildAlias.Nickname == "subquery name") + .Select(p => p.Nickname); } } + private QueryOver<Child> DetachedQueryOverAge + { + get + { + return + new QueryOver<Child>(() => _subqueryChildAlias) + .Where(() => _subqueryChildAlias.Nickname == "subquery name") + .Select(p => p.Age); + } + } + [Test] public void Property() { ICriteria expected = CreateTestCriteria(typeof(Person)) - .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)); + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGt("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyIn("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyLe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLt("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyNe("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyNotIn("Name", DetachedCriteriaName)); var actual = CreateTestQueryOver<Person>() - .WithSubquery.WhereProperty(p => p.Name).Eq(DetachedQueryOverName); + .WithSubquery.WhereProperty(p => p.Name).Eq(DetachedQueryOverName) + .WithSubquery.WhereProperty(p => p.Age).Ge(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).Gt(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Name).In(DetachedQueryOverName) + .WithSubquery.WhereProperty(p => p.Age).Le(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Age).Lt(DetachedQueryOverAge) + .WithSubquery.WhereProperty(p => p.Name).Ne(DetachedQueryOverName) + .WithSubquery.WhereProperty(p => p.Name).NotIn(DetachedQueryOverName); AssertCriteriaAreEqual(expected, actual); } @@ -74,15 +107,53 @@ { ICriteria expected = CreateTestCriteria(typeof(Person)) - .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)); + .Add(Subqueries.PropertyEq("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyNe("Name", DetachedCriteriaName)) + .Add(Subqueries.PropertyGe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyGt("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLe("Age", DetachedCriteriaAge)) + .Add(Subqueries.PropertyLt("Age", DetachedCriteriaAge)); var actual = CreateTestQueryOver<Person>() - .WithSubquery.Where(p => p.Name == DetachedQueryOverName.As<string>()); + .WithSubquery.Where(p => p.Name == DetachedQueryOverName.As<string>()) + .WithSubquery.Where(p => p.Name != DetachedQueryOverName.As<string>()) + .WithSubquery.Where(p => p.Age >= DetachedQueryOverAge.As<int>()) + .WithSubquery.Where(p => p.Age > DetachedQueryOverAge.As<int>()) + .WithSubquery.Where(p => p.Age <= DetachedQueryOverAge.As<int>()) + .WithSubquery.Where(p => p.Age < DetachedQueryOverAge.As<int>()); AssertCriteriaAreEqual(expected, actual); } + [Test] + public void Value() + { + ICriteria expected = + CreateTestCriteria(typeof(Person)) + .Add(Subqueries.Eq("Name", DetachedCriteriaName)) + .Add(Subqueries.Ge("Age", DetachedCriteriaAge)) + .Add(Subqueries.Gt("Age", DetachedCriteriaAge)) + .Add(Subqueries.In("Name", DetachedCriteriaName)) + .Add(Subqueries.Le("Age", DetachedCriteriaAge)) + .Add(Subqueries.Lt("Age", DetachedCriteriaAge)) + .Add(Subqueries.Ne("Name", DetachedCriteriaName)) + .Add(Subqueries.NotIn("Name", DetachedCriteriaName)); + + var actual = + CreateTestQueryOver<Person>() + .WithSubquery.WhereValue("Name").Eq(DetachedQueryOverName) + .WithSubquery.WhereValue("Age").Ge(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").Gt(DetachedQueryOverAge) + .WithSubquery.WhereValue("Name").In(DetachedQueryOverName) + .WithSubquery.WhereValue("Age").Le(DetachedQueryOverAge) + .WithSubquery.WhereValue("Age").Lt(DetachedQueryOverAge) + .WithSubquery.WhereValue("Name").Ne(DetachedQueryOverName) + .WithSubquery.WhereValue("Name").NotIn(DetachedQueryOverName); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-06 22:50:31
|
Revision: 4822 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4822&view=rev Author: steverstrong Date: 2009-11-06 22:50:19 +0000 (Fri, 06 Nov 2009) Log Message: ----------- Further Linq work - Support for Enumerable.Aggregate and various string functions (xxx.StartsWith etc) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs trunk/nhibernate/src/NHibernate/Linq/ResultTransformer.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -383,5 +383,20 @@ { return new HqlAll(_factory); } + + public HqlLike Like() + { + return new HqlLike(_factory); + } + + public HqlConcat Concat() + { + return new HqlConcat(_factory); + } + + public HqlExpressionList ExpressionList() + { + return new HqlExpressionList(_factory); + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -632,4 +632,18 @@ { } } + + public class HqlLike : HqlTreeNode + { + public HqlLike(IASTFactory factory) : base(HqlSqlWalker.LIKE, "like", factory) + { + } + } + + public class HqlConcat : HqlTreeNode + { + public HqlConcat(IASTFactory factory) : base(HqlSqlWalker.METHOD_CALL, "method", factory) + { + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -1,8 +1,28 @@ +using System; using System.Linq; +using System.Linq.Expressions; using System.Reflection; namespace NHibernate.Linq { + public static class ReflectionHelper + { + public delegate void Action(); + + public static MethodInfo GetMethod<TSource>(Expression<Action<TSource>> method) + { + var methodInfo = ((MethodCallExpression) method.Body).Method; + return methodInfo.IsGenericMethod ? methodInfo.GetGenericMethodDefinition() : methodInfo; + } + + public static MethodInfo GetMethod(Expression<Action> method) + { + var methodInfo = ((MethodCallExpression)method.Body).Method; + return methodInfo.IsGenericMethod ? methodInfo.GetGenericMethodDefinition() : methodInfo; + } + } + + // TODO rename / remove - reflection helper above is better public static class EnumerableHelper { public static MethodInfo GetMethod(string name, System.Type[] parameterTypes) Modified: trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/HqlNodeStack.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -11,6 +11,7 @@ public HqlNodeStack(HqlTreeBuilder builder) { + // TODO - only reason for the build is to have a root node. Sucks, change this _root = builder.Holder(); _stack.Push(_root); } Modified: trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -1,16 +1,36 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using NHibernate.Engine.Query; using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Linq.ResultOperators; using NHibernate.Linq.Visitors; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.StreamedData; using Remotion.Data.Linq.Parsing.ExpressionTreeVisitors; using Remotion.Data.Linq.Parsing.Structure; +using Remotion.Data.Linq.Parsing.Structure.IntermediateModel; namespace NHibernate.Linq { public class NhLinqExpression : IQueryExpression { + private static readonly MethodCallExpressionNodeTypeRegistry MethodCallRegistry = + MethodCallExpressionNodeTypeRegistry.CreateDefault(); + + static NhLinqExpression() + { + MethodCallRegistry.Register( + new[] + { + MethodCallExpressionNodeTypeRegistry.GetRegisterableMethodDefinition(ReflectionHelper.GetMethod(() => Queryable.Aggregate<object>(null, null))), + MethodCallExpressionNodeTypeRegistry.GetRegisterableMethodDefinition(ReflectionHelper.GetMethod(() => Queryable.Aggregate<object, object>(null, null, null))) + }, + typeof (AggregateExpressionNode)); + } + + private readonly Expression _expression; private CommandData _commandData; private readonly IDictionary<ConstantExpression, NamedParameter> _queryParameters; @@ -40,7 +60,8 @@ public IASTNode Translate(ISessionFactory sessionFactory) { var requiredHqlParameters = new List<NamedParameterDescriptor>(); - var queryModel = new QueryParser(new ExpressionTreeParser(MethodCallExpressionNodeTypeRegistry.CreateDefault())).GetParsedQuery(_expression); + // TODO - can we cache any of this? + var queryModel = new QueryParser(new ExpressionTreeParser(MethodCallRegistry)).GetParsedQuery(_expression); _commandData = QueryModelVisitor.GenerateHqlQuery(queryModel, _queryParameters, requiredHqlParameters); @@ -67,4 +88,65 @@ _commandData.AddAdditionalCriteria(impl); } } + + public class AggregateExpressionNode : ResultOperatorExpressionNodeBase + { + public MethodCallExpressionParseInfo ParseInfo { get; set; } + public Expression OptionalSeed { get; set; } + public LambdaExpression Accumulator { get; set; } + public LambdaExpression OptionalSelector { get; set; } + + public AggregateExpressionNode(MethodCallExpressionParseInfo parseInfo, Expression arg1, Expression arg2, LambdaExpression optionalSelector) : base(parseInfo, null, optionalSelector) + { + ParseInfo = parseInfo; + + if (arg2 != null) + { + OptionalSeed = arg1; + Accumulator = (LambdaExpression) arg2; + } + else + { + Accumulator = (LambdaExpression) arg1; + } + + OptionalSelector = optionalSelector; + } + + public override Expression Resolve(ParameterExpression inputParameter, Expression expressionToBeResolved, ClauseGenerationContext clauseGenerationContext) + { + throw new NotImplementedException(); + } + + protected override ResultOperatorBase CreateResultOperator(ClauseGenerationContext clauseGenerationContext) + { + return new AggregateResultOperator(ParseInfo, OptionalSeed, Accumulator, OptionalSelector); + } + } + + public class AggregateResultOperator : ClientSideTransformOperator + { + public MethodCallExpressionParseInfo ParseInfo { get; set; } + public Expression OptionalSeed { get; set; } + public LambdaExpression Accumulator { get; set; } + public LambdaExpression OptionalSelector { get; set; } + + public AggregateResultOperator(MethodCallExpressionParseInfo parseInfo, Expression optionalSeed, LambdaExpression accumulator, LambdaExpression optionalSelector) + { + ParseInfo = parseInfo; + OptionalSeed = optionalSeed; + Accumulator = accumulator; + OptionalSelector = optionalSelector; + } + + public override IStreamedDataInfo GetOutputDataInfo(IStreamedDataInfo inputInfo) + { + throw new NotImplementedException(); + } + + public override ResultOperatorBase Clone(CloneContext cloneContext) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/ResultTransformer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ResultTransformer.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/ResultTransformer.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -1,7 +1,9 @@ using System; using System.Collections; +using System.Linq; using System.Linq.Expressions; using NHibernate.Transform; +using Remotion.Collections; namespace NHibernate.Linq { @@ -30,7 +32,38 @@ public IList TransformList(IList collection) { - return _listTransformation == null ? collection : (IList) _listTransformation.DynamicInvoke(collection); + if (_listTransformation == null) + { + return collection; + } + + object transformResult = collection; + + if (collection.Count > 0) + { + if (collection[0] is object[]) + { + if ( ((object[])collection[0]).Length != 1) + { + // We only expect single items + throw new NotSupportedException(); + } + + transformResult = _listTransformation.DynamicInvoke(collection.Cast<object[]>().Select(o => o[0])); + } + else + { + transformResult = _listTransformation.DynamicInvoke(collection); + } + } + + if (transformResult is IList) + { + return (IList) transformResult; + } + + var list = new ArrayList {transformResult}; + return list; } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using NHibernate.Engine.Query; using NHibernate.Hql.Ast; using NHibernate.Linq.Expressions; -using NHibernate.Linq.ReWriters; +using Remotion.Data.Linq; using Remotion.Data.Linq.Clauses.Expressions; using Remotion.Data.Linq.Clauses.ExpressionTreeVisitors; @@ -17,8 +19,9 @@ protected readonly HqlNodeStack _stack; private readonly IDictionary<ConstantExpression, NamedParameter> _parameters; private readonly IList<NamedParameterDescriptor> _requiredHqlParameters; + static private readonly MethodGeneratorRegistry _methodGeneratorRegistry = MethodGeneratorRegistry.Initialise(); - public HqlGeneratorExpressionTreeVisitor(IDictionary<ConstantExpression, NamedParameter> parameters, IList<NamedParameterDescriptor> requiredHqlParameters) + public HqlGeneratorExpressionTreeVisitor(IDictionary<ConstantExpression, NamedParameter> parameters, IList<NamedParameterDescriptor> requiredHqlParameters) { _parameters = parameters; _requiredHqlParameters = requiredHqlParameters; @@ -36,6 +39,16 @@ VisitExpression(expression); } + public HqlNodeStack Stack + { + get { return _stack; } + } + + public HqlTreeBuilder TreeBuilder + { + get { return _hqlTreeBuilder; } + } + protected override Expression VisitNhAverage(NhAverageExpression expression) { var visitor = new HqlGeneratorExpressionTreeVisitor(_parameters, _requiredHqlParameters); @@ -238,106 +251,11 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression expression) { - if (expression.Method.DeclaringType == typeof(Enumerable) || - expression.Method.DeclaringType == typeof(Queryable)) - { - switch (expression.Method.Name) - { - case "Any": - // Any has one or two arguments. Arg 1 is the source and arg 2 is the optional predicate - using (_stack.PushNode(_hqlTreeBuilder.Exists())) - { - using (_stack.PushNode(_hqlTreeBuilder.Query())) - { - using (_stack.PushNode(_hqlTreeBuilder.SelectFrom())) - { - using (_stack.PushNode(_hqlTreeBuilder.From())) - { - using (_stack.PushNode(_hqlTreeBuilder.Range())) - { - VisitExpression(expression.Arguments[0]); + var generator = _methodGeneratorRegistry.GetMethodGenerator(expression.Method); - if (expression.Arguments.Count > 1) - { - var expr = (LambdaExpression) expression.Arguments[1]; - _stack.PushLeaf(_hqlTreeBuilder.Alias(expr.Parameters[0].Name)); - } - } - } - } - if (expression.Arguments.Count > 1) - { - using (_stack.PushNode(_hqlTreeBuilder.Where())) - { - VisitExpression(expression.Arguments[1]); - } - } - } - } - break; + generator.BuildHql(expression.Object, expression.Arguments, this); - case "All": - // All has one or two arguments. Arg 1 is the source and arg 2 is the optional predicate - using (_stack.PushNode(_hqlTreeBuilder.Not())) - { - using (_stack.PushNode(_hqlTreeBuilder.Exists())) - { - using (_stack.PushNode(_hqlTreeBuilder.Query())) - { - using (_stack.PushNode(_hqlTreeBuilder.SelectFrom())) - { - using (_stack.PushNode(_hqlTreeBuilder.From())) - { - using (_stack.PushNode(_hqlTreeBuilder.Range())) - { - VisitExpression(expression.Arguments[0]); - - if (expression.Arguments.Count > 1) - { - var expr = (LambdaExpression) expression.Arguments[1]; - - _stack.PushLeaf(_hqlTreeBuilder.Alias(expr.Parameters[0].Name)); - } - } - } - } - if (expression.Arguments.Count > 1) - { - using (_stack.PushNode(_hqlTreeBuilder.Where())) - { - using (_stack.PushNode(_hqlTreeBuilder.Not())) - { - VisitExpression(expression.Arguments[1]); - } - } - } - } - } - } - break; - - case "Min": - using (_stack.PushNode(_hqlTreeBuilder.Min())) - { - VisitExpression(expression.Arguments[1]); - } - break; - case "Max": - using (_stack.PushNode(_hqlTreeBuilder.Max())) - { - VisitExpression(expression.Arguments[1]); - } - break; - default: - throw new NotSupportedException(string.Format("The Enumerable method {0} is not supported", expression.Method.Name)); - } - - return expression; - } - else - { - return base.VisitMethodCallExpression(expression); // throws - } + return expression; } protected override Expression VisitLambdaExpression(LambdaExpression expression) @@ -401,4 +319,352 @@ return itemAsExpression != null ? FormattingExpressionTreeVisitor.Format(itemAsExpression) : unhandledItem.ToString(); } } + + public class MethodGeneratorRegistry + { + public static MethodGeneratorRegistry Initialise() + { + var registry = new MethodGeneratorRegistry(); + + // TODO - could use reflection here + registry.Register(new QueryableMethodsGenerator()); + registry.Register(new StringMethodsGenerator()); + + return registry; + } + + private readonly Dictionary<MethodInfo, IHqlGeneratorForMethod> _registeredMethods = new Dictionary<MethodInfo, IHqlGeneratorForMethod>(); + + public IHqlGeneratorForMethod GetMethodGenerator(MethodInfo method) + { + IHqlGeneratorForMethod methodGenerator; + + if (method.IsGenericMethod) + { + method = method.GetGenericMethodDefinition(); + } + + if (_registeredMethods.TryGetValue(method, out methodGenerator)) + { + return methodGenerator; + } + + throw new NotSupportedException(); + } + + public void RegisterMethodGenerator(MethodInfo method, IHqlGeneratorForMethod generator) + { + _registeredMethods.Add(method, generator); + } + + private void Register(IHqlGeneratorForType typeMethodGenerator) + { + typeMethodGenerator.RegisterMethods(this); + } + + } + + public interface IHqlGeneratorForMethod + { + IEnumerable<MethodInfo> SupportedMethods { get; } + void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); + } + + public interface IHqlGeneratorForType + { + void RegisterMethods(MethodGeneratorRegistry methodGeneratorRegistry); + } + + abstract public class BaseHqlGeneratorForType : IHqlGeneratorForType + { + protected readonly List<IHqlGeneratorForMethod> MethodRegistry = new List<IHqlGeneratorForMethod>(); + + public void RegisterMethods(MethodGeneratorRegistry methodGeneratorRegistry) + { + foreach (var generator in MethodRegistry) + { + foreach (var method in generator.SupportedMethods) + { + methodGeneratorRegistry.RegisterMethodGenerator(method, generator); + } + } + } + } + + public abstract class BaseHqlGeneratorForMethod : IHqlGeneratorForMethod + { + public IEnumerable<MethodInfo> SupportedMethods { get; protected set; } + + public abstract void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor); + } + + public class StringMethodsGenerator : BaseHqlGeneratorForType + { + public StringMethodsGenerator() + { + // TODO - could use reflection + MethodRegistry.Add(new StartsWithGenerator()); + MethodRegistry.Add(new EndsWithGenerator()); + MethodRegistry.Add(new ContainsGenerator()); + MethodRegistry.Add(new EqualsGenerator()); + } + + class StartsWithGenerator : BaseHqlGeneratorForMethod + { + public StartsWithGenerator() + { + SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.StartsWith(null)) }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) + { + hqlVisitor.Visit(targetObject); + + // TODO - this sucks. Concat() just pushes a method node, and we have to do all the child stuff. + // Sort out the tree stuff so it works properly + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Concat())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("concat")); + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Visit(arguments[0]); + + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Constant("%")); + } + } + } + } + } + + class EndsWithGenerator : BaseHqlGeneratorForMethod + { + public EndsWithGenerator() + { + SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.EndsWith(null)) }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) + { + hqlVisitor.Visit(targetObject); + + // TODO - this sucks. Concat() just pushes a method node, and we have to do all the child stuff. + // Sort out the tree stuff so it works properly + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Concat())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("concat")); + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Constant("%")); + + hqlVisitor.Visit(arguments[0]); + } + } + } + } + } + + class ContainsGenerator : BaseHqlGeneratorForMethod + { + public ContainsGenerator() + { + SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.Contains(null)) }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Like())) + { + hqlVisitor.Visit(targetObject); + + // TODO - this sucks. Concat() just pushes a method node, and we have to do all the child stuff. + // Sort out the tree stuff so it works properly + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Concat())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Ident("concat")); + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.ExpressionList())) + { + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Constant("%")); + + hqlVisitor.Visit(arguments[0]); + + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Constant("%")); + } + } + } + } + } + + class EqualsGenerator : BaseHqlGeneratorForMethod + { + public EqualsGenerator() + { + SupportedMethods = new[] { ReflectionHelper.GetMethod<string>(x => x.Equals((string)null)) }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Equality())) + { + hqlVisitor.Visit(targetObject); + + hqlVisitor.Visit(arguments[0]); + } + } + } + } + + public class QueryableMethodsGenerator : BaseHqlGeneratorForType + { + public QueryableMethodsGenerator() + { + // TODO - could use reflection + MethodRegistry.Add(new AnyGenerator()); + MethodRegistry.Add(new AllGenerator()); + MethodRegistry.Add(new MinGenerator()); + MethodRegistry.Add(new MaxGenerator()); + } + + class AnyGenerator : BaseHqlGeneratorForMethod + { + public AnyGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Any<object>(null)), + ReflectionHelper.GetMethod(() => Queryable.Any<object>(null, null)), + ReflectionHelper.GetMethod(() => Enumerable.Any<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Any<object>(null, null)) + }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + // Any has one or two arguments. Arg 1 is the source and arg 2 is the optional predicate + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Exists())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Query())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.SelectFrom())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.From())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Range())) + { + hqlVisitor.Visit(arguments[0]); + + if (arguments.Count > 1) + { + var expr = (LambdaExpression)arguments[1]; + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Alias(expr.Parameters[0].Name)); + } + } + } + } + if (arguments.Count > 1) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Where())) + { + hqlVisitor.Visit(arguments[1]); + } + } + } + } + } + } + + class AllGenerator : BaseHqlGeneratorForMethod + { + public AllGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.All<object>(null, null)), + ReflectionHelper.GetMethod(() => Enumerable.All<object>(null, null)) + }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + // All has two arguments. Arg 1 is the source and arg 2 is the predicate + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Not())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Exists())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Query())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.SelectFrom())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.From())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Range())) + { + hqlVisitor.Visit(arguments[0]); + + var expr = (LambdaExpression)arguments[1]; + + hqlVisitor.Stack.PushLeaf(hqlVisitor.TreeBuilder.Alias(expr.Parameters[0].Name)); + } + } + } + + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Where())) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Not())) + { + hqlVisitor.Visit(arguments[1]); + } + } + } + } + } + } + } + + class MinGenerator : BaseHqlGeneratorForMethod + { + public MinGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Min<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Min<object>(null)) + }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Min())) + { + hqlVisitor.Visit(arguments[1]); + } + } + } + + class MaxGenerator : BaseHqlGeneratorForMethod + { + public MaxGenerator() + { + SupportedMethods = new[] + { + ReflectionHelper.GetMethod(() => Queryable.Max<object>(null)), + ReflectionHelper.GetMethod(() => Enumerable.Max<object>(null)) + }; + } + + public override void BuildHql(Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlGeneratorExpressionTreeVisitor hqlVisitor) + { + using (hqlVisitor.Stack.PushNode(hqlVisitor.TreeBuilder.Max())) + { + hqlVisitor.Visit(arguments[1]); + } + } + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2009-11-05 17:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -214,13 +214,70 @@ { ProcessClientSideSelect((ClientSideSelect) resultOperator); } - else + else if (resultOperator is AggregateResultOperator) + { + ProcessAggregateOperator((AggregateResultOperator)resultOperator); + } + else { throw new NotSupportedException(string.Format("The {0} result operator is not current supported", resultOperator.GetType().Name)); } } + private void ProcessAggregateOperator(AggregateResultOperator resultOperator) + { + var inputType = resultOperator.Accumulator.Parameters[1].Type; + var accumulatorType = resultOperator.Accumulator.Parameters[0].Type; + var inputList = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(typeof(object)), "inputList"); + + var castToItem = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { inputType }); + var castToItemExpr = Expression.Call(castToItem, inputList); + + MethodCallExpression call; + + if (resultOperator.ParseInfo.ParsedExpression.Arguments.Count == 2) + { + var aggregate = ReflectionHelper.GetMethod(() => Enumerable.Aggregate<object>(null, null)); + aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType); + + call = Expression.Call( + aggregate, + castToItemExpr, + resultOperator.Accumulator + ); + + } + else if (resultOperator.ParseInfo.ParsedExpression.Arguments.Count == 3) + { + var aggregate = ReflectionHelper.GetMethod(() => Enumerable.Aggregate<object, object>(null, null, null)); + aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType, accumulatorType); + + call = Expression.Call( + aggregate, + castToItemExpr, + resultOperator.OptionalSeed, + resultOperator.Accumulator + ); + } + else + { + var selectorType = resultOperator.OptionalSelector.Type.GetGenericArguments()[2]; + var aggregate = ReflectionHelper.GetMethod(() => Enumerable.Aggregate<object, object, object>(null, null, null, null)); + aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType, accumulatorType, selectorType); + + call = Expression.Call( + aggregate, + castToItemExpr, + resultOperator.OptionalSeed, + resultOperator.Accumulator, + resultOperator.OptionalSelector + ); + } + + _listTransformers.Add(Expression.Lambda(call, inputList)); + } + private void ProcessClientSideSelect(ClientSideSelect resultOperator) { var inputType = resultOperator.SelectClause.Parameters[0].Type; @@ -251,13 +308,6 @@ private void ProcessNonAggregatingGroupBy(NonAggregatingGroupBy resultOperator, QueryModel model) { - /* - public static IQueryable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( - this IQueryable<TSource> source, - Expression<Func<TSource, TKey>> keySelector, - Expression<Func<TSource, TElement>> elementSelector); - */ - var tSource = model.SelectClause.Selector.Type; var tKey = resultOperator.GroupBy.KeySelector.Type; var tElement = resultOperator.GroupBy.ElementSelector.Type; @@ -305,32 +355,8 @@ LambdaExpression elementSelectorExpr = Expression.Lambda(elementSelector, itemParam); - ParameterExpression objectArrayParam = Expression.Parameter(typeof (object[]), "array"); + Expression castToItemExpr = Expression.Call(castToItem, listParameter); - Expression castToItemExpr; - if (_itemTransformers.Count > 0) - { - // The item transformer will already have removed the object[]. We need to do this: - // list.Cast<tSource>().GroupBy(keySelectorExpr, elementSelectorExpr).ToList(); - castToItemExpr = Expression.Call(castToItem, listParameter); - } - else - { - // We have an object[] in the ResultTransformer - // list.Cast<object[]>().Select(o => o[0]).Cast<tSource>().GroupBy(keySelectorExpr, elementSelectorExpr).ToList(); - var castToObjectArray = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { typeof(object[]) }); - var selectObject = EnumerableHelper.GetMethod("Select", new[] { typeof(IEnumerable<>), typeof(Func<,>) }, new[] { typeof(object[]), typeof(object) }); - - var castToObjectArrayExpr = Expression.Call(castToObjectArray, listParameter); - - LambdaExpression index = Expression.Lambda(Expression.ArrayIndex(objectArrayParam, Expression.Constant(0)), - objectArrayParam); - - var selectObjectExpr = Expression.Call(selectObject, castToObjectArrayExpr, index); - - castToItemExpr = Expression.Call(castToItem, selectObjectExpr); - } - var groupByExpr = Expression.Call(groupByMethod, castToItemExpr, keySelectorExpr, elementSelectorExpr); var toListExpr = Expression.Call(toList, groupByExpr); Added: trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/AggregateTests.cs 2009-11-06 22:50:19 UTC (rev 4822) @@ -0,0 +1,139 @@ +using System; +using System.Linq; +using System.Text; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class AggregateTests : LinqTestCase + { + [Test] + public void AggregateWithStartsWith() + { + var query = (from c in db.Customers where c.CustomerId.StartsWith("A") select c.CustomerId) + .Aggregate(new StringBuilder(), (sb, id) => sb.Append(id).Append(",")); + + Console.WriteLine(query); + Assert.AreEqual("ALFKI,ANATR,ANTON,AROUT,", query.ToString()); + } + + [Test] + public void AggregateWithEndsWith() + { + var query = (from c in db.Customers where c.CustomerId.EndsWith("TH") select c.CustomerId) + .Aggregate(new StringBuilder(), (sb, id) => sb.Append(id).Append(",")); + + Console.WriteLine(query); + Assert.AreEqual("WARTH,", query.ToString()); + } + + [Test] + public void AggregateWithContains() + { + var query = (from c in db.Customers where c.CustomerId.Contains("CH") select c.CustomerId) + .Aggregate(new StringBuilder(), (sb, id) => sb.Append(id).Append(",")); + + Console.WriteLine(query); + Assert.AreEqual("CHOPS,RANCH,", query.ToString()); + } + + [Test] + public void AggregateWithEquals() + { + var query = (from c in db.Customers + where c.CustomerId.Equals("ALFKI") || c.CustomerId.Equals("ANATR") || c.CustomerId.Equals("ANTON") + select c.CustomerId) + .Aggregate((prev, next) => (prev + "," + next)); + + Console.WriteLine(query); + Assert.AreEqual("ALFKI,ANATR,ANTON", query); + } + + [Test] + public void AggregateWithNotStartsWith() + { + var query = (from c in db.Customers + where c.CustomerId.StartsWith("A") && !c.CustomerId.StartsWith("AN") + select c.CustomerId) + .Aggregate(new StringBuilder(), (sb, id) => sb.Append(id).Append(",")); + + Console.WriteLine(query); + Assert.AreEqual("ALFKI,AROUT,", query.ToString()); + } + /* + [Test] + [Ignore("TODO")] + public void AggregateWithMonthFunction() + { + var date = new DateTime(2007, 1, 1); + + var query = (from e in db.Employees + where db.Methods.Month(e.BirthDate) == date.Month + select e.FirstName) + .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); + + Console.WriteLine("{0} Birthdays:", date.ToString("MMMM")); + Console.WriteLine(query); + } + + [Test] + [Ignore("TODO")] + public void AggregateWithBeforeYearFunction() + { + var date = new DateTime(1960, 1, 1); + + var query = (from e in db.Employees + where db.Methods.Year(e.BirthDate) < date.Year + select db.Methods.Upper(e.FirstName)) + .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); + + Console.WriteLine("Birthdays before {0}:", date.ToString("yyyy")); + Console.WriteLine(query); + } + + [Test] + [Ignore("TODO")] + public void AggregateWithOnOrAfterYearFunction() + { + var date = new DateTime(1960, 1, 1); + + var query = (from e in db.Employees + where db.Methods.Year(e.BirthDate) >= date.Year && db.Methods.Len(e.FirstName) > 4 + select e.FirstName) + .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); + + Console.WriteLine("Birthdays after {0}:", date.ToString("yyyy")); + Console.WriteLine(query); + } + + [Test] + [Ignore("TODO")] + public void AggregateWithUpperAndLowerFunctions() + { + var date = new DateTime(2007, 1, 1); + + var query = (from e in db.Employees + where db.Methods.Month(e.BirthDate) == date.Month + select new { First = e.FirstName.ToUpper(), Last = db.Methods.Lower(e.LastName) }) + .Aggregate(new StringBuilder(), (sb, name) => sb.Length > 0 ? sb.Append(", ").Append(name) : sb.Append(name)); + + Console.WriteLine("{0} Birthdays:", date.ToString("MMMM")); + Console.WriteLine(query); + } + + [Test] + [Ignore("TODO")] + public void AggregateWithCustomFunction() + { + var date = new DateTime(1960, 1, 1); + + var query = (from e in db.Employees + where db.Methods.Year(e.BirthDate) < date.Year + select db.Methods.fnEncrypt(e.FirstName)) + .Aggregate(new StringBuilder(), (sb, name) => sb.AppendLine(BitConverter.ToString(name))); + + Console.WriteLine(query); + }*/ + } +} \ 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:46:33 UTC (rev 4821) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-06 22:50:19 UTC (rev 4822) @@ -375,6 +375,7 @@ <Compile Include="LazyOneToOne\Person.cs" /> <Compile Include="LazyProperty\Book.cs" /> <Compile Include="LazyProperty\LazyPropertyFixture.cs" /> + <Compile Include="Linq\AggregateTests.cs" /> <Compile Include="Linq\Entities\Address.cs" /> <Compile Include="Linq\Entities\Customer.cs" /> <Compile Include="Linq\Entities\Employee.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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. |
From: <ste...@us...> - 2009-11-05 17:19:32
|
Revision: 4820 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4820&view=rev Author: steverstrong Date: 2009-11-05 17:19:23 +0000 (Thu, 05 Nov 2009) Log Message: ----------- Removed some unused code Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2009-11-05 16:43:43 UTC (rev 4819) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2009-11-05 17:19:23 UTC (rev 4820) @@ -15,27 +15,15 @@ [Serializable] public class CastFunction : ISQLFunction, IFunctionGrammar { - //private LazyType returnType; #region ISQLFunction Members public IType ReturnType(IType columnType, IMapping mapping) { //note there is a weird implementation in the client side //TODO: cast that use only costant are not supported in SELECT. Ex: cast(5 as string) - //return SetLazyType(columnType); return columnType; } - /* - private LazyType SetLazyType(IType columnType) - { - if(returnType == null) - { - returnType = new LazyType(); - } - returnType.RealType = columnType; - return returnType; - } - */ + public bool HasArguments { get { return true; } @@ -55,7 +43,7 @@ string typeName = args[1].ToString(); string sqlType; IType hqlType = TypeFactory.HeuristicType(typeName); - //SetLazyType(hqlType); + if (hqlType != null) { SqlType[] sqlTypeCodes = hqlType.SqlTypes(factory); @@ -107,217 +95,5 @@ } #endregion - - /// <summary> - /// Delegate the values to a real type - /// </summary> - /// <remarks> - /// The real return type of Cast is know only after the Cast is parsed. - /// This class was created in NH to remove the responsibility of the parser about know the - /// real return type. - /// </remarks> - [Serializable] - private class LazyType: IType - { - public IType RealType { get; set; } - - #region Implementation of ICacheAssembler - - public object Disassemble(object value, ISessionImplementor session, object owner) - { - return RealType.Disassemble(value, session, owner); - } - - public object Assemble(object cached, ISessionImplementor session, object owner) - { - return RealType.Assemble(cached, session, owner); - } - - public void BeforeAssemble(object cached, ISessionImplementor session) - { - RealType.BeforeAssemble(cached, session); - } - - #endregion - - #region Implementation of IType - - public string Name - { - get { return RealType.Name; } - } - - public System.Type ReturnedClass - { - get { return RealType.ReturnedClass; } - } - - public bool IsMutable - { - get { return RealType.IsMutable; } - } - - public bool IsAssociationType - { - get { return RealType.IsAssociationType; } - } - - public bool IsXMLElement - { - get { return RealType.IsXMLElement; } - } - - public bool IsCollectionType - { - get { return RealType.IsCollectionType; } - } - - public bool IsComponentType - { - get { return RealType.IsComponentType; } - } - - public bool IsEntityType - { - get { return RealType.IsEntityType; } - } - - public bool IsAnyType - { - get { return RealType.IsAnyType; } - } - - public SqlType[] SqlTypes(IMapping mapping) - { - return RealType.SqlTypes(mapping); - } - - public int GetColumnSpan(IMapping mapping) - { - return RealType.GetColumnSpan(mapping); - } - - public bool IsDirty(object old, object current, ISessionImplementor session) - { - return RealType.IsDirty(old, current, session); - } - - public bool IsDirty(object old, object current, bool[] checkable, ISessionImplementor session) - { - return RealType.IsDirty(old, current, checkable, session); - } - - public bool IsModified(object oldHydratedState, object currentState, bool[] checkable, ISessionImplementor session) - { - return RealType.IsModified(oldHydratedState, currentState, checkable, session); - } - - public object NullSafeGet(IDataReader rs, string[] names, ISessionImplementor session, object owner) - { - return RealType.NullSafeGet(rs, names, session, owner); - } - - public object NullSafeGet(IDataReader rs, string name, ISessionImplementor session, object owner) - { - return RealType.NullSafeGet(rs, name, session, owner); - } - - public void NullSafeSet(IDbCommand st, object value, int index, bool[] settable, ISessionImplementor session) - { - RealType.NullSafeSet(st, value, index, settable, session); - } - - public void NullSafeSet(IDbCommand st, object value, int index, ISessionImplementor session) - { - RealType.NullSafeSet(st, value, index, session); - } - - public string ToLoggableString(object value, ISessionFactoryImplementor factory) - { - return RealType.ToLoggableString(value, factory); - } - - public object DeepCopy(object val, EntityMode entityMode, ISessionFactoryImplementor factory) - { - return RealType.DeepCopy(val, entityMode, factory); - } - - public object Hydrate(IDataReader rs, string[] names, ISessionImplementor session, object owner) - { - return RealType.Hydrate(rs, names, session, owner); - } - - public object ResolveIdentifier(object value, ISessionImplementor session, object owner) - { - return RealType.ResolveIdentifier(value, session, owner); - } - - public object SemiResolve(object value, ISessionImplementor session, object owner) - { - return RealType.SemiResolve(value, session, owner); - } - - public object Replace(object original, object target, ISessionImplementor session, object owner, IDictionary copiedAlready) - { - return RealType.Replace(original, target, session, owner, copiedAlready); - } - - public object Replace(object original, object target, ISessionImplementor session, object owner, IDictionary copyCache, ForeignKeyDirection foreignKeyDirection) - { - return RealType.Replace(original, target, session, owner, copyCache, foreignKeyDirection); - } - - public bool IsSame(object x, object y, EntityMode entityMode) - { - return RealType.IsSame(x, y, entityMode); - } - - public bool IsEqual(object x, object y, EntityMode entityMode) - { - return RealType.IsEqual(x, y, entityMode); - } - - public bool IsEqual(object x, object y, EntityMode entityMode, ISessionFactoryImplementor factory) - { - return RealType.IsEqual(x, y, entityMode, factory); - } - - public int GetHashCode(object x, EntityMode entityMode) - { - return RealType.GetHashCode(x, entityMode); - } - - public int GetHashCode(object x, EntityMode entityMode, ISessionFactoryImplementor factory) - { - return RealType.GetHashCode(x, entityMode, factory); - } - - public int Compare(object x, object y, EntityMode? entityMode) - { - return RealType.Compare(x, y, entityMode); - } - - public IType GetSemiResolvedType(ISessionFactoryImplementor factory) - { - return RealType.GetSemiResolvedType(factory); - } - - public void SetToXMLNode(XmlNode node, object value, ISessionFactoryImplementor factory) - { - RealType.SetToXMLNode(node, value, factory); - } - - public object FromXMLNode(XmlNode xml, IMapping factory) - { - return RealType.FromXMLNode(xml, factory); - } - - public bool[] ToColumnNullness(object value, IMapping mapping) - { - return RealType.ToColumnNullness(value, mapping); - } - - #endregion - } } } Modified: trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs 2009-11-05 16:43:43 UTC (rev 4819) +++ trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs 2009-11-05 17:19:23 UTC (rev 4820) @@ -23,13 +23,6 @@ [Test(Description = "This sample uses Count to find the number of Orders placed before yesterday in the database.")] public void CountWithWhereClause() { - using (var s = OpenSession()) - { - var r = s.CreateQuery("select cast(count(o), int) from Order o where o.OrderDate <= cast(:p1, datetime)") - .SetParameter("p1", DateTime.Today.AddDays(-1)) - .List(); - } - var q = from o in db.Orders where o.OrderDate <= DateTime.Today.AddDays(-1) select o; int count = q.Count(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ste...@us...> - 2009-11-05 16:43:54
|
Revision: 4819 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4819&view=rev Author: steverstrong Date: 2009-11-05 16:43:43 +0000 (Thu, 05 Nov 2009) Log Message: ----------- Further Linq updates, plus a change to the Cast dialect function Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/MergeAggregatingResultsRewriter.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionKeyVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByKeySelectorVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/NhThrowingExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Shipper.cs trunk/nhibernate/src/NHibernate.Test/Linq/LinqQuerySamples.cs trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Shipper.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Linq/Expressions/ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAggregatedExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhDistinctExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhExpressionType.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMaxExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMinExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhNewExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhSumExpression.cs trunk/nhibernate/src/NHibernate/Linq/GroupBy/ trunk/nhibernate/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupByAggregateDetectionVisitor.cs trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupBySelectClauseRewriter.cs trunk/nhibernate/src/NHibernate/Linq/GroupBy/NonAggregatingGroupByRewriter.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/AggregatingGroupJoinRewriter.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinAggregateDetectionVisitor.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinSelectClauseRewriter.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/IsAggregatingResults.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/LocateGroupJoinQuerySource.cs trunk/nhibernate/src/NHibernate/Linq/GroupJoin/NonAggregatingGroupJoinRewriter.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/EqualityHqlGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/SwapQuerySourceVisitor.cs trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs trunk/nhibernate/src/NHibernate.Test/Linq/ObjectDumper.cs Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Linq/NhNewExpression.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupByRewriter.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupJoinRewriter.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/GroupBySelectClauseRewriter.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/NonAggregatingGroupByRewriter.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByAggregateDetectionVisitor.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -15,16 +15,17 @@ [Serializable] public class CastFunction : ISQLFunction, IFunctionGrammar { - private LazyType returnType; + //private LazyType returnType; #region ISQLFunction Members public IType ReturnType(IType columnType, IMapping mapping) { //note there is a weird implementation in the client side //TODO: cast that use only costant are not supported in SELECT. Ex: cast(5 as string) - return SetLazyType(columnType); + //return SetLazyType(columnType); + return columnType; } - + /* private LazyType SetLazyType(IType columnType) { if(returnType == null) @@ -34,6 +35,7 @@ returnType.RealType = columnType; return returnType; } + */ public bool HasArguments { get { return true; } @@ -53,7 +55,7 @@ string typeName = args[1].ToString(); string sqlType; IType hqlType = TypeFactory.HeuristicType(typeName); - SetLazyType(hqlType); + //SetLazyType(hqlType); if (hqlType != null) { SqlType[] sqlTypeCodes = hqlType.SqlTypes(factory); Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -133,6 +133,11 @@ _node.Text = "string"; break; default: + if (type == typeof(Guid)) + { + _node.Text = "guid"; + break; + } throw new NotSupportedException(string.Format("Don't currently support idents of type {0}", type.Name)); } } Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAggregatedExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAggregatedExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAggregatedExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,21 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhAggregatedExpression : Expression + { + public Expression Expression { get; set; } + + public NhAggregatedExpression(Expression expression, NhExpressionType type) + : base((ExpressionType)type, expression.Type) + { + Expression = expression; + } + + public NhAggregatedExpression(Expression expression, System.Type expressionType, NhExpressionType type) + : base((ExpressionType)type, expressionType) + { + Expression = expression; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,11 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhAverageExpression : NhAggregatedExpression + { + public NhAverageExpression(Expression expression) : base(expression, NhExpressionType.Average) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhCountExpression : NhAggregatedExpression + { + public NhCountExpression(Expression expression) + : base(expression, typeof(int), NhExpressionType.Count) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhDistinctExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhDistinctExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhDistinctExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhDistinctExpression : NhAggregatedExpression + { + public NhDistinctExpression(Expression expression) + : base(expression, NhExpressionType.Distinct) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhExpressionType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhExpressionType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhExpressionType.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,13 @@ +namespace NHibernate.Linq.Expressions +{ + public enum NhExpressionType + { + Average = 10000, + Min, + Max, + Sum, + Count, + Distinct, + New + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMaxExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMaxExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMaxExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhMaxExpression : NhAggregatedExpression + { + public NhMaxExpression(Expression expression) + : base(expression, NhExpressionType.Max) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMinExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMinExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhMinExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhMinExpression : NhAggregatedExpression + { + public NhMinExpression(Expression expression) + : base(expression, NhExpressionType.Min) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhNewExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhNewExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhNewExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhNewExpression : Expression + { + private readonly ReadOnlyCollection<string> _members; + private readonly ReadOnlyCollection<Expression> _arguments; + + public NhNewExpression(IList<string> members, IList<Expression> arguments) + : base((ExpressionType)NhExpressionType.New, typeof(object)) + { + _members = new ReadOnlyCollection<string>(members); + _arguments = new ReadOnlyCollection<Expression>(arguments); + } + + public ReadOnlyCollection<Expression> Arguments + { + get { return _arguments; } + } + + public ReadOnlyCollection<string> Members + { + get { return _members; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhSumExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhSumExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhSumExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public class NhSumExpression : NhAggregatedExpression + { + public NhSumExpression(Expression expression) + : base(expression, NhExpressionType.Sum) + { + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,88 @@ +using System; +using System.Linq; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; +using Remotion.Data.Linq.Clauses.ResultOperators; + +namespace NHibernate.Linq.GroupBy +{ + /// <summary> + /// An AggregatingGroupBy is a query such as: + /// + /// from p in db.Products + /// group p by p.Category.CategoryId + /// into g + /// select new + /// { + /// g.Key, + /// MaxPrice = g.Max(p => p.UnitPrice) + /// }; + /// + /// Where the grouping operation is being fully aggregated and hence does not create any form of heirarchy. + /// This class takes such queries, flattens out the re-linq sub-query and re-writes the outer select + /// </summary> + public class AggregatingGroupByRewriter + { + private AggregatingGroupByRewriter() + { + } + + public static void ReWrite(QueryModel queryModel) + { + var subQueryExpression = queryModel.MainFromClause.FromExpression as SubQueryExpression; + + if ((subQueryExpression != null) && + (subQueryExpression.QueryModel.ResultOperators.Count() == 1) && + (subQueryExpression.QueryModel.ResultOperators[0] is GroupResultOperator) && + (IsAggregatingGroupBy(queryModel))) + { + var rewriter = new AggregatingGroupByRewriter(); + rewriter.FlattenSubQuery(subQueryExpression, queryModel.MainFromClause, queryModel); + } + } + + private static bool IsAggregatingGroupBy(QueryModel queryModel) + { + return new GroupByAggregateDetectionVisitor().Visit(queryModel.SelectClause.Selector); + } + + private void FlattenSubQuery(SubQueryExpression subQueryExpression, FromClauseBase fromClause, + QueryModel queryModel) + { + // Move the result operator up + if (queryModel.ResultOperators.Count != 0) + { + throw new NotImplementedException(); + } + + var groupBy = (GroupResultOperator) subQueryExpression.QueryModel.ResultOperators[0]; + + // Replace the outer select clause... + queryModel.SelectClause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryExpression.QueryModel)); + + queryModel.SelectClause.TransformExpressions( + s => + new SwapQuerySourceVisitor(queryModel.MainFromClause, subQueryExpression.QueryModel.MainFromClause).Swap + (s)); + + MainFromClause innerMainFromClause = subQueryExpression.QueryModel.MainFromClause; + CopyFromClauseData(innerMainFromClause, fromClause); + + foreach (var bodyClause in subQueryExpression.QueryModel.BodyClauses) + { + queryModel.BodyClauses.Add(bodyClause); + } + + queryModel.ResultOperators.Add(groupBy); + } + + protected void CopyFromClauseData(FromClauseBase source, FromClauseBase destination) + { + destination.FromExpression = source.FromExpression; + destination.ItemName = source.ItemName; + destination.ItemType = source.ItemType; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupByAggregateDetectionVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupByAggregateDetectionVisitor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupByAggregateDetectionVisitor.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,61 @@ +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.GroupBy +{ + // TODO: This needs strengthening. Possibly a lot in common with the GroupJoinAggregateDetectionVisitor class, which does many more checks + /// <summary> + /// Detects if an expression tree contains aggregate functions + /// </summary> + internal class GroupByAggregateDetectionVisitor : NhExpressionTreeVisitor + { + public bool ContainsAggregateMethods { get; private set; } + + public bool Visit(Expression expression) + { + ContainsAggregateMethods = false; + + VisitExpression(expression); + + return ContainsAggregateMethods; + } + + // TODO - this should not exist, since it should be handled either by re-linq or by the MergeAggregatingResultsRewriter + protected override Expression VisitMethodCallExpression(MethodCallExpression m) + { + if (m.Method.DeclaringType == typeof (Queryable) || + m.Method.DeclaringType == typeof (Enumerable)) + { + switch (m.Method.Name) + { + case "Count": + case "Min": + case "Max": + case "Sum": + case "Average": + ContainsAggregateMethods = true; + break; + } + } + + return m; + } + + protected override Expression VisitNhAggregate(NhAggregatedExpression expression) + { + ContainsAggregateMethods = true; + return expression; + } + + protected override Expression VisitSubQueryExpression(SubQueryExpression expression) + { + ContainsAggregateMethods = + new GroupByAggregateDetectionVisitor().Visit(expression.QueryModel.SelectClause.Selector); + + return expression; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupBySelectClauseRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupBySelectClauseRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupBy/GroupBySelectClauseRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,131 @@ +using System; +using System.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; +using Remotion.Data.Linq.Clauses.ResultOperators; + +namespace NHibernate.Linq.GroupBy +{ + internal class GroupBySelectClauseRewriter : NhExpressionTreeVisitor + { + public static Expression ReWrite(Expression expression, GroupResultOperator groupBy, QueryModel model) + { + var visitor = new GroupBySelectClauseRewriter(groupBy, model); + return visitor.VisitExpression(expression); + } + + private readonly GroupResultOperator _groupBy; + private readonly QueryModel _model; + + public GroupBySelectClauseRewriter(GroupResultOperator groupBy, QueryModel model) + { + _groupBy = groupBy; + _model = model; + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + if (expression.ReferencedQuerySource == _groupBy) + { + return _groupBy.ElementSelector; + } + + return base.VisitQuerySourceReferenceExpression(expression); + } + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + if (IsMemberOfModel(expression)) + { + if (expression.Member.Name == "Key") + { + return _groupBy.KeySelector; + } + else + { + Expression elementSelector = _groupBy.ElementSelector; + + if ((elementSelector is MemberExpression) || (elementSelector is QuerySourceReferenceExpression)) + { + // If ElementSelector is MemberExpression, just return + return base.VisitMemberExpression(expression); + } + else if (elementSelector is NewExpression) + { + // If ElementSelector is NewExpression, then search for member of name "get_" + originalMemberExpression.Member.Name + // TODO - this wouldn't handle nested initialisers. Should do a tree walk to find the correct member + var nex = elementSelector as NewExpression; + + int i = 0; + foreach (var member in nex.Members) + { + if (member.Name == "get_" + expression.Member.Name) + { + return nex.Arguments[i]; + } + i++; + } + + throw new NotImplementedException(); + } + else + { + throw new NotImplementedException(); + } + } + } + else + { + return base.VisitMemberExpression(expression); + } + } + + // TODO - dislike this code intensly. Should probably be a tree-walk in its own right + private bool IsMemberOfModel(MemberExpression expression) + { + var querySourceRef = expression.Expression as QuerySourceReferenceExpression; + + if (querySourceRef == null) + { + return false; + } + + var fromClause = querySourceRef.ReferencedQuerySource as FromClauseBase; + + if (fromClause == null) + { + return false; + } + + var subQuery = fromClause.FromExpression as SubQueryExpression; + + if (subQuery != null) + { + return subQuery.QueryModel == _model; + } + + var referencedQuery = fromClause.FromExpression as QuerySourceReferenceExpression; + + if (referencedQuery == null) + { + return false; + } + + var querySource = referencedQuery.ReferencedQuerySource as FromClauseBase; + + var subQuery2 = querySource.FromExpression as SubQueryExpression; + + return (subQuery2.QueryModel == _model); + } + + protected override Expression VisitSubQueryExpression(SubQueryExpression expression) + { + // TODO - is this safe? All we are extracting is the select clause from the sub-query. Assumes that everything + // else in the subquery has been removed. If there were two subqueries, one aggregating & one not, this may not be a + // valid assumption. Should probably be passed a list of aggregating subqueries that we are flattening so that we can check... + return GroupBySelectClauseRewriter.ReWrite(expression.QueryModel.SelectClause.Selector, _groupBy, _model); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupBy/NonAggregatingGroupByRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupBy/NonAggregatingGroupByRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupBy/NonAggregatingGroupByRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,108 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Linq.ResultOperators; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; +using Remotion.Data.Linq.Clauses.ResultOperators; + +namespace NHibernate.Linq.GroupBy +{ + public class NonAggregatingGroupByRewriter + { + private NonAggregatingGroupByRewriter() + { + } + + public static void ReWrite(QueryModel queryModel) + { + var subQueryExpression = queryModel.MainFromClause.FromExpression as SubQueryExpression; + + if ((subQueryExpression != null) && + (subQueryExpression.QueryModel.ResultOperators.Count() == 1) && + (subQueryExpression.QueryModel.ResultOperators[0] is GroupResultOperator) && + (IsNonAggregatingGroupBy(queryModel))) + { + var rewriter = new NonAggregatingGroupByRewriter(); + rewriter.FlattenSubQuery(subQueryExpression, queryModel.MainFromClause, queryModel); + } + } + + private void FlattenSubQuery(SubQueryExpression subQueryExpression, MainFromClause fromClause, + QueryModel queryModel) + { + // Create a new client-side select for the outer + // TODO - don't like calling GetGenericArguments here... + var clientSideSelect = new ClientSideSelect(new NonAggregatingGroupBySelectRewriter().Visit(queryModel.SelectClause.Selector, subQueryExpression.Type.GetGenericArguments()[0], queryModel.MainFromClause)); + + // Replace the outer select clause... + queryModel.SelectClause = subQueryExpression.QueryModel.SelectClause; + + MainFromClause innerMainFromClause = subQueryExpression.QueryModel.MainFromClause; + + CopyFromClauseData(innerMainFromClause, fromClause); + + foreach (var bodyClause in subQueryExpression.QueryModel.BodyClauses) + { + queryModel.BodyClauses.Add(bodyClause); + } + + // Move the result operator up + if (queryModel.ResultOperators.Count != 0) + { + throw new NotImplementedException(); + } + + queryModel.ResultOperators.Add(new NonAggregatingGroupBy((GroupResultOperator) subQueryExpression.QueryModel.ResultOperators[0])); + queryModel.ResultOperators.Add(clientSideSelect); + } + + protected void CopyFromClauseData(FromClauseBase source, FromClauseBase destination) + { + destination.FromExpression = source.FromExpression; + destination.ItemName = source.ItemName; + destination.ItemType = source.ItemType; + } + + private static bool IsNonAggregatingGroupBy(QueryModel queryModel) + { + return new GroupByAggregateDetectionVisitor().Visit(queryModel.SelectClause.Selector) == false; + } + } + + internal class NonAggregatingGroupBySelectRewriter : NhExpressionTreeVisitor + { + private ParameterExpression _inputParameter; + private IQuerySource _querySource; + + public LambdaExpression Visit(Expression clause, System.Type resultType, IQuerySource querySource) + { + _inputParameter = Expression.Parameter(resultType, "inputParameter"); + _querySource = querySource; + + return Expression.Lambda(VisitExpression(clause), _inputParameter); + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + if (expression.ReferencedQuerySource == _querySource) + { + return _inputParameter; + } + + return expression; + } + } + + internal class ClientSideSelect : ClientSideTransformOperator + { + public LambdaExpression SelectClause { get; private set; } + + public ClientSideSelect(LambdaExpression selectClause) + { + SelectClause = selectClause; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/AggregatingGroupJoinRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/AggregatingGroupJoinRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/AggregatingGroupJoinRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Linq; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; + +namespace NHibernate.Linq.GroupJoin +{ + /// <summary> + /// An AggregatingGroupJoin is a query such as: + /// + /// from c in db.Customers + /// join o in db.Orders on c.CustomerId equals o.Customer.CustomerId into ords + /// join e in db.Employees on c.Address.City equals e.Address.City into emps + /// select new { c.ContactName, ords = ords.Count(), emps = emps.Count() }; + /// + /// where the results of the joins are being fully aggregated and hence do not create any form of hierarchy. + /// This class takes such expressions and turns them into this form: + /// + /// from c in db.Customers + /// select new + /// { + /// c.ContactName, + /// ords = (from o2 in db.Orders where o2.Customer.CustomerId == c.CustomerId select o2).Count(), + /// emps = (from e2 in db.Employees where e2.Address.City == c.Address.City select e2).Count() + /// }; + /// + /// </summary> + public class AggregatingGroupJoinRewriter + { + private AggregatingGroupJoinRewriter() + { + } + + public static void ReWrite(QueryModel model) + { + // firstly, get the group join clauses + var groupJoin = model.BodyClauses.Where(bc => bc is GroupJoinClause).Cast<GroupJoinClause>(); + + if (groupJoin.Count() == 0) + { + // No group join here.. + return; + } + + // Now walk the tree to decide which groupings are fully aggregated (and can hence be done in hql) + var aggregateDetectorResults = IsAggregatingGroupJoin(model, groupJoin); + + if (aggregateDetectorResults.AggregatingClauses.Count > 0) + { + // Re-write the select expression + model.SelectClause.TransformExpressions(s => GroupJoinSelectClauseRewriter.ReWrite(s, aggregateDetectorResults)); + + // Remove the aggregating group joins + foreach (GroupJoinClause aggregatingGroupJoin in aggregateDetectorResults.AggregatingClauses) + { + model.BodyClauses.Remove(aggregatingGroupJoin); + } + } + } + + private static IsAggregatingResults IsAggregatingGroupJoin(QueryModel model, IEnumerable<GroupJoinClause> clause) + { + return GroupJoinAggregateDetectionVisitor.Visit(clause, model.SelectClause.Selector); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinAggregateDetectionVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinAggregateDetectionVisitor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinAggregateDetectionVisitor.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.GroupJoin +{ + internal class GroupJoinAggregateDetectionVisitor : NhExpressionTreeVisitor + { + private readonly HashSet<GroupJoinClause> _groupJoinClauses; + private readonly StackFlag _inAggregate = new StackFlag(); + private readonly StackFlag _parentExpressionProcessed = new StackFlag(); + + private readonly List<Expression> _nonAggregatingExpressions = new List<Expression>(); + private readonly List<GroupJoinClause> _nonAggregatingGroupJoins = new List<GroupJoinClause>(); + private readonly List<GroupJoinClause> _aggregatingGroupJoins = new List<GroupJoinClause>(); + + private GroupJoinAggregateDetectionVisitor(IEnumerable<GroupJoinClause> groupJoinClause) + { + _groupJoinClauses = new HashSet<GroupJoinClause>(groupJoinClause); + } + + public static IsAggregatingResults Visit(IEnumerable<GroupJoinClause> groupJoinClause, Expression selectExpression) + { + var visitor = new GroupJoinAggregateDetectionVisitor(groupJoinClause); + + visitor.VisitExpression(selectExpression); + + return new IsAggregatingResults { NonAggregatingClauses = visitor._nonAggregatingGroupJoins, AggregatingClauses = visitor._aggregatingGroupJoins, NonAggregatingExpressions = visitor._nonAggregatingExpressions }; + } + + protected override Expression VisitSubQueryExpression(SubQueryExpression expression) + { + VisitExpression(expression.QueryModel.SelectClause.Selector); + return expression; + } + + protected override Expression VisitNhAggregate(NhAggregatedExpression expression) + { + using (_inAggregate.SetFlag()) + { + return base.VisitNhAggregate(expression); + } + } + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + if (_inAggregate.FlagIsFalse && _parentExpressionProcessed.FlagIsFalse) + { + _nonAggregatingExpressions.Add(expression); + } + + using (_parentExpressionProcessed.SetFlag()) + { + return base.VisitMemberExpression(expression); + } + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + var fromClause = (FromClauseBase) expression.ReferencedQuerySource; + + if (fromClause.FromExpression is QuerySourceReferenceExpression) + { + var querySourceReference = (QuerySourceReferenceExpression) fromClause.FromExpression; + + if (_groupJoinClauses.Contains(querySourceReference.ReferencedQuerySource as GroupJoinClause)) + { + if (_inAggregate.FlagIsFalse) + { + _nonAggregatingGroupJoins.Add((GroupJoinClause) querySourceReference.ReferencedQuerySource); + } + else + { + _aggregatingGroupJoins.Add((GroupJoinClause) querySourceReference.ReferencedQuerySource); + } + } + } + + return base.VisitQuerySourceReferenceExpression(expression); + } + + internal class StackFlag + { + public bool FlagIsTrue { get; private set; } + + public bool FlagIsFalse { get { return !FlagIsTrue; } } + + public IDisposable SetFlag() + { + return new StackFlagDisposable(this); + } + + internal class StackFlagDisposable : IDisposable + { + private readonly StackFlag _parent; + private readonly bool _old; + + public StackFlagDisposable(StackFlag parent) + { + _parent = parent; + _old = parent.FlagIsTrue; + parent.FlagIsTrue = true; + } + + public void Dispose() + { + _parent.FlagIsTrue = _old; + } + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinSelectClauseRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinSelectClauseRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/GroupJoinSelectClauseRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,52 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.GroupJoin +{ + public class GroupJoinSelectClauseRewriter : NhExpressionTreeVisitor + { + private readonly IsAggregatingResults _results; + + public static Expression ReWrite(Expression expression, IsAggregatingResults results) + { + return new GroupJoinSelectClauseRewriter(results).VisitExpression(expression); + } + + private GroupJoinSelectClauseRewriter(IsAggregatingResults results) + { + _results = results; + } + + protected override Expression VisitSubQueryExpression(SubQueryExpression expression) + { + // If the sub query's main (and only) from clause is one of our aggregating group bys, then swap it + GroupJoinClause groupJoin = LocateGroupJoinQuerySource(expression.QueryModel); + + if (groupJoin != null) + { + Expression innerSelector = new SwapQuerySourceVisitor(groupJoin.JoinClause, expression.QueryModel.MainFromClause). + Swap(groupJoin.JoinClause.InnerKeySelector); + + expression.QueryModel.MainFromClause.FromExpression = groupJoin.JoinClause.InnerSequence; + + + // TODO - this only works if the key selectors are not composite. Needs improvement... + expression.QueryModel.BodyClauses.Add(new WhereClause(Expression.Equal(innerSelector, groupJoin.JoinClause.OuterKeySelector))); + } + + return expression; + } + + private GroupJoinClause LocateGroupJoinQuerySource(QueryModel model) + { + if (model.BodyClauses.Count > 0) + { + return null; + } + return new LocateGroupJoinQuerySource(_results).Detect(model.MainFromClause.FromExpression); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/IsAggregatingResults.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/IsAggregatingResults.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/IsAggregatingResults.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using Remotion.Data.Linq.Clauses; + +namespace NHibernate.Linq.GroupJoin +{ + public class IsAggregatingResults + { + public List<GroupJoinClause> NonAggregatingClauses { get; set; } + public List<GroupJoinClause> AggregatingClauses { get; set; } + public List<Expression> NonAggregatingExpressions { get; set; } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/LocateGroupJoinQuerySource.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/LocateGroupJoinQuerySource.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/LocateGroupJoinQuerySource.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,34 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.GroupJoin +{ + public class LocateGroupJoinQuerySource : NhExpressionTreeVisitor + { + private readonly IsAggregatingResults _results; + private GroupJoinClause _groupJoin; + + public LocateGroupJoinQuerySource(IsAggregatingResults results) + { + _results = results; + } + + public GroupJoinClause Detect(Expression expression) + { + VisitExpression(expression); + return _groupJoin; + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + if (_results.AggregatingClauses.Contains(expression.ReferencedQuerySource as GroupJoinClause)) + { + _groupJoin = expression.ReferencedQuerySource as GroupJoinClause; + } + + return base.VisitQuerySourceReferenceExpression(expression); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Linq/GroupJoin/NonAggregatingGroupJoinRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/GroupJoin/NonAggregatingGroupJoinRewriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/GroupJoin/NonAggregatingGroupJoinRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Linq.GroupJoin; +using Remotion.Data.Linq; +using Remotion.Data.Linq.Clauses; +using Remotion.Data.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.Visitors +{ + public class NonAggregatingGroupJoinRewriter + { + private readonly QueryModel _model; + private readonly IEnumerable<GroupJoinClause> _groupJoinClauses; + private QuerySourceUsageLocator _locator; + + private NonAggregatingGroupJoinRewriter(QueryModel model, IEnumerable<GroupJoinClause> groupJoinClauses) + { + _model = model; + _groupJoinClauses = groupJoinClauses; + } + + public static void ReWrite(QueryModel model) + { + // firstly, get the group join clauses + var groupJoinClauses = model.BodyClauses.Where(bc => bc is GroupJoinClause).Cast<GroupJoinClause>(); + + if (groupJoinClauses.Count() == 0) + { + // No group join here.. + return; + } + + var rewriter = new NonAggregatingGroupJoinRewriter(model, groupJoinClauses); + + rewriter.ReWrite(); + } + + private void ReWrite() + { + var aggregateDetectorResults = GetGroupJoinInformation(_groupJoinClauses); + + foreach (var nonAggregatingJoin in aggregateDetectorResults.NonAggregatingClauses) + { + // Group joins get processed (currently) in one of three ways. + // Option 1: results of group join are not further referenced outside of the final projection. + // In this case, replace the group join with a join, and add a client-side grouping operator + // to build the correct hierarchy + // + // Option 2: Results of group join are only used in a plain "from" expression, such as: + // from o in db.Orders + // from p in db.Products + // join d in db.OrderLines + // on new {o.OrderId, p.ProductId} equals new {d.Order.OrderId, d.Product.ProductId} + // into details + // from d in details + // select new {o.OrderId, p.ProductId, d.UnitPrice}; + // In this case, simply change the group join to a join; the results of the grouping are being + // removed by the subsequent "from" + // + // Option 3: Results of group join are only used in a "from ... DefaultIfEmpty()" construction, such as: + // from o in dc.Orders + // join v in dc.Vendors on o.VendorId equals v.Id into ov + // from x in ov.DefaultIfEmpty() + // join s in dc.Status on o.StatusId equals s.Id into os + // from y in os.DefaultIfEmpty() + // select new { o.OrderNumber, x.VendorName, y.StatusName } + // This is used to repesent an outer join, and again the "from" is removing the hierarchy. So + // simply change the group join to an outer join + + _locator = new QuerySourceUsageLocator(nonAggregatingJoin); + + foreach (var bodyClause in _model.BodyClauses) + { + _locator.Search(bodyClause); + } + + if (IsHierarchicalJoin(nonAggregatingJoin)) + { + } + else if (IsFlattenedJoin(nonAggregatingJoin)) + { + ProcessFlattenedJoin(nonAggregatingJoin); + } + else if (IsOuterJoin(nonAggregatingJoin)) + { + + } + else + { + // Wonder what this is? + throw new NotSupportedException(); + } + } + } + + private void ProcessFlattenedJoin(GroupJoinClause nonAggregatingJoin) + { + // Need to: + // 1. Remove the group join and replace it with a join + // 2. Remove the corresponding "from" clause (the thing that was doing the flattening) + // 3. Rewrite the selector to reference the "join" rather than the "from" clause + SwapClause(nonAggregatingJoin, nonAggregatingJoin.JoinClause); + + // TODO - don't like use of _locator here; would rather we got this passed in. Ditto on next line (esp. the cast) + _model.BodyClauses.Remove(_locator.Clauses[0]); + + var querySourceSwapper = new SwapQuerySourceVisitor((IQuerySource) _locator.Clauses[0], nonAggregatingJoin.JoinClause); + _model.SelectClause.TransformExpressions(querySourceSwapper.Swap); + } + + // TODO - store the indexes of the join clauses when we find them, then can remove this loop + private void SwapClause(IBodyClause oldClause, IBodyClause newClause) + { + for (int i = 0; i < _model.BodyClauses.Count; i++) + { + if (_model.BodyClauses[i] == oldClause) + { + _model.BodyClauses.RemoveAt(i); + _model.BodyClauses.Insert(i, newClause); + } + } + } + + private bool IsOuterJoin(GroupJoinClause nonAggregatingJoin) + { + return false; + } + + private bool IsFlattenedJoin(GroupJoinClause nonAggregatingJoin) + { + if (_locator.Clauses.Count == 1) + { + var from = _locator.Clauses[0] as AdditionalFromClause; + + if (from != null) + { + return true; + } + } + + return false; + } + + private bool IsHierarchicalJoin(GroupJoinClause nonAggregatingJoin) + { + return _locator.Clauses.Count == 0; + } + + // TODO - rename this and share with the AggregatingGroupJoinRewriter + private IsAggregatingResults GetGroupJoinInformation(IEnumerable<GroupJoinClause> clause) + { + return GroupJoinAggregateDetectionVisitor.Visit(clause, _model.SelectClause.Selector); + } + + } + + internal class QuerySourceUsageLocator : NhExpressionTreeVisitor + { + private readonly IQuerySource _querySource; + private bool _references; + private readonly List<IBodyClause> _clauses = new List<IBodyClause>(); + + public QuerySourceUsageLocator(IQuerySource querySource) + { + _querySource = querySource; + } + + public IList<IBodyClause> Clauses + { + get { return _clauses.AsReadOnly(); } + } + + public void Search(IBodyClause clause) + { + _references = false; + + clause.TransformExpressions(ExpressionSearcher); + + if (_references) + { + _clauses.Add(clause); + } + } + + private Expression ExpressionSearcher(Expression arg) + { + VisitExpression(arg); + return arg; + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { + if (expression.ReferencedQuerySource == _querySource) + { + _references = true; + } + + return expression; + } + } +} \ No newline at end of file Deleted: trunk/nhibernate/src/NHibernate/Linq/NhNewExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhNewExpression.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Linq/NhNewExpression.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq.Expressions; -using NHibernate.Linq.ReWriters; - -namespace NHibernate.Linq -{ - public class NhNewExpression : Expression - { - private readonly ReadOnlyCollection<string> _members; - private readonly ReadOnlyCollection<Expression> _arguments; - - public NhNewExpression(IList<string> members, IList<Expression> arguments) - : base((ExpressionType)NhExpressionType.New, typeof(object)) - { - _members = new ReadOnlyCollection<string>(members); - _arguments = new ReadOnlyCollection<Expression>(arguments); - } - - public ReadOnlyCollection<Expression> Arguments - { - get { return _arguments; } - } - - public ReadOnlyCollection<string> Members - { - get { return _members; } - } - } -} Modified: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -47,7 +47,7 @@ return new NhQueryable<T>(this, expression); } - void SetParameters(IQuery query, IDictionary<string, object> parameters) + static void SetParameters(IQuery query, IDictionary<string, object> parameters) { foreach (var parameterName in query.NamedParameters) { Deleted: trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupByRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupByRewriter.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupByRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -1,69 +0,0 @@ -using System; -using System.Linq; -using NHibernate.Linq.Visitors; -using Remotion.Data.Linq; -using Remotion.Data.Linq.Clauses; -using Remotion.Data.Linq.Clauses.Expressions; -using Remotion.Data.Linq.Clauses.ResultOperators; - -namespace NHibernate.Linq.ReWriters -{ - public class AggregatingGroupByRewriter - { - public void ReWrite(QueryModel queryModel) - { - var subQueryExpression = queryModel.MainFromClause.FromExpression as SubQueryExpression; - - if ((subQueryExpression != null) && - (subQueryExpression.QueryModel.ResultOperators.Count() == 1) && - (subQueryExpression.QueryModel.ResultOperators[0] is GroupResultOperator) && - (IsAggregatingGroupBy(queryModel))) - { - FlattenSubQuery(subQueryExpression, queryModel.MainFromClause, queryModel); - } - } - - private static bool IsAggregatingGroupBy(QueryModel queryModel) - { - return new GroupByAggregateDetectionVisitor().Visit(queryModel.SelectClause.Selector); - } - - private void FlattenSubQuery(SubQueryExpression subQueryExpression, FromClauseBase fromClause, - QueryModel queryModel) - { - // Move the result operator up - if (queryModel.ResultOperators.Count != 0) - { - throw new NotImplementedException(); - } - - var groupBy = (GroupResultOperator) subQueryExpression.QueryModel.ResultOperators[0]; - - // Replace the outer select clause... - queryModel.SelectClause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryExpression.QueryModel)); - - queryModel.SelectClause.TransformExpressions( - s => - new SwapQuerySourceVisitor(queryModel.MainFromClause, subQueryExpression.QueryModel.MainFromClause).Swap - (s)); - - - MainFromClause innerMainFromClause = subQueryExpression.QueryModel.MainFromClause; - CopyFromClauseData(innerMainFromClause, fromClause); - - foreach (var bodyClause in subQueryExpression.QueryModel.BodyClauses) - { - queryModel.BodyClauses.Add(bodyClause); - } - - queryModel.ResultOperators.Add(groupBy); - } - - protected void CopyFromClauseData(FromClauseBase source, FromClauseBase destination) - { - destination.FromExpression = source.FromExpression; - destination.ItemName = source.ItemName; - destination.ItemType = source.ItemType; - } - } -} \ No newline at end of file Deleted: trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupJoinRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupJoinRewriter.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/AggregatingGroupJoinRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -1,322 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using NHibernate.Linq.Visitors; -using Remotion.Data.Linq; -using Remotion.Data.Linq.Clauses; -using Remotion.Data.Linq.Clauses.Expressions; - -namespace NHibernate.Linq.ReWriters -{ - public class AggregatingGroupJoinRewriter - { - public void ReWrite(QueryModel model) - { - // We want to take queries like this: - - //var q = - // from c in db.Customers - // join o in db.Orders on c.CustomerId equals o.Customer.CustomerId into ords - // join e in db.Employees on c.Address.City equals e.Address.City into emps - // select new { c.ContactName, ords = ords.Count(), emps = emps.Count() }; - - // and turn them into this: - - //var q = - // from c in db.Customers - // select new - // { - // c.ContactName, - // ords = (from o2 in db.Orders where o2.Customer.CustomerId == c.CustomerId select o2).Count(), - // emps = (from e2 in db.Employees where e2.Address.City == c.Address.City select e2).Count() - // }; - - // so spot a group join where every use of the grouping in the selector is an aggregate - - // firstly, get the group join clauses - var groupJoin = model.BodyClauses.Where(bc => bc is GroupJoinClause).Cast<GroupJoinClause>(); - - if (groupJoin.Count() == 0) - { - // No group join here.. - return; - } - - // Now walk the tree to decide which groupings are fully aggregated (and can hence be done in hql) - var aggregateDetectorResults = IsAggregatingGroupJoin(model, groupJoin); - - if (aggregateDetectorResults.AggregatingClauses.Count > 0) - { - // Re-write the select expression - model.SelectClause.TransformExpressions(s => GroupJoinSelectClauseRewriter.ReWrite(s, aggregateDetectorResults)); - - // Remove the aggregating group joins - foreach (GroupJoinClause aggregatingGroupJoin in aggregateDetectorResults.AggregatingClauses) - { - model.BodyClauses.Remove(aggregatingGroupJoin); - } - } - } - - private static IsAggregatingResults IsAggregatingGroupJoin(QueryModel model, IEnumerable<GroupJoinClause> clause) - { - return new GroupJoinAggregateDetectionVisitor(clause).Visit(model.SelectClause.Selector); - } - } - - public class GroupJoinSelectClauseRewriter : NhExpressionTreeVisitor - { - private readonly IsAggregatingResults _results; - - public static Expression ReWrite(Expression expression, IsAggregatingResults results) - { - return new GroupJoinSelectClauseRewriter(results).VisitExpression(expression); - } - - private GroupJoinSelectClauseRewriter(IsAggregatingResults results) - { - _results = results; - } - - protected override Expression VisitSubQueryExpression(SubQueryExpression expression) - { - // If the sub queries main (and only) from clause is one of our aggregating group bys, then swap it - GroupJoinClause groupJoin = LocateGroupJoinQuerySource(expression.QueryModel); - - if (groupJoin != null) - { - Expression innerSelector = new SwapQuerySourceVisitor(groupJoin.JoinClause, expression.QueryModel.MainFromClause). - Swap(groupJoin.JoinClause.InnerKeySelector); - - expression.QueryModel.MainFromClause.FromExpression = groupJoin.JoinClause.InnerSequence; - - - // TODO - this only works if the key selectors are not composite. Needs improvement... - expression.QueryModel.BodyClauses.Add(new WhereClause(Expression.Equal(innerSelector, groupJoin.JoinClause.OuterKeySelector))); - } - - return expression; - } - - private GroupJoinClause LocateGroupJoinQuerySource(QueryModel model) - { - if (model.BodyClauses.Count > 0) - { - return null; - } - return new LocateGroupJoinQuerySource(_results).Detect(model.MainFromClause.FromExpression); - } - } - - public class SwapQuerySourceVisitor : NhExpressionTreeVisitor - { - private readonly IQuerySource _oldClause; - private readonly IQuerySource _newClause; - - public SwapQuerySourceVisitor(IQuerySource oldClause, IQuerySource newClause) - { - _oldClause = oldClause; - _newClause = newClause; - } - - public Expression Swap(Expression expression) - { - return VisitExpression(expression); - } - - protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) - { - if (expression.ReferencedQuerySource == _oldClause) - { - return new QuerySourceReferenceExpression(_newClause); - } - - // TODO - really don't like this drill down approach. Feels fragile - var mainFromClause = expression.ReferencedQuerySource as MainFromClause; - - if (mainFromClause != null) - { - mainFromClause.FromExpression = VisitExpression(mainFromClause.FromExpression); - } - - return expression; - } - - protected override Expression VisitSubQueryExpression(SubQueryExpression expression) - { - expression.QueryModel.TransformExpressions(VisitExpression); - return base.VisitSubQueryExpression(expression); - } - } - - public class LocateGroupJoinQuerySource : NhExpressionTreeVisitor - { - private readonly IsAggregatingResults _results; - private GroupJoinClause _groupJoin; - - public LocateGroupJoinQuerySource(IsAggregatingResults results) - { - _results = results; - } - - public GroupJoinClause Detect(Expression expression) - { - VisitExpression(expression); - return _groupJoin; - } - - protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) - { - if (_results.AggregatingClauses.Contains(expression.ReferencedQuerySource as GroupJoinClause)) - { - _groupJoin = expression.ReferencedQuerySource as GroupJoinClause; - } - - return base.VisitQuerySourceReferenceExpression(expression); - } - } - - public class IsAggregatingResults - { - public List<GroupJoinClause> NonAggregatingClauses { get; set; } - public List<GroupJoinClause> AggregatingClauses { get; set; } - public List<Expression> NonAggregatingExpressions { get; set; } - } - - internal class GroupJoinAggregateDetectionVisitor : NhExpressionTreeVisitor - { - private readonly HashSet<GroupJoinClause> _groupJoinClauses; - private readonly StackFlag _inAggregate = new StackFlag(); - private readonly StackFlag _parentExpressionProcessed = new StackFlag(); - - private readonly List<Expression> _nonAggregatingExpressions = new List<Expression>(); - private readonly List<GroupJoinClause> _nonAggregatingGroupJoins = new List<GroupJoinClause>(); - private readonly List<GroupJoinClause> _aggregatingGroupJoins = new List<GroupJoinClause>(); - - public GroupJoinAggregateDetectionVisitor(IEnumerable<GroupJoinClause> groupJoinClause) - { - _groupJoinClauses = new HashSet<GroupJoinClause>(groupJoinClause); - } - - public IsAggregatingResults Visit(Expression expression) - { - VisitExpression(expression); - - return new IsAggregatingResults { NonAggregatingClauses = _nonAggregatingGroupJoins, AggregatingClauses = _aggregatingGroupJoins, NonAggregatingExpressions = _nonAggregatingExpressions }; - } - - protected override Expression VisitSubQueryExpression(SubQueryExpression expression) - { - VisitExpression(expression.QueryModel.SelectClause.Selector); - return expression; - } - - protected override Expression VisitNhAverage(NhAverageExpression expression) - { - using (_inAggregate.SetFlag()) - { - return base.VisitNhAverage(expression); - } - } - - protected override Expression VisitNhCount(NhCountExpression expression) - { - using (_inAggregate.SetFlag()) - { - return base.VisitNhCount(expression); - } - } - - protected override Expression VisitNhMax(NhMaxExpression expression) - { - using (_inAggregate.SetFlag()) - { - return base.VisitNhMax(expression); - } - } - - protected override Expression VisitNhMin(NhMinExpression expression) - { - using (_inAggregate.SetFlag()) - { - return base.VisitNhMin(expression); - } - } - - protected override Expression VisitNhSum(NhSumExpression expression) - { - using (_inAggregate.SetFlag()) - { - return base.VisitNhSum(expression); - } - } - - protected override Expression VisitMemberExpression(MemberExpression expression) - { - if (_inAggregate.FlagIsFalse && _parentExpressionProcessed.FlagIsFalse) - { - _nonAggregatingExpressions.Add(expression); - } - - using (_parentExpressionProcessed.SetFlag()) - { - return base.VisitMemberExpression(expression); - } - } - - protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) - { - var fromClause = (FromClauseBase) expression.ReferencedQuerySource; - - if (fromClause.FromExpression is QuerySourceReferenceExpression) - { - var querySourceReference = (QuerySourceReferenceExpression) fromClause.FromExpression; - - if (_groupJoinClauses.Contains(querySourceReference.ReferencedQuerySource as GroupJoinClause)) - { - if (_inAggregate.FlagIsFalse) - { - _nonAggregatingGroupJoins.Add((GroupJoinClause) querySourceReference.ReferencedQuerySource); - } - else - { - _aggregatingGroupJoins.Add((GroupJoinClause) querySourceReference.ReferencedQuerySource); - } - } - } - - return base.VisitQuerySourceReferenceExpression(expression); - } - - internal class StackFlag - { - public bool FlagIsTrue { get; private set; } - - public bool FlagIsFalse { get { return !FlagIsTrue; } } - - public IDisposable SetFlag() - { - return new StackFlagDisposable(this); - } - - internal class StackFlagDisposable : IDisposable - { - private readonly StackFlag _parent; - private readonly bool _old; - - public StackFlagDisposable(StackFlag parent) - { - _parent = parent; - _old = parent.FlagIsTrue; - parent.FlagIsTrue = true; - } - - public void Dispose() - { - _parent.FlagIsTrue = _old; - } - } - } - } -} \ No newline at end of file Deleted: trunk/nhibernate/src/NHibernate/Linq/ReWriters/GroupBySelectClauseRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/GroupBySelectClauseRewriter.cs 2009-11-04 10:55:10 UTC (rev 4818) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/GroupBySelectClauseRewriter.cs 2009-11-05 16:43:43 UTC (rev 4819) @@ -1,203 +0,0 @@ -using System; -using System.Linq.Expressions; -using NHibernate.Linq.Visitors; -using Remotion.Data.Linq; -using Remotion.Data.Linq.Clauses; -using Remotion.Data.Linq.Clauses.Expressions; -using Remotion.Data.Linq.Clauses.ResultOperators; - -namespace NHibernate.Linq.ReWriters -{ - internal class GroupBySelectClauseRewriter : NhExpressionTreeVisitor - { - public static Expression ReWrite(Expression expression, ... [truncated message content] |
From: <ric...@us...> - 2009-11-04 10:55:22
|
Revision: 4818 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4818&view=rev Author: ricbrown Date: 2009-11-04 10:55:10 +0000 (Wed, 04 Nov 2009) Log Message: ----------- Added QueryOver<T> constructor using alias. Protected internally used constructors. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-03 16:11:25 UTC (rev 4817) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-04 10:55:10 UTC (rev 4818) @@ -25,13 +25,20 @@ _criteria = _impl; } - public QueryOver(CriteriaImpl impl) + public QueryOver(Expression<Func<T>> alias) { + string aliasPath = ExpressionProcessor.FindMemberExpression(alias.Body); + _impl = new CriteriaImpl(typeof(T), aliasPath, null); + _criteria = _impl; + } + + protected internal QueryOver(CriteriaImpl impl) + { _impl = impl; _criteria = impl; } - public QueryOver(CriteriaImpl rootImpl, ICriteria criteria) + protected internal QueryOver(CriteriaImpl rootImpl, ICriteria criteria) { _impl = rootImpl; _criteria = criteria; Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs 2009-11-03 16:11:25 UTC (rev 4817) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs 2009-11-04 10:55:10 UTC (rev 4818) @@ -32,13 +32,17 @@ protected IQueryOver<T> CreateTestQueryOver<T>() { - return new QueryOver<T>(new CriteriaImpl(typeof(T), null)); + return (IQueryOver<T>) + typeof(QueryOver<T>).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new System.Type[] { typeof(CriteriaImpl) }, null) + .Invoke(new object[] { new CriteriaImpl(typeof(T), null) }); } protected IQueryOver<T> CreateTestQueryOver<T>(Expression<Func<object>> alias) { string aliasContainer = ExpressionProcessor.FindMemberExpression(alias.Body); - return new QueryOver<T>(new CriteriaImpl(typeof(T), aliasContainer, null)); + return (IQueryOver<T>) + typeof(QueryOver<T>).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new System.Type[] { typeof(CriteriaImpl) }, null) + .Invoke(new object[] { new CriteriaImpl(typeof(T), aliasContainer, null) }); } protected void AssertCriteriaAreEqual(ICriteria expected, ICriteria actual) @@ -56,6 +60,20 @@ AssertObjectsAreEqual(expected, ((QueryOver<T>)actual).UnderlyingCriteria); } + protected void AssertCriteriaAreEqual<T>(DetachedCriteria expected, QueryOver<T> actual) + { + ICriteria criteria = actual.UnderlyingCriteria; + CriteriaImpl criteriaImpl = (CriteriaImpl) + typeof(QueryOver<T>).GetField("_impl", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(actual); + + DetachedCriteria actualDetached = (DetachedCriteria) + typeof(DetachedCriteria).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new System.Type[] { typeof(CriteriaImpl), typeof(ICriteria) }, null) + .Invoke(new object[] { criteriaImpl, criteria }); + + AssertObjectsAreEqual(expected, actualDetached); + } + private void AssertDictionariesAreEqual(IDictionary expected, IDictionary actual) { Assert.AreEqual(expected.Keys.Count, actual.Keys.Count, _fieldPath.Peek() + ".Count"); Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-03 16:11:25 UTC (rev 4817) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-04 10:55:10 UTC (rev 4818) @@ -447,6 +447,21 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void DetachedQueryOver() + { + DetachedCriteria expected = + DetachedCriteria.For<Person>("personAlias") + .Add(Restrictions.Eq("personAlias.Name", "test name")); + + Person personAlias = null; + QueryOver<Person> actual = + new QueryOver<Person>(() => personAlias) + .Where(() => personAlias.Name == "test name"); + + AssertCriteriaAreEqual(expected, actual); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-03 16:11:32
|
Revision: 4817 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4817&view=rev Author: ricbrown Date: 2009-11-03 16:11:25 +0000 (Tue, 03 Nov 2009) Log Message: ----------- Added overloads for IQueryOver.JoinQueryOver and IQueryOver.Join using aliases. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-10-31 18:34:16 UTC (rev 4816) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-03 16:11:25 UTC (rev 4817) @@ -161,6 +161,13 @@ ExpressionProcessor.FindMemberExpression(path.Body))); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body))); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) { return new QueryOver<U>(_impl, @@ -169,6 +176,14 @@ ExpressionProcessor.FindMemberExpression(alias.Body))); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body))); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, JoinType joinType) { return new QueryOver<U>(_impl, @@ -177,6 +192,14 @@ joinType)); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + joinType)); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias, JoinType joinType) { return new QueryOver<U>(_impl, @@ -186,6 +209,15 @@ joinType)); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body), + joinType)); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) { return new QueryOver<U>(_impl, @@ -194,6 +226,14 @@ ExpressionProcessor.FindMemberExpression(alias.Body))); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body))); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { return new QueryOver<U>(_impl, @@ -201,6 +241,13 @@ ExpressionProcessor.FindMemberExpression(path.Body))); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body))); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { return new QueryOver<U>(_impl, @@ -210,6 +257,15 @@ joinType)); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body), + joinType)); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, JoinType joinType) { return new QueryOver<U>(_impl, @@ -218,6 +274,14 @@ joinType)); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType) + { + return new QueryOver<U>(_impl, + _criteria.CreateCriteria( + ExpressionProcessor.FindMemberExpression(path.Body), + joinType)); + } + public QueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias) { return AddAlias( @@ -226,6 +290,14 @@ JoinType.InnerJoin); } + public QueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias) + { + return AddAlias( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body), + JoinType.InnerJoin); + } + public QueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) { return AddAlias( @@ -234,6 +306,14 @@ joinType); } + public QueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + { + return AddAlias( + ExpressionProcessor.FindMemberExpression(path.Body), + ExpressionProcessor.FindMemberExpression(alias.Body), + joinType); + } + public QueryOverJoinBuilder<T> Inner { get { return new QueryOverJoinBuilder<T>(this, JoinType.InnerJoin); } @@ -394,33 +474,63 @@ IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, U>> path) { return JoinQueryOver(path); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<U>> path) + { return JoinQueryOver(path); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) { return JoinQueryOver(path, alias); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { return JoinQueryOver(path, alias); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, U>> path, JoinType joinType) { return JoinQueryOver(path, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType) + { return JoinQueryOver(path, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias, JoinType joinType) { return JoinQueryOver(path, alias, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType) + { return JoinQueryOver(path, alias, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { return JoinQueryOver(path); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { return JoinQueryOver(path); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) { return JoinQueryOver(path, alias); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { return JoinQueryOver(path, alias); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, JoinType joinType) { return JoinQueryOver(path, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType) + { return JoinQueryOver(path, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { return JoinQueryOver(path, alias, joinType); } + IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) + { return JoinQueryOver(path, alias, joinType); } + IQueryOver<T> IQueryOver<T>.Join(Expression<Func<T, object>> path, Expression<Func<object>> alias) { return Join(path, alias); } + IQueryOver<T> IQueryOver<T>.Join(Expression<Func<object>> path, Expression<Func<object>> alias) + { return Join(path, alias); } + IQueryOver<T> IQueryOver<T>.Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) { return Join(path, alias, joinType); } + IQueryOver<T> IQueryOver<T>.Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + { return Join(path, alias, joinType); } + IQueryOverJoinBuilder<T> IQueryOver<T>.Inner { get { return new IQueryOverJoinBuilder<T>(this, JoinType.InnerJoin); } } Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-10-31 18:34:16 UTC (rev 4816) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOverJoinBuilder.cs 2009-11-03 16:11:25 UTC (rev 4817) @@ -18,21 +18,41 @@ return root.JoinQueryOver<U>(path, joinType); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) { return root.JoinQueryOver<U>(path, alias, joinType); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { return root.JoinQueryOver<U>(path, joinType); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) { return root.JoinQueryOver<U>(path, alias, joinType); } + public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + } public class IQueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<IQueryOver<T>, T> @@ -44,21 +64,41 @@ return root.JoinQueryOver<U>(path, joinType); } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) { return root.JoinQueryOver<U>(path, alias, joinType); } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { return root.JoinQueryOver<U>(path, joinType); } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + { + return root.JoinQueryOver<U>(path, joinType); + } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) { return root.JoinQueryOver<U>(path, alias, joinType); } + public IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + { + return root.JoinQueryOver<U>(path, alias, joinType); + } + } public class QueryOverJoinBuilderBase<R, T> where R : IQueryOver<T> @@ -78,6 +118,11 @@ return (R)root.Join(path, alias, joinType); } + public R Join(Expression<Func<object>> path, Expression<Func<object>> alias) + { + return (R)root.Join(path, alias, joinType); + } + } } Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-10-31 18:34:16 UTC (rev 4816) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-03 16:11:25 UTC (rev 4817) @@ -155,7 +155,7 @@ IQueryOverLockBuilder<T> Lock(Expression<Func<object>> alias); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// </summary> /// <typeparam name="U">Type of sub-criteria</typeparam> /// <param name="path">Lambda expression returning association path</param> @@ -163,35 +163,71 @@ IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// </summary> /// <typeparam name="U">Type of sub-criteria</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// </summary> + /// <typeparam name="U">Type of sub-criteria</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// </summary> /// <typeparam name="U">Type of sub-criteria</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// </summary> + /// <typeparam name="U">Type of sub-criteria</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="joinType">Type of join</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, JoinType joinType); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// </summary> /// <typeparam name="U">Type of sub-criteria</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <param name="joinType">Type of join</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// </summary> + /// <typeparam name="U">Type of sub-criteria</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <param name="joinType">Type of join</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias, JoinType joinType); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// </summary> + /// <typeparam name="U">Type of sub-criteria</typeparam> + /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> + /// <param name="joinType">Type of join</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// specifying a collection for the join. /// </summary> /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> @@ -200,37 +236,77 @@ IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// specifying a collection for the join. /// </summary> /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// specifying a collection for the join. + /// </summary> + /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// specifying a collection for the join. /// </summary> /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// specifying a collection for the join. + /// </summary> + /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="joinType">Type of join</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, JoinType joinType); /// <summary> - /// Creates a new NHibernate.ICriteria<T>, "rooted" at the associated entity + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity /// specifying a collection for the join. /// </summary> /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> /// <param name="path">Lambda expression returning association path</param> + /// <param name="joinType">Type of join</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType); + + /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// specifying a collection for the join. + /// </summary> + /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> + /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> /// <param name="joinType">Type of join</param> /// <returns>The created "sub criteria"</returns> IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType); /// <summary> + /// Creates a new NHibernate.ICriteria<U>, "rooted" at the associated entity + /// specifying a collection for the join. + /// </summary> + /// <typeparam name="U">Type of sub-criteria (type of the collection)</typeparam> + /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> + /// <param name="joinType">Type of join</param> + /// <returns>The created "sub criteria"</returns> + IQueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType); + + /// <summary> /// Join an association, assigning an alias to the joined entity /// </summary> /// <param name="path">Lambda expression returning association path</param> @@ -243,11 +319,28 @@ /// </summary> /// <param name="path">Lambda expression returning association path</param> /// <param name="alias">Lambda expression returning alias reference</param> + /// <returns>criteria instance</returns> + IQueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias); + + /// <summary> + /// Join an association, assigning an alias to the joined entity + /// </summary> + /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> /// <param name="joinType">Type of join</param> /// <returns>criteria instance</returns> IQueryOver<T> Join(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType); - IQueryOverJoinBuilder<T> Inner { get; } + /// <summary> + /// Join an association, assigning an alias to the joined entity + /// </summary> + /// <param name="path">Lambda expression returning association path</param> + /// <param name="alias">Lambda expression returning alias reference</param> + /// <param name="joinType">Type of join</param> + /// <returns>criteria instance</returns> + IQueryOver<T> Join(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType); + + IQueryOverJoinBuilder<T> Inner { get; } IQueryOverJoinBuilder<T> Left { get; } IQueryOverJoinBuilder<T> Right { get; } IQueryOverJoinBuilder<T> Full { get; } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-10-31 18:34:16 UTC (rev 4816) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-03 16:11:25 UTC (rev 4817) @@ -179,6 +179,23 @@ } [Test] + public void SubCriteria_JoinQueryOver_ToOneAlias() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .CreateCriteria("personAlias.Father") + .Add(Expression.Eq("Name", "test name")); + + Person personAlias = null; + IQueryOver<Person> actual = + CreateTestQueryOver<Person>(() => personAlias) + .JoinQueryOver(() => personAlias.Father) // sub-criteria + .Where(f => f.Name == "test name"); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void SubCriteria_JoinQueryOver_ToMany() { ICriteria expected = @@ -195,6 +212,23 @@ } [Test] + public void SubCriteria_JoinQueryOver_ToManyAlias() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .CreateCriteria("personAlias.Children", JoinType.InnerJoin) + .Add(Expression.Eq("Nickname", "test name")); + + Person personAlias = null; + IQueryOver<Child> actual = + CreateTestQueryOver<Person>(() => personAlias) + .Inner.JoinQueryOver(() => personAlias.Children) // sub-criteria + .Where(c => c.Nickname == "test name"); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void SubCriteria_JoinQueryOverCombinations() { ICriteria expected = @@ -243,6 +277,25 @@ } [Test] + public void Alias_JoinAlias() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .CreateAlias("personAlias.Father", "fatherAlias") + .CreateAlias("personAlias.Children", "childAlias", JoinType.InnerJoin); + + Person personAlias = null; + Person fatherAlias = null; + Child childAlias = null; + IQueryOver<Person> actual = + CreateTestQueryOver<Person>(() => personAlias) + .Join(() => personAlias.Father, () => fatherAlias) + .Inner.Join(() => personAlias.Children, () => childAlias); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void Alias_JoinCombinations() { ICriteria expected = This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: J. Mrs.J. <jee...@ya...> - 2009-11-03 13:43:52
|
我有新的電郵地址!你現可電郵給我:jee...@ya... - Beloved friend,How are you today? I hope all is well .Be informed that due to your delay , the CASHIER'S CHEQUE worth of (US$1.5 Million ) was converted into ATM-Card which you can withdraw in any ATM Cash Point Machine Worldwide has been programmed by the issuing bank .Note that the issuing bank has packaged the ATM CARD with the secret code and registered it with FEDEX EXPRESS COMPANY also you will be drawing sum of (US$4,000.00) everyday.Therefore, quickly contact FEDEX COMPANY with bellow information .Director:Dr.Joe Odife,Email addres:(fed...@li...) or (fed...@ho...)Tele phone: +229-930 171 96 or +23480 792 840 00,But the only money you have to send to FEDEX COMPANY is only ( US $105 ) according to the director of the issuing bank for the smooth delivery of your package to your door step also refresh your full NAME,ADDRESS,TELE PHONE NUMBER AND DRIVER'S LIC OR PASSPORT to them to avoid wrong delivery.Yours faithfully, Mrs.Jeffery Jean. |
From: <fab...@us...> - 2009-10-31 18:34:23
|
Revision: 4816 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4816&view=rev Author: fabiomaulo Date: 2009-10-31 18:34:16 +0000 (Sat, 31 Oct 2009) Log Message: ----------- tagging release Added Paths: ----------- tags/2.1.1GA/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |