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