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