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: <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: <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-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-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: <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-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: <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 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-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-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-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-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-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 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 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 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: <fab...@us...> - 2009-11-20 20:14:05
|
Revision: 4847 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4847&view=rev Author: fabiomaulo Date: 2009-11-20 20:13:57 +0000 (Fri, 20 Nov 2009) Log Message: ----------- Merge r4846 (fix NH-2011) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Model.cs Modified: trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2009-11-20 20:00:56 UTC (rev 4846) +++ trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2009-11-20 20:13:57 UTC (rev 4847) @@ -1125,8 +1125,10 @@ ? new object[subtypes.Length] : componentType.GetPropertyValues(original[i], session); object[] targetComponentValues = componentType.GetPropertyValues(target[i], session); - ReplaceAssociations(origComponentValues, targetComponentValues, subtypes, session, null, copyCache, + object[] componentCopy = ReplaceAssociations(origComponentValues, targetComponentValues, subtypes, session, null, copyCache, foreignKeyDirection); + if (!componentType.IsAnyType) + componentType.SetPropertyValues(target[i], componentCopy, session.EntityMode); copied[i] = target[i]; } else if (!types[i].IsAssociationType) Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Fixture.cs 2009-11-20 20:13:57 UTC (rev 4847) @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH2011 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void Test() + { + using (ISession session = OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + session.Save(new Country {CountryCode = "SE"}); + tx.Commit(); + } + } + + var newOrder = new Order(); + newOrder.GroupComponent = new GroupComponent(); + newOrder.GroupComponent.Countries = new List<Country>(); + newOrder.GroupComponent.Countries.Add(new Country {CountryCode = "SE"}); + + Order mergedCopy; + using (ISession session = OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + mergedCopy = (Order) session.Merge(newOrder); + tx.Commit(); + } + } + + using (ISession session = OpenSession()) + { + var order = session.Get<Order>(mergedCopy.Id); + Assert.That(order.GroupComponent.Countries.Count, Is.EqualTo(1)); + } + + using (ISession session = OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + session.Delete("from Order"); + session.Delete("from Country"); + tx.Commit(); + } + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Mappings.hbm.xml 2009-11-20 20:13:57 UTC (rev 4847) @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH2011"> + + <class name="Order" table="Orders"> + + <id name="Id"> + <generator class="guid.comb"/> + </id> + + <component name="GroupComponent"> + + <bag name="Countries" table="OrderCountries" cascade="none"> + <key column="OrderId" /> + <many-to-many column="CountryCode" class="Country" /> + </bag> + + </component> + + </class> + + <class name="Country" table="Countries"> + + <id name="CountryCode" unsaved-value="null"> + <generator class="assigned"/> + </id> + + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Model.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2011/Model.cs 2009-11-20 20:13:57 UTC (rev 4847) @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH2011 +{ + public class Order + { + public virtual Guid Id { get; set; } + + public virtual GroupComponent GroupComponent { get; set; } + } + + public class GroupComponent + { + public virtual IList<Country> Countries { get; set; } + } + + public class Country + { + public virtual string CountryCode { get; set; } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-20 20:00:56 UTC (rev 4846) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-20 20:13:57 UTC (rev 4847) @@ -665,6 +665,8 @@ <Compile Include="NHSpecificTest\NH2000\SampleTest.cs" /> <Compile Include="NHSpecificTest\NH2003\Fixture.cs" /> <Compile Include="NHSpecificTest\NH2003\Model.cs" /> + <Compile Include="NHSpecificTest\NH2011\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH2011\Model.cs" /> <Compile Include="NHSpecificTest\NH473\Child.cs" /> <Compile Include="NHSpecificTest\NH473\Fixture.cs" /> <Compile Include="NHSpecificTest\NH473\Parent.cs" /> @@ -2078,6 +2080,7 @@ <EmbeddedResource Include="CfgTest\Loquacious\EntityToCache.hbm.xml" /> <EmbeddedResource Include="DriverTest\SqlServerCeEntity.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH2011\Mappings.hbm.xml" /> <EmbeddedResource Include="Linq\Mappings\Animal.hbm.xml" /> <EmbeddedResource Include="Linq\Mappings\AnotherEntity.hbm.xml" /> <EmbeddedResource Include="Linq\Mappings\Role.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-20 21:28:58
|
Revision: 4848 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4848&view=rev Author: ricbrown Date: 2009-11-20 21:28:47 +0000 (Fri, 20 Nov 2009) Log Message: ----------- Added convenience syntax for negation of expressions. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.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-20 20:13:57 UTC (rev 4847) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-20 21:28:47 UTC (rev 4848) @@ -89,6 +89,16 @@ return Add(expression); } + public QueryOver<T> AndNot(Expression<Func<T, bool>> expression) + { + return AddNot(expression); + } + + public QueryOver<T> AndNot(Expression<Func<bool>> expression) + { + return AddNot(expression); + } + public QueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<T, object>> expression) { return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); @@ -114,6 +124,16 @@ return Add(expression); } + public QueryOver<T> WhereNot(Expression<Func<T, bool>> expression) + { + return AddNot(expression); + } + + public QueryOver<T> WhereNot(Expression<Func<bool>> expression) + { + return AddNot(expression); + } + public QueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<T, object>> expression) { return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); @@ -464,7 +484,19 @@ return this; } + private QueryOver<T> AddNot(Expression<Func<T, bool>> expression) + { + _criteria.Add(Restrictions.Not(ExpressionProcessor.ProcessExpression<T>(expression))); + return this; + } + private QueryOver<T> AddNot(Expression<Func<bool>> expression) + { + _criteria.Add(Restrictions.Not(ExpressionProcessor.ProcessExpression(expression))); + return this; + } + + ICriteria IQueryOver<T>.UnderlyingCriteria { get { return UnderlyingCriteria; } } @@ -477,6 +509,12 @@ IQueryOver<T> IQueryOver<T>.And(ICriterion expression) { return And(expression); } + IQueryOver<T> IQueryOver<T>.AndNot(Expression<Func<T, bool>> expression) + { return AndNot(expression); } + + IQueryOver<T> IQueryOver<T>.AndNot(Expression<Func<bool>> expression) + { return AndNot(expression); } + IQueryOverRestrictionBuilder<T> IQueryOver<T>.AndRestrictionOn(Expression<Func<T, object>> expression) { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } @@ -492,6 +530,12 @@ IQueryOver<T> IQueryOver<T>.Where(ICriterion expression) { return Where(expression); } + IQueryOver<T> IQueryOver<T>.WhereNot(Expression<Func<T, bool>> expression) + { return WhereNot(expression); } + + IQueryOver<T> IQueryOver<T>.WhereNot(Expression<Func<bool>> expression) + { return WhereNot(expression); } + IQueryOverRestrictionBuilder<T> IQueryOver<T>.WhereRestrictionOn(Expression<Func<T, object>> expression) { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-20 20:13:57 UTC (rev 4847) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-20 21:28:47 UTC (rev 4848) @@ -50,6 +50,20 @@ IQueryOver<T> And(ICriterion expression); /// <summary> + /// Add negation of criterion expressed as a lambda expression + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOver<T> AndNot(Expression<Func<T, bool>> expression); + + /// <summary> + /// Add negation of criterion expressed as a lambda expression + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOver<T> AndNot(Expression<Func<bool>> expression); + + /// <summary> /// Add restriction to a property /// </summary> /// <param name="expression">Lambda expression containing path to property</param> @@ -64,14 +78,14 @@ IQueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<object>> expression); /// <summary> - /// Identical semantics to Add() to allow more readable queries + /// Identical semantics to And() to allow more readable queries /// </summary> /// <param name="expression">Lambda expression</param> /// <returns>criteria instance</returns> IQueryOver<T> Where(Expression<Func<T, bool>> expression); /// <summary> - /// Identical semantics to Add() to allow more readable queries + /// Identical semantics to And() to allow more readable queries /// </summary> /// <param name="expression">Lambda expression</param> /// <returns>criteria instance</returns> @@ -83,6 +97,20 @@ IQueryOver<T> Where(ICriterion expression); /// <summary> + /// Identical semantics to AndNot() to allow more readable queries + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOver<T> WhereNot(Expression<Func<T, bool>> expression); + + /// <summary> + /// Identical semantics to AndNot() to allow more readable queries + /// </summary> + /// <param name="expression">Lambda expression</param> + /// <returns>criteria instance</returns> + IQueryOver<T> WhereNot(Expression<Func<bool>> expression); + + /// <summary> /// Identical semantics to AndRestrictionOn() to allow more readable queries /// </summary> /// <param name="expression">Lambda expression</param> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-20 20:13:57 UTC (rev 4847) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-20 21:28:47 UTC (rev 4848) @@ -101,18 +101,39 @@ } [Test] + public void Negation() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .Add(Restrictions.Not(Restrictions.Eq("Name", "test name"))) + .Add(Restrictions.Not(Restrictions.Eq("personAlias.Name", "test name"))); + + Person personAlias = null; + IQueryOver<Person> actual = + CreateTestQueryOver<Person>(() => personAlias) + .AndNot(p => p.Name == "test name") + .AndNot(() => personAlias.Name == "test name"); + + AssertCriteriaAreEqual(expected, actual); + } + + [Test] public void Where_BehavesTheSameAs_And() { Person personAlias = null; QueryOver<Person> expected = (QueryOver<Person>) CreateTestQueryOver<Person>(() => personAlias) .And(() => personAlias.Name == "test name") - .And(p => p.Name == "test name"); + .And(p => p.Name == "test name") + .AndNot(() => personAlias.Name == "test name") + .AndNot(p => p.Name == "test name"); IQueryOver<Person> actual = CreateTestQueryOver<Person>(() => personAlias) .Where(() => personAlias.Name == "test name") - .Where(p => p.Name == "test name"); + .Where(p => p.Name == "test name") + .WhereNot(() => personAlias.Name == "test name") + .WhereNot(p => p.Name == "test name"); AssertCriteriaAreEqual(expected.UnderlyingCriteria, actual); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-23 17:38:18
|
Revision: 4855 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4855&view=rev Author: ricbrown Date: 2009-11-23 17:38:07 +0000 (Mon, 23 Nov 2009) Log Message: ----------- Added first cut of projections using Lambda expressions. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/ProjectionList.cs trunk/nhibernate/src/NHibernate/Criterion/Projections.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/ProjectionsExtensions.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/ProjectionList.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/ProjectionList.cs 2009-11-22 15:34:59 UTC (rev 4854) +++ trunk/nhibernate/src/NHibernate/Criterion/ProjectionList.cs 2009-11-23 17:38:07 UTC (rev 4855) @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Impl; using NHibernate.SqlCommand; using NHibernate.Type; -using System.Collections.Generic; namespace NHibernate.Criterion { @@ -32,6 +34,11 @@ return Add(Projections.Alias(projection, alias)); } + public ProjectionList Add<T>(IProjection projection, Expression<Func<T>> alias) + { + return Add(projection, ExpressionProcessor.FindMemberExpression(alias.Body)); + } + public IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) { IList<IType> types = new List<IType>(Length); Modified: trunk/nhibernate/src/NHibernate/Criterion/Projections.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2009-11-22 15:34:59 UTC (rev 4854) +++ trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2009-11-23 17:38:07 UTC (rev 4855) @@ -1,4 +1,6 @@ using System; +using System.Linq.Expressions; +using NHibernate.Impl; using NHibernate.Type; namespace NHibernate.Criterion @@ -316,5 +318,138 @@ SelectSubqueryExpression expr = new SelectSubqueryExpression(detachedCriteria); return new SubqueryProjection(expr); } + + /// <summary> + /// A property average value + /// </summary> + public static AggregateProjection Avg<T>(Expression<Func<T, object>> expression) + { + return Projections.Avg(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property average value + /// </summary> + public static AggregateProjection Avg(Expression<Func<object>> expression) + { + return Projections.Avg(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property value count + /// </summary> + public static CountProjection Count<T>(Expression<Func<T, object>> expression) + { + return Projections.Count(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property value count + /// </summary> + public static CountProjection Count(Expression<Func<object>> expression) + { + return Projections.Count(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A distinct property value count + /// </summary> + public static CountProjection CountDistinct<T>(Expression<Func<T, object>> expression) + { + return Projections.CountDistinct(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A distinct property value count + /// </summary> + public static CountProjection CountDistinct(Expression<Func<object>> expression) + { + return Projections.CountDistinct(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A grouping property value + /// </summary> + public static PropertyProjection GroupProperty<T>(Expression<Func<T, object>> expression) + { + return Projections.GroupProperty(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A grouping property value + /// </summary> + public static PropertyProjection GroupProperty(Expression<Func<object>> expression) + { + return Projections.GroupProperty(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property maximum value + /// </summary> + public static AggregateProjection Max<T>(Expression<Func<T, object>> expression) + { + return Projections.Max(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property maximum value + /// </summary> + public static AggregateProjection Max(Expression<Func<object>> expression) + { + return Projections.Max(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property minimum value + /// </summary> + public static AggregateProjection Min<T>(Expression<Func<T, object>> expression) + { + return Projections.Min(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property minimum value + /// </summary> + public static AggregateProjection Min(Expression<Func<object>> expression) + { + return Projections.Min(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A projected property value + /// </summary> + public static PropertyProjection Property<T>(Expression<Func<T, object>> expression) + { + return Projections.Property(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A projected property value + /// </summary> + public static PropertyProjection Property(Expression<Func<object>> expression) + { + return Projections.Property(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + public static IProjection SubQuery<T>(QueryOver<T> detachedQueryOver) + { + return Projections.SubQuery(detachedQueryOver.DetachedCriteria); + } + + /// <summary> + /// A property value sum + /// </summary> + public static AggregateProjection Sum<T>(Expression<Func<T, object>> expression) + { + return Projections.Sum(ExpressionProcessor.FindMemberExpression(expression.Body)); + } + + /// <summary> + /// A property value sum + /// </summary> + public static AggregateProjection Sum(Expression<Func<object>> expression) + { + return Projections.Sum(ExpressionProcessor.FindMemberExpression(expression.Body)); + } } } Added: trunk/nhibernate/src/NHibernate/Criterion/ProjectionsExtensions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/ProjectionsExtensions.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/ProjectionsExtensions.cs 2009-11-23 17:38:07 UTC (rev 4855) @@ -0,0 +1,23 @@ +using System; +using System.Linq.Expressions; + +using NHibernate.Impl; + +namespace NHibernate.Criterion +{ + public static class ProjectionsExtensions + { + /// <summary> + /// Create an alias for a projection + /// </summary> + /// <param name="projection">the projection instance</param> + /// <param name="alias">LambdaExpression returning an alias</param> + /// <returns>return NHibernate.Criterion.IProjection</returns> + public static IProjection WithAlias(this IProjection projection, + Expression<Func<object>> alias) + { + string aliasContainer = ExpressionProcessor.FindMemberExpression(alias.Body); + return Projections.Alias(projection, aliasContainer); + } + } +} Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-22 15:34:59 UTC (rev 4854) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-23 17:38:07 UTC (rev 4855) @@ -515,6 +515,7 @@ <Compile Include="Criterion\Lambda\QueryOverRestrictionBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryPropertyBuilder.cs" /> + <Compile Include="Criterion\ProjectionsExtensions.cs" /> <Compile Include="Dialect\MsSql2008Dialect.cs" /> <Compile Include="Dialect\InformixDialect0940.cs" /> <Compile Include="Dialect\InformixDialect1000.cs" /> Added: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) @@ -0,0 +1,90 @@ +using System; +using System.Collections; + +using NUnit.Framework; + +using NHibernate.Criterion; + +namespace NHibernate.Test.Criteria.Lambda +{ + + [TestFixture] + public class ProjectionsFixture : LambdaFixtureBase + { + + private Child _subqueryChildAlias = null; + + private DetachedCriteria DetachedCriteriaAge + { + get + { + return ToDetachedCriteria(DetachedQueryOverAge); + } + } + + private QueryOver<Child> DetachedQueryOverAge + { + get + { + return + new QueryOver<Child>(() => _subqueryChildAlias) + .Where(() => _subqueryChildAlias.Nickname == "subquery name") + .Select(p => p.Age); + } + } + + [Test] + public void ArbitraryProjections() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .SetProjection(Projections.ProjectionList() + .Add(Projections.Alias(Projections.Avg("Age"), "personAgeProjectionAlias")) + .Add(Projections.Avg("Age"), "personAgeProjectionAlias") + .Add(Projections.Avg("personAlias.Age")) + .Add(Projections.Count("Age")) + .Add(Projections.Count("personAlias.Age")) + .Add(Projections.CountDistinct("Age")) + .Add(Projections.CountDistinct("personAlias.Age")) + .Add(Projections.GroupProperty("Age")) + .Add(Projections.GroupProperty("personAlias.Age")) + .Add(Projections.Max("Age")) + .Add(Projections.Max("personAlias.Age")) + .Add(Projections.Min("Age")) + .Add(Projections.Min("personAlias.Age")) + .Add(Projections.Property("Age")) + .Add(Projections.Property("personAlias.Age")) + .Add(Projections.SubQuery(DetachedCriteriaAge)) + .Add(Projections.Sum("Age")) + .Add(Projections.Sum("personAlias.Age"))); + + Person personAlias = null; + Person personAgeProjectionAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .Select(Projections.ProjectionList() + .Add(Projections.Avg<Person>(p => p.Age).WithAlias(() => personAgeProjectionAlias)) + .Add(Projections.Avg<Person>(p => p.Age), () => personAgeProjectionAlias) + .Add(Projections.Avg(() => personAlias.Age)) + .Add(Projections.Count<Person>(p => p.Age)) + .Add(Projections.Count(() => personAlias.Age)) + .Add(Projections.CountDistinct<Person>(p => p.Age)) + .Add(Projections.CountDistinct(() => personAlias.Age)) + .Add(Projections.GroupProperty<Person>(p => p.Age)) + .Add(Projections.GroupProperty(() => personAlias.Age)) + .Add(Projections.Max<Person>(p => p.Age)) + .Add(Projections.Max(() => personAlias.Age)) + .Add(Projections.Min<Person>(p => p.Age)) + .Add(Projections.Min(() => personAlias.Age)) + .Add(Projections.Property<Person>(p => p.Age)) + .Add(Projections.Property(() => personAlias.Age)) + .Add(Projections.SubQuery(DetachedQueryOverAge)) + .Add(Projections.Sum<Person>(p => p.Age)) + .Add(Projections.Sum(() => personAlias.Age))); + + 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-22 15:34:59 UTC (rev 4854) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-23 17:38:07 UTC (rev 4855) @@ -160,6 +160,7 @@ <Compile Include="Criteria\Enrolment.cs" /> <Compile Include="Criteria\Lambda\CriteriaAssertFixture.cs" /> <Compile Include="Criteria\Lambda\ExpressionProcessorFixture.cs" /> + <Compile Include="Criteria\Lambda\ProjectionsFixture.cs" /> <Compile Include="Criteria\Lambda\QueryOverFixture.cs" /> <Compile Include="Criteria\Lambda\IntegrationFixture.cs" /> <Compile Include="Criteria\Lambda\LambdaFixtureBase.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-23 18:00:28
|
Revision: 4856 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4856&view=rev Author: ricbrown Date: 2009-11-23 18:00:21 +0000 (Mon, 23 Nov 2009) Log Message: ----------- Moved creation of detached QueryOver of T to a factory method. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.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-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -19,6 +19,16 @@ protected QueryOver() { } + public static QueryOver<T> Of<T>() + { + return new QueryOver<T>(); + } + + public static QueryOver<T> Of<T>(Expression<Func<T>> alias) + { + return new QueryOver<T>(alias); + } + public ICriteria UnderlyingCriteria { get { return _criteria; } @@ -38,13 +48,13 @@ public class QueryOver<T> : QueryOver, IQueryOver<T> { - public QueryOver() + protected internal QueryOver() { _impl = new CriteriaImpl(typeof(T), null); _criteria = _impl; } - public QueryOver(Expression<Func<T>> alias) + protected internal QueryOver(Expression<Func<T>> alias) { string aliasPath = ExpressionProcessor.FindMemberExpression(alias.Body); _impl = new CriteriaImpl(typeof(T), aliasPath, null); Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -81,7 +81,7 @@ using (ISession s = OpenSession()) { QueryOver<Person> personQuery = - new QueryOver<Person>() + QueryOver.Of<Person>() .Where(p => p.Name == "test person 1"); IList<Person> actual = Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -27,7 +27,7 @@ get { return - new QueryOver<Child>(() => _subqueryChildAlias) + QueryOver.Of<Child>(() => _subqueryChildAlias) .Where(() => _subqueryChildAlias.Nickname == "subquery name") .Select(p => p.Age); } Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -477,7 +477,7 @@ Person personAlias = null; QueryOver<Person> actual = - new QueryOver<Person>(() => personAlias) + QueryOver.Of<Person>(() => personAlias) .Where(() => personAlias.Name == "test name"); AssertCriteriaAreEqual(expected, actual); Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/RestrictionsFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -158,7 +158,7 @@ Person personAlias = null; QueryOver<Person> actual = - new QueryOver<Person>(() => personAlias) + QueryOver.Of<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" }) Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-23 17:38:07 UTC (rev 4855) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/SubqueryFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) @@ -47,7 +47,7 @@ get { return - new QueryOver<Child>(() => _subqueryChildAlias) + QueryOver.Of<Child>(() => _subqueryChildAlias) .Where(() => _subqueryChildAlias.Nickname == "subquery name"); } } @@ -57,7 +57,7 @@ get { return - new QueryOver<Child>(() => _subqueryChildAlias) + QueryOver.Of<Child>(() => _subqueryChildAlias) .Where(() => _subqueryChildAlias.Nickname == "subquery name") .Select(p => p.Nickname); } @@ -68,7 +68,7 @@ get { return - new QueryOver<Child>(() => _subqueryChildAlias) + QueryOver.Of<Child>(() => _subqueryChildAlias) .Where(() => _subqueryChildAlias.Nickname == "subquery name") .Select(p => p.Age); } @@ -112,7 +112,7 @@ Person personAlias = null; QueryOver<Person> actual = - new QueryOver<Person>(() => personAlias) + QueryOver.Of<Person>(() => personAlias) .WithSubquery.WhereProperty(p => p.Name).Eq(DetachedQueryOverName) .WithSubquery.WhereProperty(() => personAlias.Name).Eq(DetachedQueryOverName); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-25 18:36:17
|
Revision: 4857 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4857&view=rev Author: ricbrown Date: 2009-11-25 18:36:07 +0000 (Wed, 25 Nov 2009) Log Message: ----------- Added typed inline projections to QueryOver. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 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/ProjectionsFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs Added: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs 2009-11-25 18:36:07 UTC (rev 4857) @@ -0,0 +1,223 @@ + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +using NHibernate.Impl; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion.Lambda +{ + + public class QueryOverProjectionBuilder<R, T> + { + + private R fluentReturn; + private IQueryOver<T> criteria; + private ProjectionList projectionList; + private IProjection lastProjection = null; + + public QueryOverProjectionBuilder(R fluentReturn, IQueryOver<T> criteria) + { + this.fluentReturn = fluentReturn; + this.criteria = criteria; + projectionList = Projections.ProjectionList(); + } + + private void AddLastProjection() + { + if (lastProjection != null) + projectionList.Add(lastProjection); + } + + private void PushProjection(IProjection projection) + { + AddLastProjection(); + lastProjection = projection; + } + + /// <summary> + /// Create the ProjectionList and return to the query + /// </summary> + public R EndSelect + { + get + { + AddLastProjection(); + criteria.Select(projectionList); + return fluentReturn; + } + } + + /// <summary> + /// Create an alias for the previous projection + /// </summary> + public QueryOverProjectionBuilder<R, T> WithAlias(Expression<Func<object>> alias) + { + string aliasContainer = ExpressionProcessor.FindMemberExpression(alias.Body); + lastProjection = Projections.Alias(lastProjection, aliasContainer); + return this; + } + + /// <summary> + /// Select an arbitrary projection + /// </summary> + public QueryOverProjectionBuilder<R, T> Select(IProjection projection) + { + PushProjection(projection); + return this; + } + + /// <summary> + /// A property average value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectAvg(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Avg(expression)); + return this; + } + + /// <summary> + /// A property average value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectAvg(Expression<Func<object>> expression) + { + PushProjection(Projections.Avg(expression)); + return this; + } + + /// <summary> + /// A property value count + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectCount(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Count(expression)); + return this; + } + + /// <summary> + /// A property value count + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectCount(Expression<Func<object>> expression) + { + PushProjection(Projections.Count(expression)); + return this; + } + + /// <summary> + /// A distinct property value count + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectCountDistinct(Expression<Func<T, object>> expression) + { + PushProjection(Projections.CountDistinct(expression)); + return this; + } + + /// <summary> + /// A distinct property value count + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectCountDistinct(Expression<Func<object>> expression) + { + PushProjection(Projections.CountDistinct(expression)); + return this; + } + + /// <summary> + /// A grouping property value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectGroup(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Group(expression)); + return this; + } + + /// <summary> + /// A grouping property value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectGroup(Expression<Func<object>> expression) + { + PushProjection(Projections.Group(expression)); + return this; + } + + /// <summary> + /// A property maximum value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectMax(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Max(expression)); + return this; + } + + /// <summary> + /// A property maximum value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectMax(Expression<Func<object>> expression) + { + PushProjection(Projections.Max(expression)); + return this; + } + + /// <summary> + /// A property minimum value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectMin(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Min(expression)); + return this; + } + + /// <summary> + /// A property minimum value + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectMin(Expression<Func<object>> expression) + { + PushProjection(Projections.Min(expression)); + return this; + } + + /// <summary> + /// A projected property value + /// </summary> + public QueryOverProjectionBuilder<R, T> Select(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Property(expression)); + return this; + } + + /// <summary> + /// A projected property value + /// </summary> + public QueryOverProjectionBuilder<R, T> Select(Expression<Func<object>> expression) + { + PushProjection(Projections.Property(expression)); + return this; + } + + public QueryOverProjectionBuilder<R, T> SelectSubQuery<U>(QueryOver<U> detachedQueryOver) + { + PushProjection(Projections.SubQuery(detachedQueryOver)); + return this; + } + + /// <summary> + /// A property value sum + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectSum(Expression<Func<T, object>> expression) + { + PushProjection(Projections.Sum(expression)); + return this; + } + + /// <summary> + /// A property value sum + /// </summary> + public QueryOverProjectionBuilder<R, T> SelectSum(Expression<Func<object>> expression) + { + PushProjection(Projections.Sum(expression)); + return this; + } + + } + +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Projections.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2009-11-23 18:00:21 UTC (rev 4856) +++ trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2009-11-25 18:36:07 UTC (rev 4857) @@ -370,7 +370,7 @@ /// <summary> /// A grouping property value /// </summary> - public static PropertyProjection GroupProperty<T>(Expression<Func<T, object>> expression) + public static PropertyProjection Group<T>(Expression<Func<T, object>> expression) { return Projections.GroupProperty(ExpressionProcessor.FindMemberExpression(expression.Body)); } @@ -378,7 +378,7 @@ /// <summary> /// A grouping property value /// </summary> - public static PropertyProjection GroupProperty(Expression<Func<object>> expression) + public static PropertyProjection Group(Expression<Func<object>> expression) { return Projections.GroupProperty(ExpressionProcessor.FindMemberExpression(expression.Body)); } Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-23 18:00:21 UTC (rev 4856) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-25 18:36:07 UTC (rev 4857) @@ -171,6 +171,11 @@ return this; } + QueryOverProjectionBuilder<QueryOver<T>, T> SelectList + { + get { return new QueryOverProjectionBuilder<QueryOver<T>, T>(this, this); } + } + public QueryOverOrderBuilder<T> OrderBy(Expression<Func<T, object>> path) { return new QueryOverOrderBuilder<T>(this, path); @@ -558,6 +563,9 @@ IQueryOver<T> IQueryOver<T>.Select(params IProjection[] projections) { return Select(projections); } + QueryOverProjectionBuilder<IQueryOver<T>, T> IQueryOver<T>.SelectList + { get { return new QueryOverProjectionBuilder<IQueryOver<T>,T>(this, this); } } + IQueryOverOrderBuilder<T> IQueryOver<T>.OrderBy(Expression<Func<T, object>> path) { return new IQueryOverOrderBuilder<T>(this, path); } Modified: trunk/nhibernate/src/NHibernate/IQueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-23 18:00:21 UTC (rev 4856) +++ trunk/nhibernate/src/NHibernate/IQueryOver.cs 2009-11-25 18:36:07 UTC (rev 4857) @@ -137,6 +137,11 @@ IQueryOver<T> Select(params IProjection[] projections); /// <summary> + /// Create a list of projections inline + /// </summary> + QueryOverProjectionBuilder<IQueryOver<T>, T> SelectList { get; } + + /// <summary> /// Add order expressed as a lambda expression /// </summary> /// <param name="path">Lambda expression</param> Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-23 18:00:21 UTC (rev 4856) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-25 18:36:07 UTC (rev 4857) @@ -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\QueryOverProjectionBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverRestrictionBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryBuilder.cs" /> <Compile Include="Criterion\Lambda\QueryOverSubqueryPropertyBuilder.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs 2009-11-23 18:00:21 UTC (rev 4856) +++ trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/ProjectionsFixture.cs 2009-11-25 18:36:07 UTC (rev 4857) @@ -70,8 +70,8 @@ .Add(Projections.Count(() => personAlias.Age)) .Add(Projections.CountDistinct<Person>(p => p.Age)) .Add(Projections.CountDistinct(() => personAlias.Age)) - .Add(Projections.GroupProperty<Person>(p => p.Age)) - .Add(Projections.GroupProperty(() => personAlias.Age)) + .Add(Projections.Group<Person>(p => p.Age)) + .Add(Projections.Group(() => personAlias.Age)) .Add(Projections.Max<Person>(p => p.Age)) .Add(Projections.Max(() => personAlias.Age)) .Add(Projections.Min<Person>(p => p.Age)) @@ -85,6 +85,59 @@ AssertCriteriaAreEqual(expected, actual); } + [Test] + public void InlineProjectionList() + { + ICriteria expected = + CreateTestCriteria(typeof(Person), "personAlias") + .SetProjection(Projections.ProjectionList() + .Add(Projections.Alias(Projections.Avg("Age"), "personAgeProjectionAlias")) + .Add(Projections.Avg("Age")) + .Add(Projections.Avg("personAlias.Age")) + .Add(Projections.Count("Age")) + .Add(Projections.Count("personAlias.Age")) + .Add(Projections.CountDistinct("Age")) + .Add(Projections.CountDistinct("personAlias.Age")) + .Add(Projections.GroupProperty("Age")) + .Add(Projections.GroupProperty("personAlias.Age")) + .Add(Projections.Max("Age")) + .Add(Projections.Max("personAlias.Age")) + .Add(Projections.Min("Age")) + .Add(Projections.Min("personAlias.Age")) + .Add(Projections.Property("Age")) + .Add(Projections.Property("personAlias.Age")) + .Add(Projections.SubQuery(DetachedCriteriaAge)) + .Add(Projections.Sum("Age")) + .Add(Projections.Sum("personAlias.Age"))); + + Person personAlias = null; + Person personAgeProjectionAlias = null; + var actual = + CreateTestQueryOver<Person>(() => personAlias) + .SelectList + .SelectAvg(p => p.Age).WithAlias(() => personAgeProjectionAlias) + .Select(Projections.Avg("Age")) // allows private properties + .SelectAvg(() => personAlias.Age) + .SelectCount(p => p.Age) + .SelectCount(() => personAlias.Age) + .SelectCountDistinct(p => p.Age) + .SelectCountDistinct(() => personAlias.Age) + .SelectGroup(p => p.Age) + .SelectGroup(() => personAlias.Age) + .SelectMax(p => p.Age) + .SelectMax(() => personAlias.Age) + .SelectMin(p => p.Age) + .SelectMin(() => personAlias.Age) + .Select(p => p.Age) + .Select(() => personAlias.Age) + .SelectSubQuery(DetachedQueryOverAge) + .SelectSum(p => p.Age) + .SelectSum(() => personAlias.Age) + .EndSelect; + + 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-27 20:10:59
|
Revision: 4861 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4861&view=rev Author: steverstrong Date: 2009-11-27 20:10:47 +0000 (Fri, 27 Nov 2009) Log Message: ----------- Further Linq test cases added, and various related bugs fixed Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs trunk/nhibernate/src/NHibernate/Linq/ExpressionToHqlTranslationResults.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/MergeAggregatingResultsRewriter.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.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.Test/Linq/LinqTestCase.cs trunk/nhibernate/src/NHibernate.Test/Linq/ParameterisedQueries.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Linq/ProjectionsTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/PropertyMethodMappingTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/QueryReuseTests.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -261,9 +261,9 @@ return new HqlBitwiseNot(_factory); } - public HqlNot Not(HqlBooleanExpression operand) + public HqlBooleanNot Not(HqlBooleanExpression operand) { - return new HqlNot(_factory, operand); + return new HqlBooleanNot(_factory, operand); } public HqlAverage Average(HqlExpression expression) @@ -360,5 +360,16 @@ { return new HqlDistinctHolder(_factory, children); } + + public HqlIsNull IsNull(HqlExpression lhs) + { + return new HqlIsNull(_factory, lhs); + } + + public HqlIsNotNull IsNotNull(HqlExpression lhs) + { + return new HqlIsNotNull(_factory, lhs); + } } + } \ 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-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -192,6 +192,9 @@ case TypeCode.Int32: SetText("integer"); break; + case TypeCode.Int64: + SetText("long"); + break; case TypeCode.Decimal: SetText("decimal"); break; @@ -201,6 +204,9 @@ case TypeCode.String: SetText("string"); break; + case TypeCode.Double: + SetText("double"); + break; default: if (type == typeof(Guid)) { @@ -299,7 +305,7 @@ public class HqlBooleanAnd : HqlBooleanExpression { public HqlBooleanAnd(IASTFactory factory, HqlBooleanExpression lhs, HqlBooleanExpression rhs) - : base(HqlSqlWalker.AND, "/", factory, lhs, rhs) + : base(HqlSqlWalker.AND, "and", factory, lhs, rhs) { } } @@ -576,9 +582,9 @@ } } - public class HqlNot : HqlBooleanExpression + public class HqlBooleanNot : HqlBooleanExpression { - public HqlNot(IASTFactory factory, HqlBooleanExpression operand) + public HqlBooleanNot(IASTFactory factory, HqlBooleanExpression operand) : base(HqlSqlWalker.NOT, "not", factory, operand) { } @@ -712,4 +718,19 @@ { } } + + public class HqlIsNull : HqlBooleanExpression + { + public HqlIsNull(IASTFactory factory, HqlExpression lhs) + : base(HqlSqlWalker.IS_NULL, "is null", factory, lhs) + { + } + } + + public class HqlIsNotNull : HqlBooleanExpression + { + public HqlIsNotNull(IASTFactory factory, HqlExpression lhs) : base(HqlSqlWalker.IS_NOT_NULL, "is not null", factory, lhs) + { + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -336,11 +336,14 @@ throw new ArgumentNullException("val", "A type specific Set(name, val) should be called because the Type can not be guessed from a null value."); } - } + + SetParameter(name, val, type); + } else { SetParameter(name, val, DetermineType(name, val)); } + return this; } Modified: trunk/nhibernate/src/NHibernate/Linq/ExpressionToHqlTranslationResults.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ExpressionToHqlTranslationResults.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/ExpressionToHqlTranslationResults.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using NHibernate.Hql.Ast; +using NHibernate.Type; namespace NHibernate.Linq { @@ -10,9 +11,9 @@ { public HqlQuery Statement { get; private set; } public ResultTransformer ResultTransformer { get; private set; } - public List<Action<IQuery, IDictionary<string, object>>> AdditionalCriteria { get; private set; } + public List<Action<IQuery, IDictionary<string, Pair<object, IType>>>> AdditionalCriteria { get; private set; } - public ExpressionToHqlTranslationResults(HqlQuery statement, IList<LambdaExpression> itemTransformers, IList<LambdaExpression> listTransformers, List<Action<IQuery, IDictionary<string, object>>> additionalCriteria) + public ExpressionToHqlTranslationResults(HqlQuery statement, IList<LambdaExpression> itemTransformers, IList<LambdaExpression> listTransformers, List<Action<IQuery, IDictionary<string, Pair<object, IType>>>> additionalCriteria) { Statement = statement; Modified: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhAverageExpression.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -1,11 +1,37 @@ -using System.Linq.Expressions; +using System; +using System.Linq.Expressions; namespace NHibernate.Linq.Expressions { public class NhAverageExpression : NhAggregatedExpression { - public NhAverageExpression(Expression expression) : base(expression, NhExpressionType.Average) + public NhAverageExpression(Expression expression) : base(expression, CalculateAverageType(expression.Type), NhExpressionType.Average) { } + + private static System.Type CalculateAverageType(System.Type inputType) + { + bool isNullable = false; + + if (inputType.IsNullable()) + { + isNullable = true; + inputType = inputType.NullableOf(); + } + + switch (System.Type.GetTypeCode(inputType)) + { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + return isNullable ? typeof(double?) : typeof (double); + case TypeCode.Decimal: + return isNullable ? typeof(decimal?) : typeof(decimal); + } + + throw new NotSupportedException(inputType.FullName); + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Expressions/NhCountExpression.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -4,9 +4,25 @@ { public class NhCountExpression : NhAggregatedExpression { - public NhCountExpression(Expression expression) - : base(expression, typeof(int), NhExpressionType.Count) + public NhCountExpression(Expression expression, System.Type type) + : base(expression, type, NhExpressionType.Count) { } } -} \ No newline at end of file + + public class NhShortCountExpression : NhCountExpression + { + public NhShortCountExpression(Expression expression) + : base(expression, typeof(int)) + { + } + } + + public class NhLongCountExpression : NhCountExpression + { + public NhLongCountExpression(Expression expression) + : base(expression, typeof(long)) + { + } + } +} Modified: trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -24,5 +24,10 @@ return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } + public static System.Type NullableOf(this System.Type type) + { + return type.GetGenericArguments()[0]; + } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/NamedParameter.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -1,3 +1,6 @@ +using System; +using NHibernate.Type; + namespace NHibernate.Linq { public class NamedParameter @@ -2,10 +5,12 @@ { - public NamedParameter(string name, object value) + public NamedParameter(string name, object value, IType type) { Name = name; Value = value; + Type = type; } - public string Name { get; set; } - public object Value { get; set; } + public string Name { get; private set; } + public object Value { get; internal set; } + public IType Type { get; internal set; } } Modified: trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/NhLinqExpression.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -6,6 +6,7 @@ using NHibernate.Hql.Ast.ANTLR.Tree; using NHibernate.Linq.ResultOperators; using NHibernate.Linq.Visitors; +using NHibernate.Type; using Remotion.Data.Linq; using Remotion.Data.Linq.Clauses; using Remotion.Data.Linq.Clauses.StreamedData; @@ -25,7 +26,7 @@ public NhLinqExpressionReturnType ReturnType { get; private set; } - public IDictionary<string, object> ParameterValuesByName { get; private set; } + public IDictionary<string, Pair<object, IType>> ParameterValuesByName { get; private set; } public ExpressionToHqlTranslationResults ExpressionToHqlTranslationResults { get; private set; } @@ -40,7 +41,10 @@ _constantToParameterMap = ExpressionParameterVisitor.Visit(_expression); - ParameterValuesByName = _constantToParameterMap.Values.ToDictionary(p => p.Name, p => p.Value); + ParameterValuesByName = _constantToParameterMap.Values.ToDictionary(p => p.Name, + p => + new Pair<object, IType> + {Left = p.Value, Right = p.Type}); Key = ExpressionKeyVisitor.Visit(_expression, _constantToParameterMap); Modified: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using NHibernate.Impl; +using NHibernate.Type; namespace NHibernate.Linq { @@ -51,15 +52,23 @@ return new NhQueryable<T>(this, expression); } - static void SetParameters(IQuery query, IDictionary<string, object> parameters) + static void SetParameters(IQuery query, IDictionary<string, Pair<object, IType>> parameters) { foreach (var parameterName in query.NamedParameters) { - query.SetParameter(parameterName, parameters[parameterName]); + var param = parameters[parameterName]; + if (param.Left == null) + { + query.SetParameter(parameterName, param.Left, param.Right); + } + else + { + query.SetParameter(parameterName, param.Left); + } } } - public void SetResultTransformerAndAdditionalCriteria(IQuery query, IDictionary<string, object> parameters) + public void SetResultTransformerAndAdditionalCriteria(IQuery query, IDictionary<string, Pair<object, IType>> parameters) { var queryImpl = (ExpressionQueryImpl) query; @@ -73,4 +82,10 @@ } } } + + public class Pair<TLeft, TRight> + { + public TLeft Left { get; set; } + public TRight Right { get; set; } + } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/ParameterAggregator.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -1,4 +1,5 @@ using System.Collections.Generic; +using NHibernate.Type; namespace NHibernate.Linq { @@ -6,9 +7,9 @@ { private readonly List<NamedParameter> _parameters = new List<NamedParameter>(); - public NamedParameter AddParameter(object value) + public NamedParameter AddParameter(object value, IType type) { - var parameter = new NamedParameter("p" + (_parameters.Count + 1), value); + var parameter = new NamedParameter("p" + (_parameters.Count + 1), value, type); _parameters.Add(parameter); return parameter; } Modified: trunk/nhibernate/src/NHibernate/Linq/ReWriters/MergeAggregatingResultsRewriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/MergeAggregatingResultsRewriter.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/MergeAggregatingResultsRewriter.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -53,9 +53,14 @@ } else if (resultOperator is CountResultOperator) { - queryModel.SelectClause.Selector = new NhCountExpression(queryModel.SelectClause.Selector); + queryModel.SelectClause.Selector = new NhShortCountExpression(queryModel.SelectClause.Selector); queryModel.ResultOperators.Remove(resultOperator); } + else if (resultOperator is LongCountResultOperator) + { + queryModel.SelectClause.Selector = new NhLongCountExpression(queryModel.SelectClause.Selector); + queryModel.ResultOperators.Remove(resultOperator); + } base.VisitResultOperator(resultOperator, queryModel, index); } @@ -89,7 +94,7 @@ { case "Count": return CreateAggregate(m.Arguments[0], (LambdaExpression)m.Arguments[1], - e => new NhCountExpression(e)); + e => new NhShortCountExpression(e)); case "Min": return CreateAggregate(m.Arguments[0], (LambdaExpression) m.Arguments[1], e => new NhMinExpression(e)); Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -25,7 +25,7 @@ { if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) { - _parameters.Add(expression, new NamedParameter("p" + (_parameters.Count + 1), expression.Value)); + _parameters.Add(expression, new NamedParameter("p" + (_parameters.Count + 1), expression.Value, NHibernateUtil.GuessType(expression.Type))); } return base.VisitConstantExpression(expression); Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -201,8 +201,31 @@ _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(rhs, _hqlTreeBuilder.Constant(1)) }, _hqlTreeBuilder.Constant(0)); + + return _hqlTreeBuilder.Equality(lhs, rhs); } + // Also check for nullability + if (expression.Left.Type.IsNullable() || expression.Right.Type.IsNullable()) + { + // TODO - yuck. This clone is needed because the AST tree nodes are not immutable, + // and sharing nodes between multiple branches will cause issues in the hqlSqlWalker phase - + // a node, x, gets visited during the walk and updated to refer to a real property. Later in + // the walk, x get revisited (since we copied it here), but now the type doesn't match what + // the parser expects. So we can't share. Implementing Clone() on HqlTreeNode would be better + // that doing a full visit of the Expression tree. Allowing shared nodes in the AST would be better + // still, but might be more work + var lhs2 = VisitExpression(expression.Left).AsExpression(); + var rhs2 = VisitExpression(expression.Right).AsExpression(); + + return _hqlTreeBuilder.BooleanOr( + _hqlTreeBuilder.BooleanAnd( + _hqlTreeBuilder.IsNull(lhs), + _hqlTreeBuilder.IsNull(rhs)), + _hqlTreeBuilder.Equality(lhs2, rhs2) + ); + } + return _hqlTreeBuilder.Equality(lhs, rhs); case ExpressionType.NotEqual: @@ -218,8 +241,32 @@ _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(rhs, _hqlTreeBuilder.Constant(1)) }, _hqlTreeBuilder.Constant(0)); + + return _hqlTreeBuilder.Inequality(lhs, rhs); + } + // Also check for nullability + if (expression.Left.Type.IsNullable() || expression.Right.Type.IsNullable()) + { + var lhs2 = VisitExpression(expression.Left).AsExpression(); + var rhs2 = VisitExpression(expression.Right).AsExpression(); + var lhs3 = VisitExpression(expression.Left).AsExpression(); + var rhs3 = VisitExpression(expression.Right).AsExpression(); + + return + _hqlTreeBuilder.BooleanOr( + _hqlTreeBuilder.BooleanOr( + _hqlTreeBuilder.BooleanAnd( + _hqlTreeBuilder.IsNull(lhs), + _hqlTreeBuilder.IsNotNull(rhs)), + _hqlTreeBuilder.BooleanAnd( + _hqlTreeBuilder.IsNotNull(lhs2), + _hqlTreeBuilder.IsNull(rhs2)) + ), + _hqlTreeBuilder.Inequality(lhs3, rhs3)); + } + return _hqlTreeBuilder.Inequality(lhs, rhs); case ExpressionType.And: Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -69,7 +69,7 @@ { Expression nx = base.VisitExpression(expression.Expression); - return nx != expression.Expression ? new NhCountExpression(nx) : expression; + return nx != expression.Expression ? new NhShortCountExpression(nx) : expression; } protected virtual Expression VisitNhSum(NhSumExpression expression) Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/NhThrowingExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/NhThrowingExpressionTreeVisitor.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/NhThrowingExpressionTreeVisitor.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -85,7 +85,7 @@ { Expression nx = base.VisitExpression(expression.Expression); - return nx != expression.Expression ? new NhCountExpression(nx) : expression; + return nx != expression.Expression ? new NhCountExpression(nx, expression.Type) : expression; } protected virtual Expression BaseVisitNhSum(NhSumExpression expression) Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -9,6 +9,7 @@ using NHibernate.Linq.GroupJoin; using NHibernate.Linq.ResultOperators; using NHibernate.Linq.ReWriters; +using NHibernate.Type; using Remotion.Data.Linq; using Remotion.Data.Linq.Clauses; using Remotion.Data.Linq.Clauses.Expressions; @@ -49,7 +50,7 @@ private readonly HqlTreeBuilder _hqlTreeBuilder; - private readonly List<Action<IQuery, IDictionary<string, object>>> _additionalCriteria = new List<Action<IQuery, IDictionary<string, object>>>(); + private readonly List<Action<IQuery, IDictionary<string, Pair<object, IType>>>> _additionalCriteria = new List<Action<IQuery, IDictionary<string, Pair<object, IType>>>>(); private readonly List<LambdaExpression> _listTransformers = new List<LambdaExpression>(); private readonly List<LambdaExpression> _itemTransformers = new List<LambdaExpression>(); @@ -200,6 +201,10 @@ { ProcessGroupByOperator((GroupResultOperator)resultOperator); } + else if (resultOperator is SingleResultOperator) + { + ProcessSingleOperator((SingleResultOperator) resultOperator); + } else { throw new NotSupportedException(string.Format("The {0} result operator is not current supported", @@ -207,6 +212,23 @@ } } + private void ProcessSingleOperator(SingleResultOperator resultOperator) + { + Expression<Func<IEnumerable<object>, object>> lambda; + + if (resultOperator.ReturnDefaultWhenEmpty) + { + lambda = (IEnumerable<object> list) => list.SingleOrDefault(); + } + else + { + lambda = (IEnumerable<object> list) => list.Single(); + } + + _additionalCriteria.Add((q, p) => q.SetMaxResults(1)); + _listTransformers.Add(lambda); + } + private void ProcessClientSideResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel) { if (resultOperator is NonAggregatingGroupBy) @@ -307,7 +329,7 @@ // clause to see if it is valid if (_parameters.TryGetValue(resultOperator.Count as ConstantExpression, out parameterName)) { - _additionalCriteria.Add((q, p) => q.SetMaxResults((int) p[parameterName.Name])); + _additionalCriteria.Add((q, p) => q.SetMaxResults((int) p[parameterName.Name].Left)); } else { @@ -321,7 +343,7 @@ if (_parameters.TryGetValue(resultOperator.Count as ConstantExpression, out parameterName)) { - _additionalCriteria.Add((q, p) => q.SetFirstResult((int)p[parameterName.Name])); + _additionalCriteria.Add((q, p) => q.SetFirstResult((int)p[parameterName.Name].Left)); } else { @@ -389,19 +411,6 @@ _listTransformers.Add(lambdaExpr); return; - /* - _listTransformers.Add(Expression.Lambda( - Expression.Call(toList, - Expression.Call(groupByMethod, - Expression.Call(castToItem, - Expression.Call(selectObject, - Expression.Call( - castToObjectArray, - listParameter), - index)), - keySelectorExpr) - ), - listParameter));*/ } private static System.Type SourceOf(Expression keySelector) Modified: trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -3538,7 +3538,7 @@ orderLine = new OrderLine { Order = orders.Where(o => o.OrderId == 11077 ).First(), Product = products.Where(p => p.Name == "Original Frankfurter grüne Soße").First(), UnitPrice = 13.00M, Quantity = 2, Discount = 0M }; session.Insert(orderLine); } - protected override void OnFixtureSetup() + protected override void OnFixtureSetup() { CreateTestData(); } Modified: trunk/nhibernate/src/NHibernate.Test/Linq/ParameterisedQueries.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/ParameterisedQueries.cs 2009-11-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate.Test/Linq/ParameterisedQueries.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -50,8 +50,8 @@ Assert.AreEqual(nhLondon.Key, nhNewYork.Key); Assert.AreEqual(1, nhLondon.ParameterValuesByName.Count); Assert.AreEqual(1, nhNewYork.ParameterValuesByName.Count); - Assert.AreEqual("London", nhLondon.ParameterValuesByName.First().Value); - Assert.AreEqual("New York", nhNewYork.ParameterValuesByName.First().Value); + Assert.AreEqual("London", nhLondon.ParameterValuesByName.First().Value.Left); + Assert.AreEqual("New York", nhNewYork.ParameterValuesByName.First().Value.Left); } } Added: trunk/nhibernate/src/NHibernate.Test/Linq/ProjectionsTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/ProjectionsTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/ProjectionsTests.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class ProjectionsTests : LinqTestCase + { + [Test] + public void ProjectAnonymousTypeWithWhere() + { + var query = (from user in db.Users + where user.Name == "ayende" + select user.Name) + .First(); + Assert.AreEqual("ayende", query); + } + + + [Test] + public void ProjectConditionals() + { + var query = (from user in db.Users + orderby user.Id + select new { user.Id, GreaterThan2 = user.Id > 2 ? "Yes" : "No" }) + .ToList(); + Assert.AreEqual("No", query[0].GreaterThan2); + Assert.AreEqual("No", query[1].GreaterThan2); + Assert.AreEqual("Yes", query[2].GreaterThan2); + } + + [Test] + public void ProjectAnonymousTypeWithMultiply() + { + var query = (from user in db.Users + select new { user.Name, user.Id, Id2 = user.Id * 2 }) + .ToList(); + Assert.AreEqual(3, query.Count); + foreach (var user in query) + { + Assert.AreEqual(user.Id * 2, user.Id2); + } + } + + [Test] + public void ProjectAnonymousTypeWithSubstraction() + { + var query = (from user in db.Users + select new { user.Name, user.Id, Id2 = user.Id - 2 }) + .ToList(); + Assert.AreEqual(3, query.Count); + foreach (var user in query) + { + Assert.AreEqual(user.Id - 2, user.Id2); + } + } + + [Test] + public void ProjectAnonymousTypeWithDivision() + { + var query = (from user in db.Users + select new { user.Name, user.Id, Id2 = (user.Id * 10) / 2 }) + .ToList(); + Assert.AreEqual(3, query.Count); + foreach (var user in query) + { + Assert.AreEqual((user.Id * 10) / 2, user.Id2); + } + } + + [Test] + public void ProjectAnonymousTypeWithAddition() + { + var query = (from user in db.Users + select new { user.Name, user.Id, Id2 = (user.Id + 101) }) + .ToList(); + Assert.AreEqual(3, query.Count); + foreach (var user in query) + { + Assert.AreEqual((user.Id + 101), user.Id2); + } + } + + [Test] + public void ProjectAnonymousTypeAndConcatenateFields() + { + var query = (from user in db.Users + orderby user.Name + select new { DoubleName = user.Name + " " + user.Name, user.RegisteredAt } + + ) + .ToList(); + + Assert.AreEqual("ayende ayende", query[0].DoubleName); + Assert.AreEqual("nhibernate nhibernate", query[1].DoubleName); + Assert.AreEqual("rahien rahien", query[2].DoubleName); + + + Assert.AreEqual(DateTime.Today, query[0].RegisteredAt); + Assert.AreEqual(new DateTime(2000, 1, 1), query[1].RegisteredAt); + Assert.AreEqual(new DateTime(1998, 12, 31), query[2].RegisteredAt); + } + + [Test] + public void ProjectKnownType() + { + var query = (from user in db.Users + orderby user.Id + select new KeyValuePair<string, DateTime>(user.Name, user.RegisteredAt)) + .ToList(); + + Assert.AreEqual("ayende", query[0].Key); + Assert.AreEqual("rahien", query[1].Key); + Assert.AreEqual("nhibernate", query[2].Key); + + + Assert.AreEqual(DateTime.Today, query[0].Value); + Assert.AreEqual(new DateTime(1998, 12, 31), query[1].Value); + Assert.AreEqual(new DateTime(2000, 1, 1), query[2].Value); + } + + [Test] + public void ProjectAnonymousType() + { + var query = (from user in db.Users + orderby user.Id + select new { user.Name, user.RegisteredAt }) + .ToList(); + Assert.AreEqual("ayende", query[0].Name); + Assert.AreEqual("rahien", query[1].Name); + Assert.AreEqual("nhibernate", query[2].Name); + + + Assert.AreEqual(DateTime.Today, query[0].RegisteredAt); + Assert.AreEqual(new DateTime(1998, 12, 31), query[1].RegisteredAt); + Assert.AreEqual(new DateTime(2000, 1, 1), query[2].RegisteredAt); + } + + [Test] + public void ProjectUserNames() + { + var query = (from user in db.Users + select user.Name).ToList(); + Assert.AreEqual(3, query.Count); + Assert.AreEqual(3, query.Intersect(new[] { "ayende", "rahien", "nhibernate" }) + .ToList().Count); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Linq/PropertyMethodMappingTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/PropertyMethodMappingTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/PropertyMethodMappingTests.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -0,0 +1,30 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class PropertyMethodMappingTests : LinqTestCase + { + [Test] + public void CanExecuteCountInSelectClause() + { + var results = db.Timesheets + .Select(t => t.Entries.Count).ToList(); + + Assert.AreEqual(3, results.Count); + Assert.AreEqual(0, results[0]); + Assert.AreEqual(2, results[1]); + Assert.AreEqual(4, results[2]); + } + + [Test] + public void CanExecuteCountInWhereClause() + { + var results = db.Timesheets + .Where(t => t.Entries.Count >= 2).ToList(); + + Assert.AreEqual(2, results.Count); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Linq/QueryReuseTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/QueryReuseTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/QueryReuseTests.cs 2009-11-27 20:10:47 UTC (rev 4861) @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NHibernate.Test.Linq.Entities; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class QueryReuseTests : LinqTestCase + { + private IQueryable<User> _query; + + protected override void OnSetUp() + { + base.OnSetUp(); + + _query = db.Users; + } + + private void AssertQueryReuseable(IQueryable<User> query) + { + IList<User> users = _query.ToList(); + Assert.AreEqual(3, users.Count); + } + + [Test] + public void CanReuseAfterFirst() + { + User user = _query.First(u => u.Name == "rahien"); + + Assert.IsNotNull(user); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterFirstOrDefault() + { + User user = _query.FirstOrDefault(u => u.Name == "rahien"); + + Assert.IsNotNull(user); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterSingle() + { + User user = _query.Single(u => u.Name == "rahien"); + + Assert.IsNotNull(user); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterSingleOrDefault() + { + User user = _query.SingleOrDefault(u => u.Name == "rahien"); + + Assert.IsNotNull(user); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterAggregate() + { + User user = _query.Aggregate((u1, u2) => u1); + + Assert.IsNotNull(user); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterAverage() + { + double average = _query.Average(u => u.InvalidLoginAttempts); + + Assert.AreEqual(5.0, average); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterCount() + { + int totalCount = _query.Count(); + + Assert.AreEqual(3, totalCount); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterCountWithPredicate() + { + int count = _query.Count(u => u.LastLoginDate != null); + + Assert.AreEqual(1, count); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterLongCount() + { + long totalCount = _query.LongCount(); + + Assert.AreEqual(3, totalCount); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterLongCountWithPredicate() + { + long totalCount = _query.LongCount(u => u.LastLoginDate != null); + + Assert.AreEqual(1, totalCount); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterMax() + { + int max = _query.Max(u => u.InvalidLoginAttempts); + + Assert.AreEqual(6, max); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterMin() + { + int min = _query.Min(u => u.InvalidLoginAttempts); + + Assert.AreEqual(4, min); + AssertQueryReuseable(_query); + } + + [Test] + public void CanReuseAfterSum() + { + int sum = _query.Sum(u => u.InvalidLoginAttempts); + + Assert.AreEqual(4 + 5 + 6, sum); + AssertQueryReuseable(_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-27 18:12:00 UTC (rev 4860) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-11-27 20:10:47 UTC (rev 4861) @@ -417,6 +417,9 @@ <Compile Include="Linq\PagingTests.cs" /> <Compile Include="Linq\ParameterisedQueries.cs" /> <Compile Include="Linq\PatientTests.cs" /> + <Compile Include="Linq\ProjectionsTests.cs" /> + <Compile Include="Linq\PropertyMethodMappingTests.cs" /> + <Compile Include="Linq\QueryReuseTests.cs" /> <Compile Include="Linq\ReadonlyTestCase.cs" /> <Compile Include="MappingTest\NonReflectiveBinderFixture.cs" /> <Compile Include="MappingTest\Wicked.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2009-11-28 12:00:53
|
Revision: 4862 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4862&view=rev Author: fabiomaulo Date: 2009-11-28 12:00:44 +0000 (Sat, 28 Nov 2009) Log Message: ----------- - Starting refactoring of binders - bug fixed for <meta> (the default inherit is true) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmMapping.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/Binder.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/MappingRootBinder.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs trunk/nhibernate/src/NHibernate.Test/MappingTest/Wicked.hbm.xml Added Paths: ----------- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/IEntityMetadata.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmMapping.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmMapping.cs 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmMapping.cs 2009-11-28 12:00:44 UTC (rev 4862) @@ -1,3 +1,5 @@ +using System.Linq; + namespace NHibernate.Cfg.MappingSchema { partial class HbmMapping : AbstractDecoratable @@ -16,5 +18,25 @@ { return meta; } + + public HbmClass[] RootClasses + { + get { return Items != null ? Items.OfType<HbmClass>().ToArray():new HbmClass[0]; } + } + + public HbmSubclass[] SubClasses + { + get { return Items != null ? Items.OfType<HbmSubclass>().ToArray(): new HbmSubclass[0]; } + } + + public HbmJoinedSubclass[] JoinedSubclasses + { + get { return Items != null ? Items.OfType<HbmJoinedSubclass>().ToArray(): new HbmJoinedSubclass[0]; } + } + + public HbmUnionSubclass[] UnionSubclasses + { + get { return Items != null ? Items.OfType<HbmUnionSubclass>().ToArray(): new HbmUnionSubclass[0]; } + } } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/IEntityMetadata.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/IEntityMetadata.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/IEntityMetadata.cs 2009-11-28 12:00:44 UTC (rev 4862) @@ -0,0 +1,7 @@ +namespace NHibernate.Cfg.MappingSchema +{ + public interface IEntityMetadata + { + + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/Binder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/Binder.cs 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/Binder.cs 2009-11-28 12:00:44 UTC (rev 4862) @@ -142,6 +142,24 @@ return (T) new XmlSerializer(typeof (T)).Deserialize(reader); } + protected static XmlNode Serialize<T>(T hbmElement) + { + // TODO : this method is only for TEMPORAL usage; should be removed after refactorize all binders + var serializer = new XmlSerializer(typeof (T)); + using (var memStream = new MemoryStream(2000)) + using (var xmlWriter = XmlWriter.Create(memStream)) + { + serializer.Serialize(xmlWriter, hbmElement); + memStream.Position = 0; + using (XmlReader reader = XmlReader.Create(memStream)) + { + var hbmDocument = new XmlDocument(); + hbmDocument.Load(reader); + return hbmDocument.DocumentElement; + } + } + } + protected static string GetXmlEnumAttribute(Enum cascadeStyle) { MemberInfo[] memberInfo = cascadeStyle.GetType().GetMember(cascadeStyle.ToString()); @@ -231,7 +249,7 @@ continue; } var inheritableValue = GetAttributeValue(metaNode, "inherit"); - bool inheritable = inheritableValue != null ? IsTrue(inheritableValue) : false; + bool inheritable = inheritableValue != null ? IsTrue(inheritableValue) : true; if (onlyInheritable & !inheritable) { continue; Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/MappingRootBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/MappingRootBinder.cs 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/MappingRootBinder.cs 2009-11-28 12:00:44 UTC (rev 4862) @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Xml; @@ -32,10 +33,7 @@ AddFilterDefinitions(mappingSchema); AddTypeDefs(mappingSchema); - AddRootClasses(node, inheritedMetas); - AddSubclasses(node, inheritedMetas); - AddJoinedSubclasses(node, inheritedMetas); - AddUnionSubclasses(node, inheritedMetas); + AddEntitiesMappings(node, mappingSchema, inheritedMetas); AddQueries(mappingSchema); AddSqlQueries(mappingSchema); @@ -44,6 +42,26 @@ AddResultSetMappingDefinitions(mappingSchema); } + private void AddEntitiesMappings(XmlNode node, HbmMapping mappingSchema, IDictionary<string, MetaAttribute> inheritedMetas) + { + foreach (var rootClass in mappingSchema.RootClasses) + { + AddRootClasses(Serialize(rootClass), rootClass, inheritedMetas); + } + foreach (var subclass in mappingSchema.SubClasses) + { + AddSubclasses(Serialize(subclass), subclass, inheritedMetas); + } + foreach (var joinedSubclass in mappingSchema.JoinedSubclasses) + { + AddJoinedSubclasses(Serialize(joinedSubclass), joinedSubclass, inheritedMetas); + } + foreach (var unionSubclass in mappingSchema.UnionSubclasses) + { + AddUnionSubclasses(Serialize(unionSubclass), unionSubclass, inheritedMetas); + } + } + private void SetMappingsProperties(HbmMapping mappingSchema) { mappings.SchemaName = mappingSchema.schema; @@ -65,36 +83,32 @@ } } - private void AddRootClasses(XmlNode parentNode, IDictionary<string, MetaAttribute> inheritedMetas) + private void AddRootClasses(XmlNode parentNode, HbmClass rootClass, IDictionary<string, MetaAttribute> inheritedMetas) { RootClassBinder binder = new RootClassBinder(this, namespaceManager, dialect); - foreach (XmlNode node in parentNode.SelectNodes(HbmConstants.nsClass, namespaceManager)) - binder.Bind(node, Deserialize<HbmClass>(node), inheritedMetas); + binder.Bind(parentNode, rootClass, inheritedMetas); } - private void AddUnionSubclasses(XmlNode parentNode, IDictionary<string, MetaAttribute> inheritedMetas) + private void AddUnionSubclasses(XmlNode parentNode, HbmUnionSubclass unionSubclass, IDictionary<string, MetaAttribute> inheritedMetas) { UnionSubclassBinder binder = new UnionSubclassBinder(this, namespaceManager, dialect); - foreach (XmlNode node in parentNode.SelectNodes(HbmConstants.nsUnionSubclass, namespaceManager)) - binder.Bind(node, inheritedMetas); + binder.Bind(parentNode, inheritedMetas); } - private void AddJoinedSubclasses(XmlNode parentNode, IDictionary<string, MetaAttribute> inheritedMetas) + private void AddJoinedSubclasses(XmlNode parentNode, HbmJoinedSubclass joinedSubclass, IDictionary<string, MetaAttribute> inheritedMetas) { JoinedSubclassBinder binder = new JoinedSubclassBinder(this, namespaceManager, dialect); - foreach (XmlNode node in parentNode.SelectNodes(HbmConstants.nsJoinedSubclass, namespaceManager)) - binder.Bind(node, inheritedMetas); + binder.Bind(parentNode, inheritedMetas); } - private void AddSubclasses(XmlNode parentNode, IDictionary<string, MetaAttribute> inheritedMetas) + private void AddSubclasses(XmlNode parentNode, HbmSubclass subClass, IDictionary<string, MetaAttribute> inheritedMetas) { SubclassBinder binder = new SubclassBinder(this, namespaceManager, dialect); - foreach (XmlNode node in parentNode.SelectNodes(HbmConstants.nsSubclass, namespaceManager)) - binder.Bind(node, inheritedMetas); + binder.Bind(parentNode, inheritedMetas); } private void AddQueries(HbmMapping mappingSchema) Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-11-28 12:00:44 UTC (rev 4862) @@ -495,6 +495,7 @@ <Compile Include="Cfg\Loquacious\MappingsConfiguration.cs" /> <Compile Include="Cfg\Loquacious\ProxyConfiguration.cs" /> <Compile Include="Cfg\MappingSchema\HbmDefinition.cs" /> + <Compile Include="Cfg\MappingSchema\IEntityMetadata.cs" /> <Compile Include="Cfg\SchemaAutoAction.cs" /> <Compile Include="Cfg\SessionFactoryConfigurationBase.cs" /> <Compile Include="Cfg\ISessionFactoryConfiguration.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs 2009-11-28 12:00:44 UTC (rev 4862) @@ -157,7 +157,7 @@ Assert.That(propertyAttribute.Value, Is.EqualTo("monetaryamount anotherSet composite property empinone level")); } - [Test] + [Test, Ignore("Not fixed, see the TODO of this test.")] public void Comparator() { PersistentClass cm = cfg.GetClassMapping("NHibernate.Test.MappingTest.Wicked"); Modified: trunk/nhibernate/src/NHibernate.Test/MappingTest/Wicked.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingTest/Wicked.hbm.xml 2009-11-27 20:10:47 UTC (rev 4861) +++ trunk/nhibernate/src/NHibernate.Test/MappingTest/Wicked.hbm.xml 2009-11-28 12:00:44 UTC (rev 4862) @@ -30,7 +30,8 @@ </property> </component> - <set name="SortedEmployee" sort="NonExistingComparator"> + <!--<set name="SortedEmployee" sort="NonExistingComparator">--> + <set name="SortedEmployee"> <meta attribute="globalmutated">sortedemployee level</meta> <key column="attrb_id"/> <many-to-many class="Employee" column="id"/> @@ -71,7 +72,7 @@ <property name="Pregnant"/> <property name="Birthdate" type="Date"/> <subclass name="DomesticAnimal"> - <meta attribute="Auditable"/> + <meta attribute="Auditable" inherit="true"/> <property name="Name"/> <many-to-one name="Owner"/> <subclass name="Cat"/> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2009-11-28 21:09:32
|
Revision: 4868 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4868&view=rev Author: ricbrown Date: 2009-11-28 21:09:24 +0000 (Sat, 28 Nov 2009) Log Message: ----------- Expanded IQueryOver to maintain both the original, and sub-criteria types. Modified Paths: -------------- 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/QueryOverProjectionBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs trunk/nhibernate/src/NHibernate/IQueryOver.cs trunk/nhibernate/src/NHibernate/ISession.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/Model.cs trunk/nhibernate/src/NHibernate.Test/Criteria/Lambda/QueryOverFixture.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverFetchBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,29 +9,29 @@ namespace NHibernate.Criterion { - public class QueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<QueryOver<T>, T> + public class QueryOverFetchBuilder<S,T> : QueryOverFetchBuilderBase<QueryOver<S,T>, S, T> { - public QueryOverFetchBuilder(QueryOver<T> root, Expression<Func<T, object>> path) + public QueryOverFetchBuilder(QueryOver<S,T> root, Expression<Func<S, object>> path) : base(root, path) { } } - public class IQueryOverFetchBuilder<T> : QueryOverFetchBuilderBase<IQueryOver<T>, T> + public class IQueryOverFetchBuilder<S,T> : QueryOverFetchBuilderBase<IQueryOver<S,T>, S, T> { - public IQueryOverFetchBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) + public IQueryOverFetchBuilder(IQueryOver<S,T> root, Expression<Func<S, object>> path) : base(root, path) { } } - public class QueryOverFetchBuilderBase<R, T> where R : IQueryOver<T> + public class QueryOverFetchBuilderBase<R, S, T> where R : IQueryOver<S,T> { protected R root; protected string path; - protected QueryOverFetchBuilderBase(R root, Expression<Func<T, object>> path) + protected QueryOverFetchBuilderBase(R root, Expression<Func<S, object>> path) { this.root = root; this.path = ExpressionProcessor.FindMemberExpression(path.Body); Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverJoinBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -8,100 +8,100 @@ namespace NHibernate.Criterion.Lambda { - - public class QueryOverJoinBuilder<T> : QueryOverJoinBuilderBase<QueryOver<T>, T> + + public class QueryOverJoinBuilder<S,T> : QueryOverJoinBuilderBase<QueryOver<S,T>, S, T> { - public QueryOverJoinBuilder(QueryOver<T> root, JoinType joinType) : base(root, joinType) { } + public QueryOverJoinBuilder(QueryOver<S,T> root, JoinType joinType) : base(root, joinType) { } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) + public QueryOver<S,U> JoinQueryOver<U>(Expression<Func<T, U>> path) { return root.JoinQueryOver<U>(path, joinType); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + public QueryOver<S,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) + public QueryOver<S,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) + public QueryOver<S,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) + public QueryOver<S,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) + public QueryOver<S,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) + public QueryOver<S,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) + public QueryOver<S,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 class IQueryOverJoinBuilder<S,T> : QueryOverJoinBuilderBase<IQueryOver<S,T>, S, T> { - public IQueryOverJoinBuilder(IQueryOver<T> root, JoinType joinType) : base(root, joinType) { } + public IQueryOverJoinBuilder(IQueryOver<S,T> root, JoinType joinType) : base(root, joinType) { } - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) + public IQueryOver<S,U> JoinQueryOver<U>(Expression<Func<T, U>> path) { return root.JoinQueryOver<U>(path, joinType); } - public IQueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + public IQueryOver<S,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) + public IQueryOver<S,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) + public IQueryOver<S,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) + public IQueryOver<S,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) + public IQueryOver<S,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) + public IQueryOver<S,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) + public IQueryOver<S,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> + public class QueryOverJoinBuilderBase<R, S, T> where R : IQueryOver<S,T> { protected R root; Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverLockBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,23 +9,23 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverLockBuilder<T> : QueryOverLockBuilderBase<QueryOver<T>, T> + public class QueryOverLockBuilder<S,T> : QueryOverLockBuilderBase<QueryOver<S,T>, S, T> { - public QueryOverLockBuilder(QueryOver<T> root, Expression<Func<object>> alias) + public QueryOverLockBuilder(QueryOver<S,T> root, Expression<Func<object>> alias) : base(root, alias) { } } - public class IQueryOverLockBuilder<T> : QueryOverLockBuilderBase<IQueryOver<T>, T> + public class IQueryOverLockBuilder<S,T> : QueryOverLockBuilderBase<IQueryOver<S,T>, S, T> { - public IQueryOverLockBuilder(IQueryOver<T> root, Expression<Func<object>> alias) + public IQueryOverLockBuilder(IQueryOver<S,T> root, Expression<Func<object>> alias) : base(root, alias) { } } - public class QueryOverLockBuilderBase<R, T> where R : IQueryOver<T> + public class QueryOverLockBuilderBase<R, S, T> where R : IQueryOver<S,T> { protected R root; Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverOrderBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,29 +9,29 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<QueryOver<T>, T> + public class QueryOverOrderBuilder<S,T> : QueryOverOrderBuilderBase<QueryOver<S,T>, S, T> { - public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) + public QueryOverOrderBuilder(QueryOver<S,T> root, Expression<Func<T, object>> path) : base(root, path) {} - public QueryOverOrderBuilder(QueryOver<T> root, Expression<Func<object>> path) : base(root, path) + public QueryOverOrderBuilder(QueryOver<S,T> root, Expression<Func<object>> path) : base(root, path) {} } - public class IQueryOverOrderBuilder<T> : QueryOverOrderBuilderBase<IQueryOver<T>, T> + public class IQueryOverOrderBuilder<S,T> : QueryOverOrderBuilderBase<IQueryOver<S,T>, S, T> { - public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<T, object>> path) : base(root, path) + public IQueryOverOrderBuilder(IQueryOver<S,T> root, Expression<Func<T, object>> path) : base(root, path) {} - public IQueryOverOrderBuilder(IQueryOver<T> root, Expression<Func<object>> path) : base(root, path) + public IQueryOverOrderBuilder(IQueryOver<S,T> root, Expression<Func<object>> path) : base(root, path) {} } - public class QueryOverOrderBuilderBase<R, T> where R : IQueryOver<T> + public class QueryOverOrderBuilderBase<R, S, T> where R : IQueryOver<S, T> { protected R root; Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverProjectionBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,15 +9,15 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverProjectionBuilder<R, T> + public class QueryOverProjectionBuilder<R, S, T> { private R fluentReturn; - private IQueryOver<T> criteria; + private IQueryOver<S,T> criteria; private ProjectionList projectionList; private IProjection lastProjection = null; - public QueryOverProjectionBuilder(R fluentReturn, IQueryOver<T> criteria) + public QueryOverProjectionBuilder(R fluentReturn, IQueryOver<S,T> criteria) { this.fluentReturn = fluentReturn; this.criteria = criteria; @@ -52,7 +52,7 @@ /// <summary> /// Create an alias for the previous projection /// </summary> - public QueryOverProjectionBuilder<R, T> WithAlias(Expression<Func<object>> alias) + public QueryOverProjectionBuilder<R, S, T> WithAlias(Expression<Func<object>> alias) { string aliasContainer = ExpressionProcessor.FindMemberExpression(alias.Body); lastProjection = Projections.Alias(lastProjection, aliasContainer); @@ -62,7 +62,7 @@ /// <summary> /// Select an arbitrary projection /// </summary> - public QueryOverProjectionBuilder<R, T> Select(IProjection projection) + public QueryOverProjectionBuilder<R, S, T> Select(IProjection projection) { PushProjection(projection); return this; @@ -71,7 +71,7 @@ /// <summary> /// A property average value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectAvg(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectAvg(Expression<Func<T, object>> expression) { PushProjection(Projections.Avg(expression)); return this; @@ -80,7 +80,7 @@ /// <summary> /// A property average value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectAvg(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectAvg(Expression<Func<object>> expression) { PushProjection(Projections.Avg(expression)); return this; @@ -89,7 +89,7 @@ /// <summary> /// A property value count /// </summary> - public QueryOverProjectionBuilder<R, T> SelectCount(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectCount(Expression<Func<T, object>> expression) { PushProjection(Projections.Count(expression)); return this; @@ -98,7 +98,7 @@ /// <summary> /// A property value count /// </summary> - public QueryOverProjectionBuilder<R, T> SelectCount(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectCount(Expression<Func<object>> expression) { PushProjection(Projections.Count(expression)); return this; @@ -107,7 +107,7 @@ /// <summary> /// A distinct property value count /// </summary> - public QueryOverProjectionBuilder<R, T> SelectCountDistinct(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectCountDistinct(Expression<Func<T, object>> expression) { PushProjection(Projections.CountDistinct(expression)); return this; @@ -116,7 +116,7 @@ /// <summary> /// A distinct property value count /// </summary> - public QueryOverProjectionBuilder<R, T> SelectCountDistinct(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectCountDistinct(Expression<Func<object>> expression) { PushProjection(Projections.CountDistinct(expression)); return this; @@ -125,7 +125,7 @@ /// <summary> /// A grouping property value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectGroup(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectGroup(Expression<Func<T, object>> expression) { PushProjection(Projections.Group(expression)); return this; @@ -134,7 +134,7 @@ /// <summary> /// A grouping property value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectGroup(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectGroup(Expression<Func<object>> expression) { PushProjection(Projections.Group(expression)); return this; @@ -143,7 +143,7 @@ /// <summary> /// A property maximum value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectMax(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectMax(Expression<Func<T, object>> expression) { PushProjection(Projections.Max(expression)); return this; @@ -152,7 +152,7 @@ /// <summary> /// A property maximum value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectMax(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectMax(Expression<Func<object>> expression) { PushProjection(Projections.Max(expression)); return this; @@ -161,7 +161,7 @@ /// <summary> /// A property minimum value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectMin(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectMin(Expression<Func<T, object>> expression) { PushProjection(Projections.Min(expression)); return this; @@ -170,7 +170,7 @@ /// <summary> /// A property minimum value /// </summary> - public QueryOverProjectionBuilder<R, T> SelectMin(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectMin(Expression<Func<object>> expression) { PushProjection(Projections.Min(expression)); return this; @@ -179,7 +179,7 @@ /// <summary> /// A projected property value /// </summary> - public QueryOverProjectionBuilder<R, T> Select(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> Select(Expression<Func<T, object>> expression) { PushProjection(Projections.Property(expression)); return this; @@ -188,13 +188,13 @@ /// <summary> /// A projected property value /// </summary> - public QueryOverProjectionBuilder<R, T> Select(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> Select(Expression<Func<object>> expression) { PushProjection(Projections.Property(expression)); return this; } - public QueryOverProjectionBuilder<R, T> SelectSubQuery<U>(QueryOver<U> detachedQueryOver) + public QueryOverProjectionBuilder<R, S, T> SelectSubQuery<U>(QueryOver<U> detachedQueryOver) { PushProjection(Projections.SubQuery(detachedQueryOver)); return this; @@ -203,7 +203,7 @@ /// <summary> /// A property value sum /// </summary> - public QueryOverProjectionBuilder<R, T> SelectSum(Expression<Func<T, object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectSum(Expression<Func<T, object>> expression) { PushProjection(Projections.Sum(expression)); return this; @@ -212,7 +212,7 @@ /// <summary> /// A property value sum /// </summary> - public QueryOverProjectionBuilder<R, T> SelectSum(Expression<Func<object>> expression) + public QueryOverProjectionBuilder<R, S, T> SelectSum(Expression<Func<object>> expression) { PushProjection(Projections.Sum(expression)); return this; Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverRestrictionBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -10,24 +10,24 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverRestrictionBuilder<T> : QueryOverRestrictionBuilderBase<QueryOver<T>, T> + public class QueryOverRestrictionBuilder<S,T> : QueryOverRestrictionBuilderBase<QueryOver<S,T>, S, T> { - public QueryOverRestrictionBuilder(QueryOver<T> root, string propertyName) + public QueryOverRestrictionBuilder(QueryOver<S,T> root, string propertyName) : base(root, propertyName) { } } - public class IQueryOverRestrictionBuilder<T> : QueryOverRestrictionBuilderBase<IQueryOver<T>, T> + public class IQueryOverRestrictionBuilder<S,T> : QueryOverRestrictionBuilderBase<IQueryOver<S,T>, S, T> { - public IQueryOverRestrictionBuilder(IQueryOver<T> root, string propertyName) + public IQueryOverRestrictionBuilder(IQueryOver<S,T> root, string propertyName) : base(root, propertyName) { } } - public class QueryOverRestrictionBuilderBase<R, T> - where R : IQueryOver<T> + public class QueryOverRestrictionBuilderBase<R,S,T> + where R : IQueryOver<S,T> { public class LambdaBetweenBuilder { Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,25 +9,25 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverSubqueryBuilder<T> : QueryOverSubqueryBuilderBase<QueryOver<T>, T, QueryOverSubqueryPropertyBuilder<T>> + public class QueryOverSubqueryBuilder<S,T> : QueryOverSubqueryBuilderBase<QueryOver<S,T>, S, T, QueryOverSubqueryPropertyBuilder<S,T>> { - public QueryOverSubqueryBuilder(QueryOver<T> root) + public QueryOverSubqueryBuilder(QueryOver<S,T> root) : base(root) { } } - public class IQueryOverSubqueryBuilder<T> : QueryOverSubqueryBuilderBase<IQueryOver<T>, T, IQueryOverSubqueryPropertyBuilder<T>> + public class IQueryOverSubqueryBuilder<S,T> : QueryOverSubqueryBuilderBase<IQueryOver<S,T>, S, T, IQueryOverSubqueryPropertyBuilder<S,T>> { - public IQueryOverSubqueryBuilder(IQueryOver<T> root) + public IQueryOverSubqueryBuilder(IQueryOver<S,T> root) : base(root) { } } - public class QueryOverSubqueryBuilderBase<R, T, S> - where R : IQueryOver<T> - where S : QueryOverSubqueryPropertyBuilderBase, new() + public class QueryOverSubqueryBuilderBase<R, S, T, B> + where R : IQueryOver<S,T> + where B : QueryOverSubqueryPropertyBuilderBase, new() { protected R root; @@ -121,21 +121,21 @@ return root; } - public S WhereProperty(Expression<Func<T, object>> expression) + public B WhereProperty(Expression<Func<T, object>> expression) { string property = ExpressionProcessor.FindMemberExpression(expression.Body); - return (S)new S().Set(root, property, null); + return (B)new B().Set(root, property, null); } - public S WhereProperty(Expression<Func<object>> expression) + public B WhereProperty(Expression<Func<object>> expression) { string property = ExpressionProcessor.FindMemberExpression(expression.Body); - return (S)new S().Set(root, property, null); + return (B)new B().Set(root, property, null); } - public S WhereValue(object value) + public B WhereValue(object value) { - return (S)new S().Set(root, null, value); + return (B)new B().Set(root, null, value); } } Modified: trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/Lambda/QueryOverSubqueryPropertyBuilder.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -9,7 +9,7 @@ namespace NHibernate.Criterion.Lambda { - public class QueryOverSubqueryPropertyBuilder<T> : QueryOverSubqueryPropertyBuilderBase<QueryOver<T>, T> + public class QueryOverSubqueryPropertyBuilder<S,T> : QueryOverSubqueryPropertyBuilderBase<QueryOver<S,T>, S, T> { public QueryOverSubqueryPropertyBuilder() @@ -17,7 +17,7 @@ } - public class IQueryOverSubqueryPropertyBuilder<T> : QueryOverSubqueryPropertyBuilderBase<IQueryOver<T>, T> + public class IQueryOverSubqueryPropertyBuilder<S,T> : QueryOverSubqueryPropertyBuilderBase<IQueryOver<S,T>, S, T> { public IQueryOverSubqueryPropertyBuilder() @@ -32,8 +32,8 @@ internal abstract QueryOverSubqueryPropertyBuilderBase Set(object root, string path, object value); } - public class QueryOverSubqueryPropertyBuilderBase<R, T> : QueryOverSubqueryPropertyBuilderBase - where R : IQueryOver<T> + public class QueryOverSubqueryPropertyBuilderBase<R, S, T> : QueryOverSubqueryPropertyBuilderBase + where R : IQueryOver<S,T> { protected R root; Modified: trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-28 14:04:43 UTC (rev 4867) +++ trunk/nhibernate/src/NHibernate/Criterion/QueryOver.cs 2009-11-28 21:09:24 UTC (rev 4868) @@ -19,14 +19,14 @@ protected QueryOver() { } - public static QueryOver<T> Of<T>() + public static QueryOver<T,T> Of<T>() { - return new QueryOver<T>(); + return new QueryOver<T,T>(); } - public static QueryOver<T> Of<T>(Expression<Func<T>> alias) + public static QueryOver<T,T> Of<T>(Expression<Func<T>> alias) { - return new QueryOver<T>(alias); + return new QueryOver<T,T>(alias); } public ICriteria UnderlyingCriteria @@ -41,11 +41,105 @@ } + [Serializable] + public class QueryOver<T> : QueryOver, IQueryOver<T> + { + + private IList<T> List() + { + return _criteria.List<T>(); + } + + private IList<U> List<U>() + { + return _criteria.List<U>(); + } + + private T UniqueResult() + { + return _criteria.UniqueResult<T>(); + } + + private U UniqueResult<U>() + { + return _criteria.UniqueResult<U>(); + } + + private IEnumerable<T> Future() + { + return _criteria.Future<T>(); + } + + private IEnumerable<U> Future<U>() + { + return _criteria.Future<U>(); + } + + private IFutureValue<T> FutureValue() + { + return _criteria.FutureValue<T>(); + } + + private IFutureValue<U> FutureValue<U>() + { + return _criteria.FutureValue<U>(); + } + + /// <summary> + /// Get an executable instance of <c>IQueryOver<T></c>, + /// to actually run the query.</summary> + public IQueryOver<T> GetExecutableQueryOver(ISession session) + { + _impl.Session = session.GetSessionImplementation(); + return this; + } + + /// <summary> + /// Method to allow comparison of detached query in Lambda expression + /// e.g., p => p.Name == myQuery.As<string> + /// </summary> + /// <typeparam name="S">type returned by query</typeparam> + /// <returns>throws an exception if evaluated directly at runtime.</returns> + public S As<S>() + { + throw new HibernateException("Incorrect syntax; .As<T> method is for use in Lambda expressions only."); + } + + + ICriteria IQueryOver<T>.UnderlyingCriteria + { get { return UnderlyingCriteria; } } + + IList<T> IQueryOver<T>.List() + { return List(); } + + IList<U> IQueryOver<T>.List<U>() + { return List<U>(); } + + T IQueryOver<T>.UniqueResult() + { return UniqueResult(); } + + U IQueryOver<T>.UniqueResult<U>() + { return UniqueResult<U>(); } + + IEnumerable<T> IQueryOver<T>.Future() + { return Future(); } + + IEnumerable<U> IQueryOver<T>.Future<U>() + { return Future<U>(); } + + IFutureValue<T> IQueryOver<T>.FutureValue() + { return FutureValue(); } + + IFutureValue<U> IQueryOver<T>.FutureValue<U>() + { return FutureValue<U>(); } + + } + /// <summary> /// Implementation of the <see cref="IQueryOver<T>"/> interface /// </summary> [Serializable] - public class QueryOver<T> : QueryOver, IQueryOver<T> + public class QueryOver<R,T> : QueryOver<R>, IQueryOver<R,T> { protected internal QueryOver() @@ -73,88 +167,77 @@ _criteria = criteria; } - /// <summary> - /// Method to allow comparison of detached query in Lambda expression - /// e.g., p => p.Name == myQuery.As<string> - /// </summary> - /// <typeparam name="R">type returned by query</typeparam> - /// <returns>throws an exception if evaluated directly at runtime.</returns> - public R As<R>() + public QueryOver<R,T> And(Expression<Func<T, bool>> expression) { - throw new HibernateException("Incorrect syntax; .As<T> method is for use in Lambda expressions only."); - } - - public QueryOver<T> And(Expression<Func<T, bool>> expression) - { return Add(expression); } - public QueryOver<T> And(Expression<Func<bool>> expression) + public QueryOver<R,T> And(Expression<Func<bool>> expression) { return Add(expression); } - public QueryOver<T> And(ICriterion expression) + public QueryOver<R,T> And(ICriterion expression) { return Add(expression); } - public QueryOver<T> AndNot(Expression<Func<T, bool>> expression) + public QueryOver<R,T> AndNot(Expression<Func<T, bool>> expression) { return AddNot(expression); } - public QueryOver<T> AndNot(Expression<Func<bool>> expression) + public QueryOver<R,T> AndNot(Expression<Func<bool>> expression) { return AddNot(expression); } - public QueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<T, object>> expression) + public QueryOverRestrictionBuilder<R,T> AndRestrictionOn(Expression<Func<T, object>> expression) { - return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + return new QueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - public QueryOverRestrictionBuilder<T> AndRestrictionOn(Expression<Func<object>> expression) + public QueryOverRestrictionBuilder<R,T> AndRestrictionOn(Expression<Func<object>> expression) { - return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + return new QueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - public QueryOver<T> Where(Expression<Func<T, bool>> expression) + public QueryOver<R,T> Where(Expression<Func<T, bool>> expression) { return Add(expression); } - public QueryOver<T> Where(Expression<Func<bool>> expression) + public QueryOver<R,T> Where(Expression<Func<bool>> expression) { return Add(expression); } - public QueryOver<T> Where(ICriterion expression) + public QueryOver<R,T> Where(ICriterion expression) { return Add(expression); } - public QueryOver<T> WhereNot(Expression<Func<T, bool>> expression) + public QueryOver<R,T> WhereNot(Expression<Func<T, bool>> expression) { return AddNot(expression); } - public QueryOver<T> WhereNot(Expression<Func<bool>> expression) + public QueryOver<R,T> WhereNot(Expression<Func<bool>> expression) { return AddNot(expression); } - public QueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<T, object>> expression) + public QueryOverRestrictionBuilder<R,T> WhereRestrictionOn(Expression<Func<T, object>> expression) { - return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + return new QueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - public QueryOverRestrictionBuilder<T> WhereRestrictionOn(Expression<Func<object>> expression) + public QueryOverRestrictionBuilder<R,T> WhereRestrictionOn(Expression<Func<object>> expression) { - return new QueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); + return new QueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - public QueryOver<T> Select(params Expression<Func<T, object>>[] projections) + public QueryOver<R,T> Select(params Expression<Func<R, object>>[] projections) { List<IProjection> projectionList = new List<IProjection>(); @@ -165,216 +248,216 @@ return this; } - public QueryOver<T> Select(params IProjection[] projections) + public QueryOver<R,T> Select(params IProjection[] projections) { _criteria.SetProjection(projections); return this; } - QueryOverProjectionBuilder<QueryOver<T>, T> SelectList + QueryOverProjectionBuilder<QueryOver<R,T>, R, T> SelectList { - get { return new QueryOverProjectionBuilder<QueryOver<T>, T>(this, this); } + get { return new QueryOverProjectionBuilder<QueryOver<R,T>, R, T>(this, this); } } - public QueryOverOrderBuilder<T> OrderBy(Expression<Func<T, object>> path) + public QueryOverOrderBuilder<R,T> OrderBy(Expression<Func<T, object>> path) { - return new QueryOverOrderBuilder<T>(this, path); + return new QueryOverOrderBuilder<R,T>(this, path); } - public QueryOverOrderBuilder<T> OrderBy(Expression<Func<object>> path) + public QueryOverOrderBuilder<R,T> OrderBy(Expression<Func<object>> path) { - return new QueryOverOrderBuilder<T>(this, path); + return new QueryOverOrderBuilder<R,T>(this, path); } - public QueryOverOrderBuilder<T> ThenBy(Expression<Func<T, object>> path) + public QueryOverOrderBuilder<R,T> ThenBy(Expression<Func<T, object>> path) { - return new QueryOverOrderBuilder<T>(this, path); + return new QueryOverOrderBuilder<R,T>(this, path); } - public QueryOverOrderBuilder<T> ThenBy(Expression<Func<object>> path) + public QueryOverOrderBuilder<R,T> ThenBy(Expression<Func<object>> path) { - return new QueryOverOrderBuilder<T>(this, path); + return new QueryOverOrderBuilder<R,T>(this, path); } - public QueryOver<T> Skip(int firstResult) + public QueryOver<R,T> Skip(int firstResult) { _criteria.SetFirstResult(firstResult); return this; } - public QueryOver<T> Take(int maxResults) + public QueryOver<R,T> Take(int maxResults) { _criteria.SetMaxResults(maxResults); return this; } - public QueryOver<T> Cacheable() + public QueryOver<R,T> Cacheable() { _criteria.SetCacheable(true); return this; } - public QueryOver<T> CacheMode(CacheMode cacheMode) + public QueryOver<R,T> CacheMode(CacheMode cacheMode) { _criteria.SetCacheMode(cacheMode); return this; } - public QueryOver<T> CacheRegion(string cacheRegion) + public QueryOver<R,T> CacheRegion(string cacheRegion) { _criteria.SetCacheRegion(cacheRegion); return this; } - public QueryOverSubqueryBuilder<T> WithSubquery + public QueryOverSubqueryBuilder<R,T> WithSubquery { - get { return new QueryOverSubqueryBuilder<T>(this); } + get { return new QueryOverSubqueryBuilder<R,T>(this); } } - public QueryOverFetchBuilder<T> Fetch(Expression<Func<T, object>> path) + public QueryOverFetchBuilder<R,T> Fetch(Expression<Func<R, object>> path) { - return new QueryOverFetchBuilder<T>(this, path); + return new QueryOverFetchBuilder<R,T>(this, path); } - public QueryOverLockBuilder<T> Lock() + public QueryOverLockBuilder<R,T> Lock() { - return new QueryOverLockBuilder<T>(this, null); + return new QueryOverLockBuilder<R,T>(this, null); } - public QueryOverLockBuilder<T> Lock(Expression<Func<object>> alias) + public QueryOverLockBuilder<R,T> Lock(Expression<Func<object>> alias) { - return new QueryOverLockBuilder<T>(this, alias); + return new QueryOverLockBuilder<R,T>(this, alias); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, U>> path) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<U>> path) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, U>> path, JoinType joinType) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, U>> path, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), joinType)); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,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) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, U>> path, Expression<Func<U>> alias, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body), joinType)); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,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) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body))); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) { - return new QueryOver<U>(_impl, + return new QueryOver<R,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) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), ExpressionProcessor.FindMemberExpression(alias.Body), joinType)); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,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) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), joinType)); } - public QueryOver<U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType) + public QueryOver<R,U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType) { - return new QueryOver<U>(_impl, + return new QueryOver<R,U>(_impl, _criteria.CreateCriteria( ExpressionProcessor.FindMemberExpression(path.Body), joinType)); } - public QueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) + public QueryOver<R,T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -382,7 +465,7 @@ JoinType.InnerJoin); } - public QueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) + public QueryOver<R,T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -390,7 +473,7 @@ JoinType.InnerJoin); } - public QueryOver<T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) + public QueryOver<R,T> JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -398,7 +481,7 @@ joinType); } - public QueryOver<T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + public QueryOver<R,T> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) { return AddAlias( ExpressionProcessor.FindMemberExpression(path.Body), @@ -406,301 +489,225 @@ joinType); } - public QueryOverJoinBuilder<T> Inner + public QueryOverJoinBuilder<R,T> Inner { - get { return new QueryOverJoinBuilder<T>(this, JoinType.InnerJoin); } + get { return new QueryOverJoinBuilder<R,T>(this, JoinType.InnerJoin); } } - public QueryOverJoinBuilder<T> Left + public QueryOverJoinBuilder<R,T> Left { - get { return new QueryOverJoinBuilder<T>(this, JoinType.LeftOuterJoin); } + get { return new QueryOverJoinBuilder<R,T>(this, JoinType.LeftOuterJoin); } } - public QueryOverJoinBuilder<T> Right + public QueryOverJoinBuilder<R,T> Right { - get { return new QueryOverJoinBuilder<T>(this, JoinType.RightOuterJoin); } + get { return new QueryOverJoinBuilder<R,T>(this, JoinType.RightOuterJoin); } } - public QueryOverJoinBuilder<T> Full + public QueryOverJoinBuilder<R,T> Full { - get { return new QueryOverJoinBuilder<T>(this, JoinType.FullJoin); } + get { return new QueryOverJoinBuilder<R,T>(this, JoinType.FullJoin); } } - public IList<T> List() + private QueryOver<R,T> AddAlias(string path, string alias, JoinType joinType) { - return _criteria.List<T>(); - } - - public IList<U> List<U>() - { - return _criteria.List<U>(); - } - - public T UniqueResult() - { - return _criteria.UniqueResult<T>(); - } - - public U UniqueResult<U>() - { - return _criteria.UniqueResult<U>(); - } - - IEnumerable<T> Future() - { - return _criteria.Future<T>(); - } - - IEnumerable<U> Future<U>() - { - return _criteria.Future<U>(); - } - - IFutureValue<T> FutureValue() - { - return _criteria.FutureValue<T>(); - } - - IFutureValue<U> FutureValue<U>() - { - return _criteria.FutureValue<U>(); - } - - /// <summary> - /// Get an executable instance of <c>IQueryOver<T></c>, - /// to actually run the query.</summary> - public IQueryOver<T> GetExecutableQueryOver(ISession session) - { - _impl.Session = session.GetSessionImplementation(); - return this; - } - - private QueryOver<T> AddAlias(string path, string alias, JoinType joinType) - { _criteria.CreateAlias(path, alias, joinType); return this; } - private QueryOver<T> Add(Expression<Func<T, bool>> expression) + private QueryOver<R,T> Add(Expression<Func<T, bool>> expression) { _criteria.Add(ExpressionProcessor.ProcessExpression<T>(expression)); return this; } - private QueryOver<T> Add(Expression<Func<bool>> expression) + private QueryOver<R,T> Add(Expression<Func<bool>> expression) { _criteria.Add(ExpressionProcessor.ProcessExpression(expression)); return this; } - private QueryOver<T> Add(ICriterion expression) + private QueryOver<R,T> Add(ICriterion expression) { _criteria.Add(expression); return this; } - private QueryOver<T> AddNot(Expression<Func<T, bool>> expression) + private QueryOver<R,T> AddNot(Expression<Func<T, bool>> expression) { _criteria.Add(Restrictions.Not(ExpressionProcessor.ProcessExpression<T>(expression))); return this; } - private QueryOver<T> AddNot(Expression<Func<bool>> expression) + private QueryOver<R,T> AddNot(Expression<Func<bool>> expression) { _criteria.Add(Restrictions.Not(ExpressionProcessor.ProcessExpression(expression))); return this; } - ICriteria IQueryOver<T>.UnderlyingCriteria - { get { return UnderlyingCriteria; } } - - IQueryOver<T> IQueryOver<T>.And(Expression<Func<T, bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.And(Expression<Func<T, bool>> expression) { return And(expression); } - IQueryOver<T> IQueryOver<T>.And(Expression<Func<bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.And(Expression<Func<bool>> expression) { return And(expression); } - IQueryOver<T> IQueryOver<T>.And(ICriterion expression) + IQueryOver<R,T> IQueryOver<R,T>.And(ICriterion expression) { return And(expression); } - IQueryOver<T> IQueryOver<T>.AndNot(Expression<Func<T, bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.AndNot(Expression<Func<T, bool>> expression) { return AndNot(expression); } - IQueryOver<T> IQueryOver<T>.AndNot(Expression<Func<bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.AndNot(Expression<Func<bool>> expression) { return AndNot(expression); } - IQueryOverRestrictionBuilder<T> IQueryOver<T>.AndRestrictionOn(Expression<Func<T, object>> expression) - { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOverRestrictionBuilder<R,T> IQueryOver<R,T>.AndRestrictionOn(Expression<Func<T, object>> expression) + { return new IQueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - IQueryOverRestrictionBuilder<T> IQueryOver<T>.AndRestrictionOn(Expression<Func<object>> expression) - { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOverRestrictionBuilder<R,T> IQueryOver<R,T>.AndRestrictionOn(Expression<Func<object>> expression) + { return new IQueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - IQueryOver<T> IQueryOver<T>.Where(Expression<Func<T, bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.Where(Expression<Func<T, bool>> expression) { return Where(expression); } - IQueryOver<T> IQueryOver<T>.Where(Expression<Func<bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.Where(Expression<Func<bool>> expression) { return Where(expression); } - IQueryOver<T> IQueryOver<T>.Where(ICriterion expression) + IQueryOver<R,T> IQueryOver<R,T>.Where(ICriterion expression) { return Where(expression); } - IQueryOver<T> IQueryOver<T>.WhereNot(Expression<Func<T, bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.WhereNot(Expression<Func<T, bool>> expression) { return WhereNot(expression); } - IQueryOver<T> IQueryOver<T>.WhereNot(Expression<Func<bool>> expression) + IQueryOver<R,T> IQueryOver<R,T>.WhereNot(Expression<Func<bool>> expression) { return WhereNot(expression); } - IQueryOverRestrictionBuilder<T> IQueryOver<T>.WhereRestrictionOn(Expression<Func<T, object>> expression) - { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOverRestrictionBuilder<R,T> IQueryOver<R,T>.WhereRestrictionOn(Expression<Func<T, object>> expression) + { return new IQueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - IQueryOverRestrictionBuilder<T> IQueryOver<T>.WhereRestrictionOn(Expression<Func<object>> expression) - { return new IQueryOverRestrictionBuilder<T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } + IQueryOverRestrictionBuilder<R,T> IQueryOver<R,T>.WhereRestrictionOn(Expression<Func<object>> expression) + { return new IQueryOverRestrictionBuilder<R,T>(this, ExpressionProcessor.FindMemberExpression(expression.Body)); } - IQueryOver<T> IQueryOver<T>.Select(params Expression<Func<T, object>>[] projections) + IQueryOver<R,T> IQueryOver<R,T>.Select(params Expression<Func<R, object>>[] projections) { return Select(projections); } - IQueryOver<T> IQueryOver<T>.Select(params IProjection[] projections) + IQueryOver<R,T> IQueryOver<R,T>.Select(params IProjection[] projections) { return Select(projections); } - QueryOverProjectionBuilder<IQueryOver<T>, T> IQueryOver<T>.SelectList - { get { return new QueryOverProjectionBuilder<IQueryOver<T>,T>(this, this); } } + QueryOverProjectionBuilder<IQueryOver<R,T>, R, T> IQueryOver<R,T>.SelectList + { get { return new QueryOverProjectionBuilder<IQueryOver<R,T>,R,T>(this, this); } } - IQueryOverOrderBuilder<T> IQueryOver<T>.OrderBy(Expression<Func<T, object>> path) - { return new IQueryOverOrderBuilder<T>(this, path); } + IQueryOverOrderBuilder<R,T> IQueryOver<R,T>.OrderBy(Expression<Func<T, object>> path) + { return new IQueryOverOrderBuilder<R,T>(this, path); } - IQueryOverOrderBuilder<T> IQueryOver<T>.OrderBy(Expression<Func<object>> path) - { return new IQueryOverOrderBuilder<T>(this, path); } + IQueryOverOrderBuilder<R,T> IQueryOver<R,T>.OrderBy(Expression<Func<object>> path) + { return new IQueryOverOrderBuilder<R,T>(this, path); } - IQueryOverOrderBuilder<T> IQueryOver<T>.ThenBy(Expression<Func<T, object>> path) - { return new IQueryOverOrderBuilder<T>(this, path); } + IQueryOverOrderBuilder<R,T> IQueryOver<R,T>.ThenBy(Expression<Func<T, object>> path) + { return new IQueryOverOrderBuilder<R,T>(this, path); } - IQueryOverOrderBuilder<T> IQueryOver<T>.ThenBy(Expression<Func<object>> path) - { return new IQueryOverOrderBuilder<T>(this, path); } + IQueryOverOrderBuilder<R,T> IQueryOver<R,T>.ThenBy(Expression<Func<object>> path) + { return new IQueryOverOrderBuilder<R,T>(this, path); } - IQueryOver<T> IQueryOver<T>.Skip(int firstResult) + IQueryOver<R,T> IQueryOver<R,T>.Skip(int firstResult) { return Skip(firstResult); } - IQueryOver<T> IQueryOver<T>.Take(int maxResults) + IQueryOver<R,T> IQueryOver<R,T>.Take(int maxResults) { return Take(maxResults); } - IQueryOver<T> IQueryOver<T>.Cacheable() + IQueryOver<R,T> IQueryOver<R,T>.Cacheable() { return Cacheable(); } - IQueryOver<T> IQueryOver<T>.CacheMode(CacheMode cacheMode) + IQueryOver<R,T> IQueryOver<R,T>.CacheMode(CacheMode cacheMode) { return CacheMode(cacheMode); } - IQueryOver<T> IQueryOver<T>.CacheRegion(string cacheRegion) + IQueryOver<R,T> IQueryOver<R,T>.CacheRegion(string cacheRegion) { return CacheRegion(cacheRegion); } - IQueryOverSubqueryBuilder<T> IQueryOver<T>.WithSubquery - { get { return new IQueryOverSubqueryBuilder<T>(this); } } + IQueryOverSubqueryBuilder<R,T> IQueryOver<R,T>.WithSubquery + { get { return new IQueryOverSubqueryBuilder<R,T>(this); } } - IQueryOverFetchBuilder<T> IQueryOver<T>.Fetch(Expression<Func<T, object>> path) - { return new IQueryOverFetchBuilder<T>(this, path); } + IQueryOverFetchBuilder<R,T> IQueryOver<R,T>.Fetch(Expression<Func<R, object>> path) + { return new IQueryOverFetchBuilder<R,T>(this, path); } - IQueryOverLockBuilder<T> IQueryOver<T>.Lock() - { return new IQueryOverLockBuilder<T>(this, null); } + IQueryOverLockBuilder<R,T> IQueryOver<R,T>.Lock() + { return new IQueryOverLockBuilder<R,T>(this, null); } - IQueryOverLockBuilder<T> IQueryOver<T>.Lock(Expression<Func<object>> alias) - { return new IQueryOverLockBuilder<T>(this, alias); } + IQueryOverLockBuilder<R,T> IQueryOver<R,T>.Lock(Expression<Func<object>> alias) + { return new IQueryOverLockBuilder<R,T>(this, alias); } - IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<T, U>> path) + IQueryOver<R,U> IQueryOver<R,T>.JoinQueryOver<U>(Expression<Func<T, U>> path) { return JoinQueryOver(path); } - IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<U>> path) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,T>.JoinQueryOver<U>(Expression<Func<T, IEnumerable<U>>> path) { return JoinQueryOver(path); } - IQueryOver<U> IQueryOver<T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,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) + IQueryOver<R,U> IQueryOver<R,T>.JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType) { return JoinQueryOver(path, alias, joinType); } - IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) + IQueryOver<R,T> IQueryOver<R,T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias) { return JoinAlias(path, alias); } - IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) + IQueryOver<R,T> IQueryOver<R,T>.JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias) { return JoinAlias(path, alias); } - IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) + IQueryOver<R,T> IQueryOver<R,T>.JoinAlias(Expression<Func<T, object>> path, Expression<Func<object>> alias, JoinType joinType) { return JoinAlias(path, alias, joinType); } - IQueryOver<T> IQueryOver<T>.JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType) + IQueryOver<R,T> IQueryOver<R,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); } } + IQueryOverJoinBuilder<R,T> IQueryOver<R,T>.Inner + { get { return new IQueryOverJoinBuilder<R,T>(this, JoinType.InnerJoin); } } - IQueryOverJoinBuilder<T> IQueryOver<T>.Left - { get { return new IQueryOverJoinBuilder<T>(this, JoinType.LeftOuterJoin); } } + IQueryOverJoinBuilder<R,T> IQueryOver<R,T>.Left + { get { return new IQueryOverJoinBuilder<R,T>(this, JoinType.LeftOuterJoin); } } - IQueryOverJoinBuilder<T> IQueryOver<T>.Right - { get { return new IQueryOverJoinBuilder<T>(this, JoinType.RightOuterJoin); } } + IQueryOverJoinBuilder<R,T> IQueryOver<R,T>.Right + { get { return new IQueryOverJoinBuilder<R,T>(this, JoinType.RightOuterJoin); } } - IQueryOverJoinBuilder<T> IQueryOver<T>.Full - { get { return new IQueryOverJoinBuilder<T>(this, JoinType.FullJoin); } } + IQueryOverJoinBuilder<R,T> IQueryOver<R,T>.Full + { get { return new IQueryOverJoinBuilder<R,T>(this, JoinType.FullJoin); } } - IList<T> IQueryOver<T>.List() - { return List(); } - - IList<U> IQueryOver<T>.List<U>() - { return List<U>(); } - - T IQueryOver<T>.UniqueResult() - { return UniqueResult(); } - - U IQueryOver<T>.UniqueResult<U>() - { return UniqueResult<U>(); } - - IEnumerable<T> IQueryOver<T... [truncated message content] |