private HqlExpression GetExpressionForBooleanEquality(Expression @operator, HqlExpression original) { //When the expression is a constant then use the constant var operandEx = @operator as ConstantExpression; if (operandEx != null) { NamedParameter namedParameter; if (_parameters.ConstantToParameterMap.TryGetValue(operandEx, out namedParameter)) { _parameters.RequiredHqlParameters.Add(new NamedParameterDescriptor(namedParameter.Name, null, false)); return(_hqlTreeBuilder.Parameter(namedParameter.Name).AsExpression()); } return(_hqlTreeBuilder.Constant(operandEx.Value)); } //When the expression is a member-access not nullable then use the HbmDot var memberAccessExpression = @operator as MemberExpression; if (ExpressionType.MemberAccess.Equals(@operator.NodeType) && memberAccessExpression != null && typeof(bool) == memberAccessExpression.Type) { // this case make the difference when the property "Value" of a nullable type is used (ignore the null since the user is explicity checking the Value) return(original); } var subQueryExpression = @operator as SubQueryExpression; if (subQueryExpression != null) { var resultOperators = subQueryExpression.QueryModel.ResultOperators; if (resultOperators.Count == 1 && (resultOperators[0] is FirstResultOperator || resultOperators[0] is SingleResultOperator)) { return(original); } } //When the expression is a member-access nullable then use the "case" clause to transform it to boolean (to use always .NET meaning instead leave the DB the behavior for null) //When the expression is a complex-expression then use the "case" clause to transform it to boolean return(_hqlTreeBuilder.Case(new[] { _hqlTreeBuilder.When(original, _hqlTreeBuilder.True()) }, _hqlTreeBuilder.False())); }
internal static HqlExpression ToArithmeticExpression(this HqlTreeNode node) { var hqlBooleanExpression = node as HqlBooleanExpression; if (hqlBooleanExpression != null) { var builder = new HqlTreeBuilder(); return(builder.Case(new[] { builder.When(hqlBooleanExpression, builder.True()) }, builder.False())); } return((HqlExpression)node); }
private static HqlExpression ConvertBooleanToCase(HqlExpression node) { if (node is HqlBooleanExpression) { var builder = new HqlTreeBuilder(); return(builder.Case( new HqlWhen[] { builder.When(node, builder.True()) }, builder.False())); } return(node); }
protected HqlTreeNode VisitConditionalExpression(ConditionalExpression expression) { var test = VisitExpression(expression.Test).ToBooleanExpression(); var ifTrue = VisitExpression(expression.IfTrue).ToArithmeticExpression(); var ifFalse = (expression.IfFalse != null ? VisitExpression(expression.IfFalse).ToArithmeticExpression() : null); HqlExpression @case = _hqlTreeBuilder.Case(new[] { _hqlTreeBuilder.When(test, ifTrue) }, ifFalse); return((expression.Type == typeof(bool) || expression.Type == (typeof(bool?))) ? @case : _hqlTreeBuilder.Cast(@case, expression.Type)); }
protected HqlTreeNode VisitConditionalExpression(ConditionalExpression expression) { var test = VisitExpression(expression.Test).ToBooleanExpression(); var ifTrue = VisitExpression(expression.IfTrue).ToArithmeticExpression(); var ifFalse = (expression.IfFalse != null ? VisitExpression(expression.IfFalse).ToArithmeticExpression() : null); HqlExpression @case = _hqlTreeBuilder.Case(new[] { _hqlTreeBuilder.When(test, ifTrue) }, ifFalse); // If both operands are parameters, HQL will not be able to determine the resulting type before // parameters binding. But it has to compute result set columns type before parameters are bound, // so an artificial cast is introduced to hint HQL at the resulting type. return(expression.Type == typeof(bool) || expression.Type == typeof(bool?) ? @case : _hqlTreeBuilder.TransparentCast(@case, expression.Type)); }
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection <Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { // Instance a.CompareTo(b) or static string.Compare(a, b)? Expression lhs = arguments.Count == 1 ? targetObject : arguments[0]; Expression rhs = arguments.Count == 1 ? arguments[0] : arguments[1]; HqlExpression lhs1 = visitor.Visit(lhs).AsExpression(); HqlExpression rhs1 = visitor.Visit(rhs).AsExpression(); HqlExpression lhs2 = visitor.Visit(lhs).AsExpression(); HqlExpression rhs2 = visitor.Visit(rhs).AsExpression(); // CASE WHEN (table.[Name] = N'Foo') THEN 0 // WHEN (table.[Name] > N'Foo') THEN 1 // ELSE -1 END return(treeBuilder.Case( new[] { treeBuilder.When(treeBuilder.Equality(lhs1, rhs1), treeBuilder.Constant(0)), treeBuilder.When(treeBuilder.GreaterThan(lhs2, rhs2), treeBuilder.Constant(1)) }, treeBuilder.Constant(-1))); }
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection <Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { var when = treeBuilder.When(visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(arguments[1]).AsExpression()); return(treeBuilder.Case(new[] { when }, visitor.Visit(arguments[2]).AsExpression())); }
protected HqlTreeNode VisitBinaryExpression(BinaryExpression expression) { var lhs = VisitExpression(expression.Left).AsExpression(); var rhs = VisitExpression(expression.Right).AsExpression(); switch (expression.NodeType) { case ExpressionType.Equal: // Need to check for boolean equality if (lhs is HqlBooleanExpression || rhs is HqlBooleanExpression) { lhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(lhs, _hqlTreeBuilder.Constant(1)) }, _hqlTreeBuilder.Constant(0)); rhs = _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.IsNullableOrReference() || expression.Right.Type.IsNullableOrReference()) { // 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: // Need to check for boolean in-equality if (lhs is HqlBooleanExpression || rhs is HqlBooleanExpression) { lhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(lhs, _hqlTreeBuilder.Constant(1)) }, _hqlTreeBuilder.Constant(0)); rhs = _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.IsNullableOrReference() || expression.Right.Type.IsNullableOrReference()) { 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: return(_hqlTreeBuilder.BitwiseAnd(lhs, rhs)); case ExpressionType.AndAlso: return(_hqlTreeBuilder.BooleanAnd(lhs.AsBooleanExpression(), rhs.AsBooleanExpression())); case ExpressionType.Or: return(_hqlTreeBuilder.BitwiseOr(lhs, rhs)); case ExpressionType.OrElse: return(_hqlTreeBuilder.BooleanOr(lhs.AsBooleanExpression(), rhs.AsBooleanExpression())); case ExpressionType.Add: return(_hqlTreeBuilder.Add(lhs, rhs)); case ExpressionType.Subtract: return(_hqlTreeBuilder.Subtract(lhs, rhs)); case ExpressionType.Multiply: return(_hqlTreeBuilder.Multiply(lhs, rhs)); case ExpressionType.Divide: return(_hqlTreeBuilder.Divide(lhs, rhs)); case ExpressionType.LessThan: return(_hqlTreeBuilder.LessThan(lhs, rhs)); case ExpressionType.LessThanOrEqual: return(_hqlTreeBuilder.LessThanOrEqual(lhs, rhs)); case ExpressionType.GreaterThan: return(_hqlTreeBuilder.GreaterThan(lhs, rhs)); case ExpressionType.GreaterThanOrEqual: return(_hqlTreeBuilder.GreaterThanOrEqual(lhs, rhs)); } throw new InvalidOperationException(); }
protected HqlTreeNode VisitBinaryExpression(BinaryExpression expression) { var lhs = VisitExpression(expression.Left).AsExpression(); var rhs = VisitExpression(expression.Right).AsExpression(); switch (expression.NodeType) { case ExpressionType.Equal: // Need to check for boolean equality if (lhs is HqlBooleanExpression || rhs is HqlBooleanExpression) { lhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(lhs, _hqlTreeBuilder.Constant(true)) }, _hqlTreeBuilder.Constant(false)); rhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(rhs, _hqlTreeBuilder.Constant(true)) }, _hqlTreeBuilder.Constant(false)); return(_hqlTreeBuilder.Equality(lhs, rhs)); } // Check for nulls on left or right. if (expression.Right is ConstantExpression && expression.Right.Type.IsNullableOrReference() && ((ConstantExpression)expression.Right).Value == null) { return(_hqlTreeBuilder.IsNull(lhs)); } if (expression.Left is ConstantExpression && expression.Left.Type.IsNullableOrReference() && ((ConstantExpression)expression.Left).Value == null) { return(_hqlTreeBuilder.IsNull(rhs)); } // Nothing was null, use standard equality. return(_hqlTreeBuilder.Equality(lhs, rhs)); case ExpressionType.NotEqual: // Need to check for boolean in-equality if (lhs is HqlBooleanExpression || rhs is HqlBooleanExpression) { lhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(lhs, _hqlTreeBuilder.Constant(true)) }, _hqlTreeBuilder.Constant(false)); rhs = _hqlTreeBuilder.Case( new [] { _hqlTreeBuilder.When(rhs, _hqlTreeBuilder.Constant(true)) }, _hqlTreeBuilder.Constant(false)); return(_hqlTreeBuilder.Inequality(lhs, rhs)); } // Check for nulls on left or right. if (expression.Right is ConstantExpression && expression.Right.Type.IsNullableOrReference() && ((ConstantExpression)expression.Right).Value == null) { return(_hqlTreeBuilder.IsNotNull(lhs)); } if (expression.Left is ConstantExpression && expression.Left.Type.IsNullableOrReference() && ((ConstantExpression)expression.Left).Value == null) { return(_hqlTreeBuilder.IsNotNull(rhs)); } // Nothing was null, use standard inequality. return(_hqlTreeBuilder.Inequality(lhs, rhs)); case ExpressionType.And: return(_hqlTreeBuilder.BitwiseAnd(lhs, rhs)); case ExpressionType.AndAlso: return(_hqlTreeBuilder.BooleanAnd(lhs.AsBooleanExpression(), rhs.AsBooleanExpression())); case ExpressionType.Or: return(_hqlTreeBuilder.BitwiseOr(lhs, rhs)); case ExpressionType.OrElse: return(_hqlTreeBuilder.BooleanOr(lhs.AsBooleanExpression(), rhs.AsBooleanExpression())); case ExpressionType.Add: return(_hqlTreeBuilder.Add(lhs, rhs)); case ExpressionType.Subtract: return(_hqlTreeBuilder.Subtract(lhs, rhs)); case ExpressionType.Multiply: return(_hqlTreeBuilder.Multiply(lhs, rhs)); case ExpressionType.Divide: return(_hqlTreeBuilder.Divide(lhs, rhs)); case ExpressionType.LessThan: return(_hqlTreeBuilder.LessThan(lhs, rhs)); case ExpressionType.LessThanOrEqual: return(_hqlTreeBuilder.LessThanOrEqual(lhs, rhs)); case ExpressionType.GreaterThan: return(_hqlTreeBuilder.GreaterThan(lhs, rhs)); case ExpressionType.GreaterThanOrEqual: return(_hqlTreeBuilder.GreaterThanOrEqual(lhs, rhs)); case ExpressionType.Coalesce: return(_hqlTreeBuilder.Coalesce(lhs, rhs)); } throw new InvalidOperationException(); }