From: <fab...@us...> - 2011-05-23 19:10:29
|
Revision: 5864 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5864&view=rev Author: fabiomaulo Date: 2011-05-23 19:10:23 +0000 (Mon, 23 May 2011) Log Message: ----------- Fix NH-2317 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2317/Fixture.cs Modified: trunk/nhibernate/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs 2011-05-23 19:07:03 UTC (rev 5863) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs 2011-05-23 19:10:23 UTC (rev 5864) @@ -1,61 +1,82 @@ -using System.Linq.Expressions; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; using NHibernate.Linq.Visitors; using Remotion.Linq; using Remotion.Linq.Clauses; using Remotion.Linq.Clauses.Expressions; +using Remotion.Linq.Clauses.ResultOperators; namespace NHibernate.Linq.ReWriters { + /// <summary> + /// This re-writer is responsible to re-write a query without a body (no where-clause and so on). + /// </summary> public class QueryReferenceExpressionFlattener : NhExpressionTreeVisitor { - private readonly QueryModel _model; + private readonly QueryModel _model; + // NOTE: Skip/Take are not completelly flattenable since Take(10).Skip(5).Take(2) should result in a subqueries-tsunami (so far not common understanding from our users) + private static readonly List<System.Type> FlattenableResultOperactors = new List<System.Type> + { + typeof(CacheableResultOperator), + typeof(SkipResultOperator), + typeof(TakeResultOperator), + }; - private QueryReferenceExpressionFlattener(QueryModel model) + private QueryReferenceExpressionFlattener(QueryModel model) { - _model = model; + _model = model; } - public static void ReWrite(QueryModel model) + public static void ReWrite(QueryModel model) { var visitor = new QueryReferenceExpressionFlattener(model); model.TransformExpressions(visitor.VisitExpression); } - protected override Expression VisitSubQueryExpression(SubQueryExpression subQuery) - { - if ((subQuery.QueryModel.BodyClauses.Count == 0) && - ((subQuery.QueryModel.ResultOperators.Count == 0) || (subQuery.QueryModel.ResultOperators.Count == 1 && subQuery.QueryModel.ResultOperators[0] is CacheableResultOperator)) - ) - { - var selectQuerySource = - subQuery.QueryModel.SelectClause.Selector as QuerySourceReferenceExpression; + protected override Expression VisitSubQueryExpression(SubQueryExpression subQuery) + { + var hasBodyClauses = subQuery.QueryModel.BodyClauses.Count > 0; + if(hasBodyClauses) + { + return base.VisitSubQueryExpression(subQuery); + } + var resultOperators = subQuery.QueryModel.ResultOperators; + if (resultOperators.Count == 0 || HasJustAllFlattenableOperator(resultOperators)) + { + var selectQuerySource = subQuery.QueryModel.SelectClause.Selector as QuerySourceReferenceExpression; - if (selectQuerySource != null && selectQuerySource.ReferencedQuerySource == subQuery.QueryModel.MainFromClause) - { - if (subQuery.QueryModel.ResultOperators.Count == 1) - { - _model.ResultOperators.Add(subQuery.QueryModel.ResultOperators[0]); - } + if (selectQuerySource != null && selectQuerySource.ReferencedQuerySource == subQuery.QueryModel.MainFromClause) + { + foreach (var resultOperator in resultOperators) + { + _model.ResultOperators.Add(resultOperator); + } - return subQuery.QueryModel.MainFromClause.FromExpression; - } - } + return subQuery.QueryModel.MainFromClause.FromExpression; + } + } - return base.VisitSubQueryExpression(subQuery); - } + return base.VisitSubQueryExpression(subQuery); + } - protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + private bool HasJustAllFlattenableOperator(IEnumerable<ResultOperatorBase> resultOperators) { + return resultOperators.All(x => FlattenableResultOperactors.Contains(x.GetType())); + } + + protected override Expression VisitQuerySourceReferenceExpression(QuerySourceReferenceExpression expression) + { var fromClauseBase = expression.ReferencedQuerySource as FromClauseBase; - if (fromClauseBase != null && + if (fromClauseBase != null && fromClauseBase.FromExpression is QuerySourceReferenceExpression && expression.Type == fromClauseBase.FromExpression.Type) { return fromClauseBase.FromExpression; } - return base.VisitQuerySourceReferenceExpression(expression); + return base.VisitQuerySourceReferenceExpression(expression); } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2317/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2317/Fixture.cs 2011-05-23 19:07:03 UTC (rev 5863) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2317/Fixture.cs 2011-05-23 19:10:23 UTC (rev 5864) @@ -5,7 +5,7 @@ namespace NHibernate.Test.NHSpecificTest.NH2317 { - [TestFixture, Ignore("Not fixed yet.")] + [TestFixture] public class Fixture : BugTestCase { protected override void OnSetUp() @@ -28,8 +28,12 @@ using (var session = sessions.OpenSession()) using(session.BeginTransaction()) { - // HQL show how should look the HQL tree in this case and in all others casses where Skip/Take are not the last sentences - var expected = session.CreateQuery("select a.id from Artist a where a in (from Artist take 3)").List<int>(); + // The HQL : "select a.id from Artist a where a in (from Artist take 3)" + // shows how should look the HQL tree in the case where Skip/Take are not the last sentences. + + // When the query has no where-clauses the the HQL can be reduced to: "select a.id from Artist a take 3)" + + var expected = session.CreateQuery("select a.id from Artist a take 3").List<int>(); var actual = session.Query<Artist>().Take(3).Select(a => a.Id).ToArray(); actual.Should().Have.SameValuesAs(expected); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |