internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull)
        {
            DbExpression cqt = (DbExpression)null;

            this.AsCql((Action <NegatedConstant, IEnumerable <Constant> >)((negated, domainValues) => cqt = negated.AsCqt(row, domainValues, this.RestrictedMemberSlot.MemberPath, skipIsNotNull)), (Action <Set <Constant> >)(domainValues =>
            {
                cqt = this.RestrictedMemberSlot.MemberPath.AsCqt(row);
                if (domainValues.Count == 1)
                {
                    cqt = (DbExpression)cqt.Equal(domainValues.Single <Constant>().AsCqt(row, this.RestrictedMemberSlot.MemberPath));
                }
                else
                {
                    cqt = Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>)domainValues.Select <Constant, DbExpression>((Func <Constant, DbExpression>)(c => (DbExpression)cqt.Equal(c.AsCqt(row, this.RestrictedMemberSlot.MemberPath)))).ToList <DbExpression>(), (Func <DbExpression, DbExpression, DbExpression>)((prev, next) => (DbExpression)prev.Or(next)));
                }
            }), (Action)(() =>
            {
                DbExpression right = (DbExpression)this.RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull().Not();
                cqt = cqt != null ? (DbExpression)cqt.And(right) : right;
            }), (Action)(() =>
            {
                DbExpression left = (DbExpression)this.RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull();
                cqt = cqt != null ? (DbExpression)left.Or(cqt) : left;
            }), skipIsNotNull);
            return(cqt);
        }
Пример #2
0
        public override DbExpression Visit(DbEqualExpression exp)
        {
            DbExpression left  = exp.Left;
            DbExpression right = exp.Right;

            left  = DbExpressionExtension.StripInvalidConvert(left);
            right = DbExpressionExtension.StripInvalidConvert(right);

            MethodInfo method_Sql_Equals = PublicConstants.MethodInfo_Sql_Equals.MakeGenericMethod(left.Type);

            /* Sql.Equals(left, right) */
            DbMethodCallExpression left_equals_right = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
            {
                left, right
            });

            if (right.NodeType == DbExpressionType.Parameter || right.NodeType == DbExpressionType.Constant || left.NodeType == DbExpressionType.Parameter || left.NodeType == DbExpressionType.Constant || right.NodeType == DbExpressionType.SubQuery || left.NodeType == DbExpressionType.SubQuery || !left.Type.CanNull() || !right.Type.CanNull())
            {
                /*
                 * a.Name == name --> a.Name == name
                 * a.Id == (select top 1 T.Id from T) --> a.Id == (select top 1 T.Id from T)
                 * 对于上述查询,我们不考虑 null
                 */

                left_equals_right.Accept(this);
                return(exp);
            }


            /*
             * a.Name == a.XName --> a.Name == a.XName or (a.Name is null and a.XName is null)
             */

            /* Sql.Equals(left, null) */
            var left_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
            {
                left, DbExpression.Constant(null, left.Type)
            });

            /* Sql.Equals(right, null) */
            var right_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
            {
                right, DbExpression.Constant(null, right.Type)
            });

            /* Sql.Equals(left, null) && Sql.Equals(right, null) */
            var left_is_null_and_right_is_null = DbExpression.And(left_is_null, right_is_null);

            /* Sql.Equals(left, right) || (Sql.Equals(left, null) && Sql.Equals(right, null)) */
            var left_equals_right_or_left_is_null_and_right_is_null = DbExpression.Or(left_equals_right, left_is_null_and_right_is_null);

            left_equals_right_or_left_is_null_and_right_is_null.Accept(this);

            return(exp);
        }
Пример #3
0
        internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull)
        {
            DbExpression cqt = null;

            AsCql(
                // negatedConstantAsCql action
                (negated, domainValues) =>
            {
                Debug.Assert(cqt == null, "unexpected construction order - cqt must be null");
                cqt = negated.AsCqt(row, domainValues, RestrictedMemberSlot.MemberPath, skipIsNotNull);
            },
                // varInDomain action
                (domainValues) =>
            {
                Debug.Assert(cqt == null, "unexpected construction order - cqt must be null");
                Debug.Assert(domainValues.Count > 0, "domain must not be empty");
                cqt = RestrictedMemberSlot.MemberPath.AsCqt(row);
                if (domainValues.Count == 1)
                {
                    // Single value
                    cqt = cqt.Equal(domainValues.Single().AsCqt(row, RestrictedMemberSlot.MemberPath));
                }
                else
                {
                    // Multiple values: build list of var = c1, var = c2, ..., then OR them all.
                    var operands =
                        domainValues.Select(c => (DbExpression)cqt.Equal(c.AsCqt(row, RestrictedMemberSlot.MemberPath))).ToList();
                    cqt = Helpers.BuildBalancedTreeInPlace(operands, (prev, next) => prev.Or(next));
                }
            },
                // varIsNotNull action
                () =>
            {
                // ( ... AND var IS NOT NULL)
                DbExpression varIsNotNull = RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull().Not();
                cqt = cqt != null ? cqt.And(varIsNotNull) : varIsNotNull;
            },
                // varIsNull action
                () =>
            {
                // (var IS NULL OR ...)
                DbExpression varIsNull = RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull();
                cqt = cqt != null ? varIsNull.Or(cqt) : varIsNull;
            },
                skipIsNotNull);

            return(cqt);
        }
