src/Shared/EntityFramework.SqlServer/SqlGen/Sql8ExpressionRewriter.cs
// <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>
This method is used for translating  and ,
and for translating the "Except" part of .
This method is used for translating and and for translating the " Except " part of .
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);
            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");
            DbExpression existsPredicate = null;
            for (var i = 0; i < leftFlattenedProperties.Count; i++)
            {
                DbExpression equalsExpression = leftFlattenedProperties[i].Equal(rightFlattenedProperties[i]);
                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);
                }
            }
            DbExpression quantifierExpression = rightInputBinding.Any(existsPredicate);
            DbExpression filterPredicate;
            if (negate)
            {
                filterPredicate = quantifierExpression.Not();
            }
            else
            {
                filterPredicate = quantifierExpression;
            }
            DbExpression result = leftInputBinding.Filter(filterPredicate);
            if (distinct)
            {
                result = result.Distinct();
            }
            return result;
        }
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 ) ; if ( expressionKind == DbExpressionKind . Skip ) { if ( RemoveNonSortProperties ( leftFlattenedProperties , rightFlattenedProperties , sortExpressionsOverLeft , leftInputBinding . VariableName , sortExpressionsBindingVariableName ) ) { rightInputBinding = CapWithProject ( rightInputBinding , rightFlattenedProperties ) ; } } Debug . Assert ( leftFlattenedProperties . Count == rightFlattenedProperties . Count , " " ) ; Debug . Assert ( leftFlattenedProperties . Count != 0 , " " ) ; DbExpression existsPredicate = null ; for ( var i = 0 ; i < leftFlattenedProperties . Count ; i ++ ) { DbExpression equalsExpression = leftFlattenedProperties [ i ] . Equal ( rightFlattenedProperties [ i ] ) ; 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 ) ; } } DbExpression quantifierExpression = rightInputBinding . Any ( existsPredicate ) ; DbExpression filterPredicate ; if ( negate ) { filterPredicate = quantifierExpression . Not ( ) ; } else { filterPredicate = quantifierExpression ; } DbExpression result = leftInputBinding . Filter ( filterPredicate ) ; if ( distinct ) { result = result . Distinct ( ) ; } return result ; }
This method is used for translating  and ,
and for translating the "Except" part of .
This method is used for translating and and for translating the " Except " part of .
//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. //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))) //A.ai == B.bi //A.ai is null AND B.bi is null //Build the quantifier //Negate if needed //Build the filter //Apply distinct in needed
left
DbExpression
right
DbExpression
expressionKind
DbExpressionKind
sortExpressionsOverLeft
IList<DbPropertyExpression>
note that this list gets destroyed by this method
note that this list gets destroyed by this method
sortExpressionsBindingVariableName
string