Пример #4
0
        public void Process(DbMethodCallExpression exp, SqlGenerator generator)
        {
            DbExpression e = exp.Arguments.First();
            DbEqualExpression equalNullExpression = DbExpression.Equal(e, DbExpression.Constant(null, UtilConstants.TypeOfString));
            DbEqualExpression equalEmptyExpression = DbExpression.Equal(e, DbExpression.Constant(string.Empty));

            DbOrExpression orExpression = DbExpression.Or(equalNullExpression, equalEmptyExpression);

            DbCaseWhenExpression.WhenThenExpressionPair whenThenPair = new DbCaseWhenExpression.WhenThenExpressionPair(orExpression, DbConstantExpression.One);

            List<DbCaseWhenExpression.WhenThenExpressionPair> whenThenExps = new List<DbCaseWhenExpression.WhenThenExpressionPair>(1);
            whenThenExps.Add(whenThenPair);

            DbCaseWhenExpression caseWhenExpression = DbExpression.CaseWhen(whenThenExps, DbConstantExpression.Zero, UtilConstants.TypeOfBoolean);

            var eqExp = DbExpression.Equal(caseWhenExpression, DbConstantExpression.One);
            eqExp.Accept(generator);
        }
Пример #5
0
        public override DbExpression Visit(DbNotEqualExpression exp)
        {
            DbExpression left  = exp.Left;
            DbExpression right = exp.Right;

            left  = DbExpressionExtension.StripInvalidConvert(left);
            right = DbExpressionExtension.StripInvalidConvert(right);

            MethodInfo method_Sql_NotEquals = PublicConstants.MethodInfo_Sql_NotEquals.MakeGenericMethod(left.Type);

            /* Sql.NotEquals(left, right) */
            DbMethodCallExpression left_not_equals_right = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2)
            {
                left, right
            });

            //明确 left right 其中一边一定为 null
            if (DbExpressionExtension.AffirmExpressionRetValueIsNull(right) || DbExpressionExtension.AffirmExpressionRetValueIsNull(left))
            {
                /*
                 * a.Name != null --> a.Name != null
                 */

                left_not_equals_right.Accept(this);
                return(exp);
            }

            if (right.NodeType == DbExpressionType.SubQuery || left.NodeType == DbExpressionType.SubQuery)
            {
                /*
                 * a.Id != (select top 1 T.Id from T) --> a.Id <> (select top 1 T.Id from T),对于这种查询,我们不考虑 null
                 */

                left_not_equals_right.Accept(this);
                return(exp);
            }

            MethodInfo method_Sql_Equals = PublicConstants.MethodInfo_Sql_Equals.MakeGenericMethod(left.Type);

            if (left.NodeType == DbExpressionType.Parameter || left.NodeType == DbExpressionType.Constant)
            {
                var t = right;
                right = left;
                left  = t;
            }
            if (right.NodeType == DbExpressionType.Parameter || right.NodeType == DbExpressionType.Constant)
            {
                /*
                 * 走到这说明 name 不可能为 null
                 * a.Name != name --> a.Name <> name or a.Name is null
                 */

                if (left.NodeType != DbExpressionType.Parameter && left.NodeType != DbExpressionType.Constant)
                {
                    /*
                     * a.Name != name --> a.Name <> name or a.Name is null
                     */

                    /* Sql.Equals(left, null) */
                    var left_is_null1 = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
                    {
                        left, DbExpression.Constant(null, left.Type)
                    });

                    /* Sql.NotEquals(left, right) || Sql.Equals(left, null) */
                    var left_not_equals_right_or_left_is_null = DbExpression.Or(left_not_equals_right, left_is_null1);
                    left_not_equals_right_or_left_is_null.Accept(this);
                }
                else
                {
                    /*
                     * name != name1 --> name <> name,其中 name 和 name1 都为变量且都不可能为 null
                     */

                    left_not_equals_right.Accept(this);
                }

                return(exp);
            }


            /*
             * a.Name != a.XName --> a.Name <> a.XName or (a.Name is null and a.XName is not null) or (a.Name is not null and a.XName is null)
             * ## a.Name != a.XName 不能翻译成:not (a.Name == a.XName or (a.Name is null and a.XName is null)),因为数据库里的 not 有时候并非真正意义上的“取反”!
             * 当 a.Name 或者 a.XName 其中一个字段有为 NULL,另一个字段有值时,会查不出此条数据 ##
             */

            DbConstantExpression null_Constant = DbExpression.Constant(null, left.Type);

            /* Sql.Equals(left, null) */
            var left_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
            {
                left, null_Constant
            });
            /* Sql.NotEquals(left, null) */
            var left_is_not_null = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2)
            {
                left, null_Constant
            });

            /* Sql.Equals(right, null) */
            var right_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2)
            {
                right, null_Constant
            });
            /* Sql.NotEquals(right, null) */
            var right_is_not_null = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2)
            {
                right, null_Constant
            });

            /* Sql.Equals(left, null) && Sql.NotEquals(right, null) */
            var left_is_null_and_right_is_not_null = DbExpression.And(left_is_null, right_is_not_null);

            /* Sql.NotEquals(left, null) && Sql.Equals(right, null) */
            var left_is_not_null_and_right_is_null = DbExpression.And(left_is_not_null, right_is_null);

            /* (Sql.Equals(left, null) && Sql.NotEquals(right, null)) || (Sql.NotEquals(left, null) && Sql.Equals(right, null)) */
            var left_is_null_and_right_is_not_null_or_left_is_not_null_and_right_is_null = DbExpression.Or(left_is_null_and_right_is_not_null, left_is_not_null_and_right_is_null);

            /* Sql.NotEquals(left, right) || (Sql.Equals(left, null) && Sql.NotEquals(right, null)) || (Sql.NotEquals(left, null) && Sql.Equals(right, null)) */
            var e = DbExpression.Or(left_not_equals_right, left_is_null_and_right_is_not_null_or_left_is_not_null_and_right_is_null);

            e.Accept(this);

            return(exp);
        }
        // <summary>
        // This method is used for translating <see cref="DbIntersectExpression" /> and <see cref="DbExceptExpression" />,
        // and for translating the "Except" part of <see cref="DbSkipExpression" />.
        // into the follwoing expression:
        // A INTERSECT B, A EXCEPT B
        // (DISTINCT)
        // |
        // FILTER
        // |
        // | - Input: A
        // | - Predicate:(NOT)
        // |
        // ANY
        // |
        // | - Input: B
        // | - Predicate:  (B.b1 = A.a1 or (B.b1 is null and A.a1 is null))
        // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null))
        // AND ...
        // AND (B.bn = A.an or (B.bn is null and A.an is null)))
        // Here, A corresponds to right and B to left.
        // (NOT) is present when transforming Except
        // for the purpose of translating <see cref="DbExceptExpression" /> or <see cref="DbSkipExpression" />.
        // (DISTINCT) is present when transforming for the purpose of translating
        // <see cref="DbExceptExpression" /> or <see cref="DbIntersectExpression" />.
        // For <see cref="DbSkipExpression" />, the input to ANY is caped with project which projects out only
        // the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate.
        // This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these.
        // </summary>
        // <param name="sortExpressionsOverLeft"> note that this list gets destroyed by this method </param>
        private DbExpression TransformIntersectOrExcept(
            DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList <DbPropertyExpression> sortExpressionsOverLeft,
            string sortExpressionsBindingVariableName)
        {
            var negate   = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip);
            var distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect);

            var leftInputBinding  = left.Bind();
            var rightInputBinding = right.Bind();

            IList <DbPropertyExpression> leftFlattenedProperties  = new List <DbPropertyExpression>();
            IList <DbPropertyExpression> rightFlattenedProperties = new List <DbPropertyExpression>();

            FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties);
            FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties);

            //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and
            // the properties in the list sortExpressionsOverLeft
            // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these
            // are non equal comparable, SQL Server 2000 throws.
            if (expressionKind == DbExpressionKind.Skip)
            {
                if (RemoveNonSortProperties(
                        leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName,
                        sortExpressionsBindingVariableName))
                {
                    rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties);
                }
            }

            Debug.Assert(
                leftFlattenedProperties.Count == rightFlattenedProperties.Count,
                "The left and the right input to INTERSECT or EXCEPT have a different number of properties");
            Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties");

            //Build the predicate for the quantifier:
            //   (B.b1 = A.a1 or (B.b1 is null and A.a1 is null))
            //      AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null))
            //      AND ...
            //      AND (B.bn = A.an or (B.bn is null and A.an is null)))
            DbExpression existsPredicate = null;

            for (var i = 0; i < leftFlattenedProperties.Count; i++)
            {
                //A.ai == B.bi
                DbExpression equalsExpression = leftFlattenedProperties[i].Equal(rightFlattenedProperties[i]);

                //A.ai is null AND B.bi is null
                DbExpression leftIsNullExpression  = leftFlattenedProperties[i].IsNull();
                DbExpression rightIsNullExpression = rightFlattenedProperties[i].IsNull();
                DbExpression bothNullExpression    = leftIsNullExpression.And(rightIsNullExpression);

                DbExpression orExpression = equalsExpression.Or(bothNullExpression);

                if (i == 0)
                {
                    existsPredicate = orExpression;
                }
                else
                {
                    existsPredicate = existsPredicate.And(orExpression);
                }
            }

            //Build the quantifier
            DbExpression quantifierExpression = rightInputBinding.Any(existsPredicate);

            DbExpression filterPredicate;

            //Negate if needed
            if (negate)
            {
                filterPredicate = quantifierExpression.Not();
            }
            else
            {
                filterPredicate = quantifierExpression;
            }

            //Build the filter
            DbExpression result = leftInputBinding.Filter(filterPredicate);

            //Apply distinct in needed
            if (distinct)
            {
                result = result.Distinct();
            }

            return(result);
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            var expression = base.VisitBinary(node) as BinaryExpression;

            DbExpression dbExpression;

            //  Need special handling for comparisons against the null constant.  If we don't translate these
            //  using an "IsNull" expression, EF will convert it literally as "= null" which doesn't work in SQL Server.
            if (IsNullConstantExpression(expression.Right))
            {
                dbExpression = MapNullComparison(expression.Left, expression.NodeType);
            }
            else if (IsNullConstantExpression(expression.Left))
            {
                dbExpression = MapNullComparison(expression.Right, expression.NodeType);
            }
            else
            {
                DbExpression leftExpression  = GetDbExpressionForExpression(expression.Left);
                DbExpression rightExpression = GetDbExpressionForExpression(expression.Right);

                switch (expression.NodeType)
                {
                case ExpressionType.Equal:
                    //  DbPropertyExpression = class property that has been mapped to a database column
                    //  DbParameterReferenceExpression = lambda parameter
                    if (IsNullableExpressionOfType <DbPropertyExpression>(leftExpression) && IsNullableExpressionOfType <DbParameterReferenceExpression>(rightExpression))
                    {
                        dbExpression = CreateEqualComparisonOfNullablePropToNullableParam(leftExpression, rightExpression);
                    }
                    else if (IsNullableExpressionOfType <DbPropertyExpression>(rightExpression) && IsNullableExpressionOfType <DbParameterReferenceExpression>(leftExpression))
                    {
                        dbExpression = CreateEqualComparisonOfNullablePropToNullableParam(rightExpression, leftExpression);
                    }
                    else
                    {
                        dbExpression = leftExpression.Equal(rightExpression);
                    }
                    break;

                case ExpressionType.NotEqual:
                    dbExpression = leftExpression.NotEqual(rightExpression);
                    break;

                case ExpressionType.GreaterThan:
                    dbExpression = leftExpression.GreaterThan(rightExpression);
                    break;

                case ExpressionType.GreaterThanOrEqual:
                    dbExpression = leftExpression.GreaterThanOrEqual(rightExpression);
                    break;

                case ExpressionType.LessThan:
                    dbExpression = leftExpression.LessThan(rightExpression);
                    break;

                case ExpressionType.LessThanOrEqual:
                    dbExpression = leftExpression.LessThanOrEqual(rightExpression);
                    break;

                case ExpressionType.AndAlso:
                    dbExpression = leftExpression.And(rightExpression);
                    break;

                case ExpressionType.OrElse:
                    dbExpression = leftExpression.Or(rightExpression);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unhandled NodeType of {0} in LambdaToDbExpressionVisitor.VisitBinary", expression.NodeType));
                }
            }

            MapExpressionToDbExpression(expression, dbExpression);

            return(expression);
        }