DefaultExpressionVisitor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Common / CommandTrees / DefaultExpressionVisitor.cs / 1305376 / DefaultExpressionVisitor.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees; 
using CqtBuilder = System.Data.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder;
using System.Linq; 
 
namespace System.Data.Common.CommandTrees
{ 
    /// 
    /// Visits each element of an expression tree from a given root expression. If any element changes, the tree is
    /// rebuilt back to the root and the new root expression is returned; otherwise the original root expression is returned.
    ///  
#if PUBLIC_DBEXPRESSIONBUILDER
    public 
#endif 
    class DefaultExpressionVisitor : DbExpressionVisitor
    { 
        private readonly Dictionary varMappings = new Dictionary();

        protected DefaultExpressionVisitor()
        { 
        }
 
        protected virtual void OnExpressionReplaced(DbExpression oldExpression, DbExpression newExpression) 
        {
        } 

        protected virtual void OnVariableRebound(DbVariableReferenceExpression fromVarRef, DbVariableReferenceExpression toVarRef)
        {
        } 

        protected virtual void OnEnterScope(IEnumerable scopeVariables) 
        { 
        }
 
        protected virtual void OnExitScope()
        {
        }
 
        protected virtual DbExpression VisitExpression(DbExpression expression)
        { 
            DbExpression newValue = null; 
            if (expression != null)
            { 
                newValue = expression.Accept(this);
            }

            return newValue; 
        }
 
        protected virtual IList VisitExpressionList(IList list) 
        {
            return VisitList(list, this.VisitExpression); 
        }

        protected virtual DbExpressionBinding VisitExpressionBinding(DbExpressionBinding binding)
        { 
            DbExpressionBinding result = binding;
            if (binding != null) 
            { 
                DbExpression newInput = this.VisitExpression(binding.Expression);
                if (!object.ReferenceEquals(binding.Expression, newInput)) 
                {
                    result = CqtBuilder.BindAs(newInput, binding.VariableName);
                    this.RebindVariable(binding.Variable, result.Variable);
                } 
            }
            return result; 
        } 

        protected virtual IList VisitExpressionBindingList(IList list) 
        {
            return this.VisitList(list, this.VisitExpressionBinding);
        }
 
        protected virtual DbGroupExpressionBinding VisitGroupExpressionBinding(DbGroupExpressionBinding binding)
        { 
            DbGroupExpressionBinding result = binding; 
            if (binding != null)
            { 
                DbExpression newInput = this.VisitExpression(binding.Expression);
                if (!object.ReferenceEquals(binding.Expression, newInput))
                {
                    result = CqtBuilder.GroupBindAs(newInput, binding.VariableName, binding.GroupVariableName); 
                    this.RebindVariable(binding.Variable, result.Variable);
                    this.RebindVariable(binding.GroupVariable, result.GroupVariable); 
                } 
            }
            return result; 
        }

        protected virtual DbSortClause VisitSortClause(DbSortClause clause)
        { 
            DbSortClause result = clause;
            if (clause != null) 
            { 
                DbExpression newExpression = this.VisitExpression(clause.Expression);
                if (!object.ReferenceEquals(clause.Expression, newExpression)) 
                {
                    if (!string.IsNullOrEmpty(clause.Collation))
                    {
                        result = (clause.Ascending ? CqtBuilder.ToSortClause(newExpression, clause.Collation) : CqtBuilder.ToSortClauseDescending(newExpression, clause.Collation)); 
                    }
                    else 
                    { 
                        result = (clause.Ascending ? CqtBuilder.ToSortClause(newExpression) : CqtBuilder.ToSortClauseDescending(newExpression));
                    } 
                }
            }
            return result;
        } 

        protected virtual IList VisitSortOrder(IList sortOrder) 
        { 
            return VisitList(sortOrder, this.VisitSortClause);
        } 

        protected virtual DbAggregate VisitAggregate(DbAggregate aggregate)
        {
            // Currently only function or group aggregate are possible 
            DbFunctionAggregate functionAggregate = aggregate as DbFunctionAggregate;
            if (functionAggregate != null) 
            { 
                return VisitFunctionAggregate(functionAggregate);
            } 

            DbGroupAggregate groupAggregate = (DbGroupAggregate)aggregate;
            return VisitGroupAggregate(groupAggregate);
        } 

        protected virtual DbFunctionAggregate VisitFunctionAggregate(DbFunctionAggregate aggregate) 
        { 
            DbFunctionAggregate result = aggregate;
            if (aggregate != null) 
            {
                EdmFunction newFunction = this.VisitFunction(aggregate.Function);
                IList newArguments = this.VisitExpressionList(aggregate.Arguments);
 
                Debug.Assert(newArguments.Count == 1, "Function aggregate had more than one argument?");
 
                if (!object.ReferenceEquals(aggregate.Function, newFunction) || 
                    !object.ReferenceEquals(aggregate.Arguments, newArguments))
                { 
                    if (aggregate.Distinct)
                    {
                        result = CqtBuilder.AggregateDistinct(newFunction, newArguments[0]);
                    } 
                    else
                    { 
                        result = CqtBuilder.Aggregate(newFunction, newArguments[0]); 
                    }
                } 
            }
            return result;
        }
 
        protected virtual DbGroupAggregate VisitGroupAggregate(DbGroupAggregate aggregate)
        { 
            DbGroupAggregate result = aggregate; 
            if (aggregate != null)
            { 
                IList newArguments = this.VisitExpressionList(aggregate.Arguments);
                Debug.Assert(newArguments.Count == 1, "Group aggregate had more than one argument?");

                if (!object.ReferenceEquals(aggregate.Arguments, newArguments)) 
                {
                    result = CqtBuilder.GroupAggregate(newArguments[0]); 
                } 
            }
            return result; 
        }

        protected virtual DbLambda VisitLambda(DbLambda lambda)
        { 
            EntityUtil.CheckArgumentNull(lambda, "lambda");
 
            DbLambda result = lambda; 
            IList newFormals = this.VisitList(lambda.Variables, varRef =>
                { 
                    TypeUsage newVarType = this.VisitTypeUsage(varRef.ResultType);
                    if (!object.ReferenceEquals(varRef.ResultType, newVarType))
                    {
                        return CqtBuilder.Variable(newVarType, varRef.VariableName); 
                    }
                    else 
                    { 
                        return varRef;
                    } 
                }
            );
            this.EnterScope(newFormals.ToArray()); // ToArray: Don't pass the List instance directly to OnEnterScope
            DbExpression newBody = this.VisitExpression(lambda.Body); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(lambda.Variables, newFormals) || 
                !object.ReferenceEquals(lambda.Body, newBody))
            { 
                result = CqtBuilder.Lambda(newBody, newFormals);
            }
            return result;
        } 

        // Metadata 'Visitor' methods 
        protected virtual EdmType VisitType(EdmType type) { return type; } 
        protected virtual TypeUsage VisitTypeUsage(TypeUsage type) { return type; }
        protected virtual EntitySetBase VisitEntitySet(EntitySetBase entitySet) { return entitySet; } 
        protected virtual EdmFunction VisitFunction(EdmFunction functionMetadata) { return functionMetadata; }

        #region Private Implementation
 
        private void NotifyIfChanged(DbExpression originalExpression, DbExpression newExpression)
        { 
            if (!object.ReferenceEquals(originalExpression, newExpression)) 
            {
                this.OnExpressionReplaced(originalExpression, newExpression); 
            }
        }

        private IList VisitList(IList list, Func map) 
        {
            IList result = list; 
            if(list != null) 
            {
                List newList = null; 
                for (int idx = 0; idx < list.Count; idx++)
                {
                    TElement newElement = map(list[idx]);
                    if (newList == null && 
                        !object.ReferenceEquals(list[idx], newElement))
                    { 
                        newList = new List(list); 
                        result = newList;
                    } 

                    if (newList != null)
                    {
                        newList[idx] = newElement; 
                    }
                } 
            } 
            return result;
        } 

        private DbExpression VisitUnary(DbUnaryExpression expression, Func callback)
        {
            DbExpression result = expression; 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            if (!object.ReferenceEquals(expression.Argument, newArgument)) 
            { 
                result = callback(newArgument);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        private DbExpression VisitTypeUnary(DbUnaryExpression expression, TypeUsage type, Func callback)
        { 
            DbExpression result = expression; 

            DbExpression newArgument = this.VisitExpression(expression.Argument); 
            TypeUsage newType = this.VisitTypeUsage(type);

            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(type, newType)) 
            {
                result = callback(newArgument, newType); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        private DbExpression VisitBinary(DbBinaryExpression expression, Func callback)
        { 
            DbExpression result = expression;
 
            DbExpression newLeft = this.VisitExpression(expression.Left); 
            DbExpression newRight = this.VisitExpression(expression.Right);
            if (!object.ReferenceEquals(expression.Left, newLeft) || 
                !object.ReferenceEquals(expression.Right, newRight))
            {
                result = callback(newLeft, newRight);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        private DbRelatedEntityRef VisitRelatedEntityRef(DbRelatedEntityRef entityRef) 
        {
            RelationshipEndMember newSource;
            RelationshipEndMember newTarget;
            VisitRelationshipEnds(entityRef.SourceEnd, entityRef.TargetEnd, out newSource, out newTarget); 
            DbExpression newTargetRef = this.VisitExpression(entityRef.TargetEntityReference);
 
            if (!object.ReferenceEquals(entityRef.SourceEnd, newSource) || 
                !object.ReferenceEquals(entityRef.TargetEnd, newTarget) ||
                !object.ReferenceEquals(entityRef.TargetEntityReference, newTargetRef)) 
            {
                return CqtBuilder.CreateRelatedEntityRef(newSource, newTarget, newTargetRef);
            }
            else 
            {
                return entityRef; 
            } 
        }
 
        private void VisitRelationshipEnds(RelationshipEndMember source, RelationshipEndMember target, out RelationshipEndMember newSource, out RelationshipEndMember newTarget)
        {
            //
            Debug.Assert(source.DeclaringType.EdmEquals(target.DeclaringType), "Relationship ends not declared by same relationship type?"); 
            RelationshipType mappedType = (RelationshipType)this.VisitType(target.DeclaringType);
 
            newSource = mappedType.RelationshipEndMembers[source.Name]; 
            newTarget = mappedType.RelationshipEndMembers[target.Name];
        } 

        private DbExpression VisitTerminal(DbExpression expression, Func reconstructor)
        {
            DbExpression result = expression; 
            TypeUsage newType = this.VisitTypeUsage(expression.ResultType);
            if (!object.ReferenceEquals(expression.ResultType, newType)) 
            { 
                result = reconstructor(newType);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        private void RebindVariable(DbVariableReferenceExpression from, DbVariableReferenceExpression to)
        { 
            // 
            // The variable is only considered rebound if the name and/or type is different.
            // Otherwise, the original variable reference and the new variable reference are 
            // equivalent, and no rebinding of references to the old variable is necessary.
            //
            // When considering the new/old result types,  the TypeUsage instance may be equal
            // or equivalent, but the EdmType must be the same instance, so that expressions 
            // such as a DbPropertyExpression with the DbVariableReferenceExpression as the Instance
            // continue to be valid. 
            // 
            if (!from.VariableName.Equals(to.VariableName, StringComparison.Ordinal) ||
                !object.ReferenceEquals(from.ResultType.EdmType, to.ResultType.EdmType) || 
                !from.ResultType.EdmEquals(to.ResultType))
            {
                this.varMappings[from] = to;
                this.OnVariableRebound(from, to); 
            }
        } 
 
        private DbExpressionBinding VisitExpressionBindingEnterScope(DbExpressionBinding binding)
        { 
            DbExpressionBinding result = this.VisitExpressionBinding(binding);
            this.OnEnterScope(new[] { result.Variable });
            return result;
        } 

        private void EnterScope(params DbVariableReferenceExpression[] scopeVars) 
        { 
            this.OnEnterScope(scopeVars);
        } 

        private void ExitScope()
        {
            this.OnExitScope(); 
        }
 
        #endregion 

        #region DbExpressionVisitor Members 

        public override DbExpression Visit(DbExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            throw EntityUtil.NotSupported(System.Data.Entity.Strings.Cqt_General_UnsupportedExpression(expression.GetType().FullName)); 
        } 

        public override DbExpression Visit(DbConstantExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            // Note that it is only safe to call DbConstantExpression.GetValue because the call to 
            // DbExpressionBuilder.Constant must clone immutable values (byte[]).
            return VisitTerminal(expression, newType => CqtBuilder.Constant(newType, expression.GetValue())); 
        } 

        public override DbExpression Visit(DbNullExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitTerminal(expression, CqtBuilder.Null); 
        }
 
        public override DbExpression Visit(DbVariableReferenceExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression;
            DbVariableReferenceExpression newRef;
            if (this.varMappings.TryGetValue(expression, out newRef)) 
            {
                result = newRef; 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbParameterReferenceExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitTerminal(expression, newType => CqtBuilder.Parameter(newType, expression.ParameterName)); 
        }
 
        public override DbExpression Visit(DbFunctionExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
            IList newArguments = this.VisitExpressionList(expression.Arguments); 
            EdmFunction newFunction = this.VisitFunction(expression.Function); 
            if (!object.ReferenceEquals(expression.Arguments, newArguments) ||
                !object.ReferenceEquals(expression.Function, newFunction)) 
            {
                result = CqtBuilder.Invoke(newFunction, newArguments);
            }
 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbLambdaExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 
            IList newArguments = this.VisitExpressionList(expression.Arguments);
            DbLambda newLambda = this.VisitLambda(expression.Lambda); 
 
            if (!object.ReferenceEquals(expression.Arguments, newArguments) ||
                !object.ReferenceEquals(expression.Lambda, newLambda)) 
            {
                result = CqtBuilder.Invoke(newLambda, newArguments);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbPropertyExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
            DbExpression newInstance = this.VisitExpression(expression.Instance); 
            if (!object.ReferenceEquals(expression.Instance, newInstance))
            { 
                result = CqtBuilder.Property(newInstance, expression.Property.Name); 
            }
            NotifyIfChanged(expression, result); 
            return result;
        }

        public override DbExpression Visit(DbComparisonExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            switch(expression.ExpressionKind)
            { 
                case DbExpressionKind.Equals:
                    return this.VisitBinary(expression, CqtBuilder.Equal);

                case DbExpressionKind.NotEquals: 
                    return this.VisitBinary(expression, CqtBuilder.NotEqual);
 
                case DbExpressionKind.GreaterThan: 
                    return this.VisitBinary(expression, CqtBuilder.GreaterThan);
 
                case DbExpressionKind.GreaterThanOrEquals:
                    return this.VisitBinary(expression, CqtBuilder.GreaterThanOrEqual);

                case DbExpressionKind.LessThan: 
                    return this.VisitBinary(expression, CqtBuilder.LessThan);
 
                case DbExpressionKind.LessThanOrEquals: 
                    return this.VisitBinary(expression, CqtBuilder.LessThanOrEqual);
 
                default:
                    throw EntityUtil.NotSupported();
            }
        } 

        public override DbExpression Visit(DbLikeExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpression newArgument = this.VisitExpression(expression.Argument);
            DbExpression newPattern = this.VisitExpression(expression.Pattern); 
            DbExpression newEscape = this.VisitExpression(expression.Escape);
 
            if (!object.ReferenceEquals(expression.Argument, newArgument) || 
                !object.ReferenceEquals(expression.Pattern, newPattern) ||
                !object.ReferenceEquals(expression.Escape, newEscape)) 
            {
                result = CqtBuilder.Like(newArgument, newPattern, newEscape);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbLimitExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            DbExpression newLimit = this.VisitExpression(expression.Limit); 
 
            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(expression.Limit, newLimit)) 
            {
                Debug.Assert(!expression.WithTies, "Limit.WithTies == true?");
                result = CqtBuilder.Limit(newArgument, newLimit);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbIsNullExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitUnary(expression, exp => 
                {
                    if(TypeSemantics.IsRowType(exp.ResultType)) 
                    { 
                        //
                        return CqtBuilder.CreateIsNullExpressionAllowingRowTypeArgument(exp); 
                    }
                    else
                    {
                        return CqtBuilder.IsNull(exp); 
                    }
                } 
            ); 
        }
 
        public override DbExpression Visit(DbArithmeticExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
            IList newArguments = this.VisitExpressionList(expression.Arguments); 
            if (!object.ReferenceEquals(expression.Arguments, newArguments)) 
            {
                switch(expression.ExpressionKind) 
                {
                    case DbExpressionKind.Divide:
                        result = CqtBuilder.Divide(newArguments[0], newArguments[1]);
                        break; 

                    case DbExpressionKind.Minus: 
                        result = CqtBuilder.Minus(newArguments[0], newArguments[1]); 
                        break;
 
                    case DbExpressionKind.Modulo:
                        result = CqtBuilder.Modulo(newArguments[0], newArguments[1]);
                        break;
 
                    case DbExpressionKind.Multiply:
                        result = CqtBuilder.Multiply(newArguments[0], newArguments[1]); 
                        break; 

                    case DbExpressionKind.Plus: 
                        result = CqtBuilder.Plus(newArguments[0], newArguments[1]);
                        break;

                    case DbExpressionKind.UnaryMinus: 
                        result = CqtBuilder.UnaryMinus(newArguments[0]);
                        break; 
 
                    default:
                        throw EntityUtil.NotSupported(); 
                }
            }
            NotifyIfChanged(expression, result);
            return result; 
        }
 
        public override DbExpression Visit(DbAndExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.And);
        }
 
        public override DbExpression Visit(DbOrExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.Or); 
        }

        public override DbExpression Visit(DbNotExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitUnary(expression, CqtBuilder.Not); 
        }
 
        public override DbExpression Visit(DbDistinctExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitUnary(expression, CqtBuilder.Distinct);
        } 
 
        public override DbExpression Visit(DbElementExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            Func resultConstructor;
            if (expression.IsSinglePropertyUnwrapped) 
            {
                // 
                resultConstructor = CqtBuilder.CreateElementExpressionUnwrapSingleProperty; 
            }
            else 
            {
                resultConstructor = CqtBuilder.Element;
            }
 
            return VisitUnary(expression, resultConstructor);
        } 
 
        public override DbExpression Visit(DbIsEmptyExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitUnary(expression, CqtBuilder.IsEmpty);
        } 

        public override DbExpression Visit(DbUnionAllExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitBinary(expression, CqtBuilder.UnionAll);
        }

        public override DbExpression Visit(DbIntersectExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            return VisitBinary(expression, CqtBuilder.Intersect);
        } 

        public override DbExpression Visit(DbExceptExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.Except); 
        } 

        public override DbExpression Visit(DbTreatExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return this.VisitTypeUnary(expression, expression.ResultType, CqtBuilder.TreatAs); 
        }
 
        public override DbExpression Visit(DbIsOfExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            if (expression.ExpressionKind == DbExpressionKind.IsOfOnly)
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.IsOfOnly); 
            }
            else 
            { 
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.IsOf);
            } 
        }

        public override DbExpression Visit(DbCastExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return this.VisitTypeUnary(expression, expression.ResultType, CqtBuilder.CastTo); 
        }
 
        public override DbExpression Visit(DbCaseExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
 
            IList newWhens = this.VisitExpressionList(expression.When); 
            IList newThens = this.VisitExpressionList(expression.Then);
            DbExpression newElse = this.VisitExpression(expression.Else); 

            if (!object.ReferenceEquals(expression.When, newWhens) ||
                !object.ReferenceEquals(expression.Then, newThens) ||
                !object.ReferenceEquals(expression.Else, newElse)) 
            {
                result = CqtBuilder.Case(newWhens, newThens, newElse); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbOfTypeExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            if (expression.ExpressionKind == DbExpressionKind.OfTypeOnly) 
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.OfTypeOnly); 
            }
            else
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.OfType); 
            }
        } 
 
        public override DbExpression Visit(DbNewInstanceExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
            TypeUsage newType = this.VisitTypeUsage(expression.ResultType); 
            IList newArguments = this.VisitExpressionList(expression.Arguments);
            bool unchanged = (object.ReferenceEquals(expression.ResultType, newType) && object.ReferenceEquals(expression.Arguments, newArguments)); 
            if (expression.HasRelatedEntityReferences) 
            {
                IList newRefs = this.VisitList(expression.RelatedEntityReferences, this.VisitRelatedEntityRef); 
                if (!unchanged ||
                    !object.ReferenceEquals(expression.RelatedEntityReferences, newRefs))
                {
                    result = CqtBuilder.CreateNewEntityWithRelationshipsExpression((EntityType)newType.EdmType, newArguments, newRefs); 
                }
            } 
            else 
            {
                if (!unchanged) 
                {
                    result = CqtBuilder.New(newType, System.Linq.Enumerable.ToArray(newArguments));
                }
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbRefExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            EntityType targetType = (EntityType)TypeHelpers.GetEdmType(expression.ResultType).ElementType; 
 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            EntityType newType = (EntityType)this.VisitType(targetType); 
            EntitySet newSet = (EntitySet)this.VisitEntitySet(expression.EntitySet);
            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(targetType, newType) ||
                !object.ReferenceEquals(expression.EntitySet, newSet)) 
            {
                result = CqtBuilder.RefFromKey(newSet, newArgument, newType); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbRelationshipNavigationExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression; 

            RelationshipEndMember newFrom; 
            RelationshipEndMember newTo;
            VisitRelationshipEnds(expression.NavigateFrom, expression.NavigateTo, out newFrom, out newTo);
            DbExpression newNavSource = this.VisitExpression(expression.NavigationSource);
 
            if (!object.ReferenceEquals(expression.NavigateFrom, newFrom) ||
                !object.ReferenceEquals(expression.NavigateTo, newTo) || 
                !object.ReferenceEquals(expression.NavigationSource, newNavSource)) 
            {
                result = CqtBuilder.Navigate(newNavSource, newFrom, newTo); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbDerefExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return this.VisitUnary(expression, CqtBuilder.Deref);
        }

        public override DbExpression Visit(DbRefKeyExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            return this.VisitUnary(expression, CqtBuilder.GetRefKey);
        } 

        public override DbExpression Visit(DbEntityRefExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return this.VisitUnary(expression, CqtBuilder.GetEntityRef); 
        } 

        public override DbExpression Visit(DbScanExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            EntitySetBase newSet = this.VisitEntitySet(expression.Target); 
            if (!object.ReferenceEquals(expression.Target, newSet)) 
            {
                result = CqtBuilder.Scan(newSet); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbFilterExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpression predicate = this.VisitExpression(expression.Predicate); 
            this.ExitScope();
            if (!object.ReferenceEquals(expression.Input, input) || 
                !object.ReferenceEquals(expression.Predicate, predicate)) 
            {
                result = CqtBuilder.Filter(input, predicate); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbProjectExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpression projection = this.VisitExpression(expression.Projection); 
            this.ExitScope();
            if (!object.ReferenceEquals(expression.Input, input) || 
                !object.ReferenceEquals(expression.Projection, projection)) 
            {
                result = CqtBuilder.Project(input, projection); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbCrossJoinExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            IList newInputs = this.VisitExpressionBindingList(expression.Inputs);
            if (!object.ReferenceEquals(expression.Inputs, newInputs)) 
            {
                result = CqtBuilder.CrossJoin(newInputs); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbJoinExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression; 

            DbExpressionBinding newLeft = this.VisitExpressionBinding(expression.Left); 
            DbExpressionBinding newRight = this.VisitExpressionBinding(expression.Right);

            this.EnterScope(newLeft.Variable, newRight.Variable);
            DbExpression newCondition = this.VisitExpression(expression.JoinCondition); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Left, newLeft) || 
                !object.ReferenceEquals(expression.Right, newRight) ||
                !object.ReferenceEquals(expression.JoinCondition, newCondition)) 
            {
                if (DbExpressionKind.InnerJoin == expression.ExpressionKind)
                {
                    result = CqtBuilder.InnerJoin(newLeft, newRight, newCondition); 
                }
                else if (DbExpressionKind.LeftOuterJoin == expression.ExpressionKind) 
                { 
                    result = CqtBuilder.LeftOuterJoin(newLeft, newRight, newCondition);
                } 
                else
                {
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.FullOuterJoin, "DbJoinExpression had ExpressionKind other than InnerJoin, LeftOuterJoin or FullOuterJoin?");
                    result = CqtBuilder.FullOuterJoin(newLeft, newRight, newCondition); 
                }
            } 
            NotifyIfChanged(expression, result); 
            return result;
        } 

        public override DbExpression Visit(DbApplyExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 
 
            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpressionBinding newApply = this.VisitExpressionBinding(expression.Apply); 
            this.ExitScope();

            if (!object.ReferenceEquals(expression.Input, newInput) ||
                !object.ReferenceEquals(expression.Apply, newApply)) 
            {
                if (DbExpressionKind.CrossApply == expression.ExpressionKind) 
                { 
                    result = CqtBuilder.CrossApply(newInput, newApply);
                } 
                else
                {
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.OuterApply, "DbApplyExpression had ExpressionKind other than CrossApply or OuterApply?");
                    result = CqtBuilder.OuterApply(newInput, newApply); 
                }
            } 
            NotifyIfChanged(expression, result); 
            return result;
        } 

        public override DbExpression Visit(DbGroupByExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 
 
            DbGroupExpressionBinding newInput = this.VisitGroupExpressionBinding(expression.Input);
            this.EnterScope(newInput.Variable); 
            IList newKeys = this.VisitExpressionList(expression.Keys);
            this.ExitScope();
            this.EnterScope(newInput.GroupVariable);
            IList newAggs = this.VisitList(expression.Aggregates, this.VisitAggregate); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.Keys, newKeys) ||
                !object.ReferenceEquals(expression.Aggregates, newAggs)) 
            {
                RowType groupOutput =
                    TypeHelpers.GetEdmType(TypeHelpers.GetEdmType(expression.ResultType).TypeUsage);
 
                var boundKeys = groupOutput.Properties.Take(newKeys.Count).Select(p => p.Name).Zip(newKeys).ToList();
                var boundAggs = groupOutput.Properties.Skip(newKeys.Count).Select(p => p.Name).Zip(newAggs).ToList(); 
 
                result = CqtBuilder.GroupBy(newInput, boundKeys, boundAggs);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        public override DbExpression Visit(DbSkipExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 

            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            IList newSortOrder = this.VisitSortOrder(expression.SortOrder);
            this.ExitScope(); 
            DbExpression newCount = this.VisitExpression(expression.Count);
 
            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.SortOrder, newSortOrder) ||
                !object.ReferenceEquals(expression.Count, newCount)) 
            {
                result = CqtBuilder.Skip(newInput, newSortOrder, newCount);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbSortExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
 
            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            IList newSortOrder = this.VisitSortOrder(expression.SortOrder); 
            this.ExitScope(); 

            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.SortOrder, newSortOrder))
            {
                result = CqtBuilder.Sort(newInput, newSortOrder);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbQuantifierExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input); 
            DbExpression predicate = this.VisitExpression(expression.Predicate); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Input, input) ||
                !object.ReferenceEquals(expression.Predicate, predicate))
            {
                if (DbExpressionKind.All == expression.ExpressionKind) 
                {
                    result = CqtBuilder.All(input, predicate); 
                } 
                else
                { 
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.Any, "DbQuantifierExpression had ExpressionKind other than All or Any?");
                    result = CqtBuilder.Any(input, predicate);
                }
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees; 
using CqtBuilder = System.Data.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder;
using System.Linq; 
 
namespace System.Data.Common.CommandTrees
{ 
    /// 
    /// Visits each element of an expression tree from a given root expression. If any element changes, the tree is
    /// rebuilt back to the root and the new root expression is returned; otherwise the original root expression is returned.
    ///  
#if PUBLIC_DBEXPRESSIONBUILDER
    public 
#endif 
    class DefaultExpressionVisitor : DbExpressionVisitor
    { 
        private readonly Dictionary varMappings = new Dictionary();

        protected DefaultExpressionVisitor()
        { 
        }
 
        protected virtual void OnExpressionReplaced(DbExpression oldExpression, DbExpression newExpression) 
        {
        } 

        protected virtual void OnVariableRebound(DbVariableReferenceExpression fromVarRef, DbVariableReferenceExpression toVarRef)
        {
        } 

        protected virtual void OnEnterScope(IEnumerable scopeVariables) 
        { 
        }
 
        protected virtual void OnExitScope()
        {
        }
 
        protected virtual DbExpression VisitExpression(DbExpression expression)
        { 
            DbExpression newValue = null; 
            if (expression != null)
            { 
                newValue = expression.Accept(this);
            }

            return newValue; 
        }
 
        protected virtual IList VisitExpressionList(IList list) 
        {
            return VisitList(list, this.VisitExpression); 
        }

        protected virtual DbExpressionBinding VisitExpressionBinding(DbExpressionBinding binding)
        { 
            DbExpressionBinding result = binding;
            if (binding != null) 
            { 
                DbExpression newInput = this.VisitExpression(binding.Expression);
                if (!object.ReferenceEquals(binding.Expression, newInput)) 
                {
                    result = CqtBuilder.BindAs(newInput, binding.VariableName);
                    this.RebindVariable(binding.Variable, result.Variable);
                } 
            }
            return result; 
        } 

        protected virtual IList VisitExpressionBindingList(IList list) 
        {
            return this.VisitList(list, this.VisitExpressionBinding);
        }
 
        protected virtual DbGroupExpressionBinding VisitGroupExpressionBinding(DbGroupExpressionBinding binding)
        { 
            DbGroupExpressionBinding result = binding; 
            if (binding != null)
            { 
                DbExpression newInput = this.VisitExpression(binding.Expression);
                if (!object.ReferenceEquals(binding.Expression, newInput))
                {
                    result = CqtBuilder.GroupBindAs(newInput, binding.VariableName, binding.GroupVariableName); 
                    this.RebindVariable(binding.Variable, result.Variable);
                    this.RebindVariable(binding.GroupVariable, result.GroupVariable); 
                } 
            }
            return result; 
        }

        protected virtual DbSortClause VisitSortClause(DbSortClause clause)
        { 
            DbSortClause result = clause;
            if (clause != null) 
            { 
                DbExpression newExpression = this.VisitExpression(clause.Expression);
                if (!object.ReferenceEquals(clause.Expression, newExpression)) 
                {
                    if (!string.IsNullOrEmpty(clause.Collation))
                    {
                        result = (clause.Ascending ? CqtBuilder.ToSortClause(newExpression, clause.Collation) : CqtBuilder.ToSortClauseDescending(newExpression, clause.Collation)); 
                    }
                    else 
                    { 
                        result = (clause.Ascending ? CqtBuilder.ToSortClause(newExpression) : CqtBuilder.ToSortClauseDescending(newExpression));
                    } 
                }
            }
            return result;
        } 

        protected virtual IList VisitSortOrder(IList sortOrder) 
        { 
            return VisitList(sortOrder, this.VisitSortClause);
        } 

        protected virtual DbAggregate VisitAggregate(DbAggregate aggregate)
        {
            // Currently only function or group aggregate are possible 
            DbFunctionAggregate functionAggregate = aggregate as DbFunctionAggregate;
            if (functionAggregate != null) 
            { 
                return VisitFunctionAggregate(functionAggregate);
            } 

            DbGroupAggregate groupAggregate = (DbGroupAggregate)aggregate;
            return VisitGroupAggregate(groupAggregate);
        } 

        protected virtual DbFunctionAggregate VisitFunctionAggregate(DbFunctionAggregate aggregate) 
        { 
            DbFunctionAggregate result = aggregate;
            if (aggregate != null) 
            {
                EdmFunction newFunction = this.VisitFunction(aggregate.Function);
                IList newArguments = this.VisitExpressionList(aggregate.Arguments);
 
                Debug.Assert(newArguments.Count == 1, "Function aggregate had more than one argument?");
 
                if (!object.ReferenceEquals(aggregate.Function, newFunction) || 
                    !object.ReferenceEquals(aggregate.Arguments, newArguments))
                { 
                    if (aggregate.Distinct)
                    {
                        result = CqtBuilder.AggregateDistinct(newFunction, newArguments[0]);
                    } 
                    else
                    { 
                        result = CqtBuilder.Aggregate(newFunction, newArguments[0]); 
                    }
                } 
            }
            return result;
        }
 
        protected virtual DbGroupAggregate VisitGroupAggregate(DbGroupAggregate aggregate)
        { 
            DbGroupAggregate result = aggregate; 
            if (aggregate != null)
            { 
                IList newArguments = this.VisitExpressionList(aggregate.Arguments);
                Debug.Assert(newArguments.Count == 1, "Group aggregate had more than one argument?");

                if (!object.ReferenceEquals(aggregate.Arguments, newArguments)) 
                {
                    result = CqtBuilder.GroupAggregate(newArguments[0]); 
                } 
            }
            return result; 
        }

        protected virtual DbLambda VisitLambda(DbLambda lambda)
        { 
            EntityUtil.CheckArgumentNull(lambda, "lambda");
 
            DbLambda result = lambda; 
            IList newFormals = this.VisitList(lambda.Variables, varRef =>
                { 
                    TypeUsage newVarType = this.VisitTypeUsage(varRef.ResultType);
                    if (!object.ReferenceEquals(varRef.ResultType, newVarType))
                    {
                        return CqtBuilder.Variable(newVarType, varRef.VariableName); 
                    }
                    else 
                    { 
                        return varRef;
                    } 
                }
            );
            this.EnterScope(newFormals.ToArray()); // ToArray: Don't pass the List instance directly to OnEnterScope
            DbExpression newBody = this.VisitExpression(lambda.Body); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(lambda.Variables, newFormals) || 
                !object.ReferenceEquals(lambda.Body, newBody))
            { 
                result = CqtBuilder.Lambda(newBody, newFormals);
            }
            return result;
        } 

        // Metadata 'Visitor' methods 
        protected virtual EdmType VisitType(EdmType type) { return type; } 
        protected virtual TypeUsage VisitTypeUsage(TypeUsage type) { return type; }
        protected virtual EntitySetBase VisitEntitySet(EntitySetBase entitySet) { return entitySet; } 
        protected virtual EdmFunction VisitFunction(EdmFunction functionMetadata) { return functionMetadata; }

        #region Private Implementation
 
        private void NotifyIfChanged(DbExpression originalExpression, DbExpression newExpression)
        { 
            if (!object.ReferenceEquals(originalExpression, newExpression)) 
            {
                this.OnExpressionReplaced(originalExpression, newExpression); 
            }
        }

        private IList VisitList(IList list, Func map) 
        {
            IList result = list; 
            if(list != null) 
            {
                List newList = null; 
                for (int idx = 0; idx < list.Count; idx++)
                {
                    TElement newElement = map(list[idx]);
                    if (newList == null && 
                        !object.ReferenceEquals(list[idx], newElement))
                    { 
                        newList = new List(list); 
                        result = newList;
                    } 

                    if (newList != null)
                    {
                        newList[idx] = newElement; 
                    }
                } 
            } 
            return result;
        } 

        private DbExpression VisitUnary(DbUnaryExpression expression, Func callback)
        {
            DbExpression result = expression; 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            if (!object.ReferenceEquals(expression.Argument, newArgument)) 
            { 
                result = callback(newArgument);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        private DbExpression VisitTypeUnary(DbUnaryExpression expression, TypeUsage type, Func callback)
        { 
            DbExpression result = expression; 

            DbExpression newArgument = this.VisitExpression(expression.Argument); 
            TypeUsage newType = this.VisitTypeUsage(type);

            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(type, newType)) 
            {
                result = callback(newArgument, newType); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        private DbExpression VisitBinary(DbBinaryExpression expression, Func callback)
        { 
            DbExpression result = expression;
 
            DbExpression newLeft = this.VisitExpression(expression.Left); 
            DbExpression newRight = this.VisitExpression(expression.Right);
            if (!object.ReferenceEquals(expression.Left, newLeft) || 
                !object.ReferenceEquals(expression.Right, newRight))
            {
                result = callback(newLeft, newRight);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        private DbRelatedEntityRef VisitRelatedEntityRef(DbRelatedEntityRef entityRef) 
        {
            RelationshipEndMember newSource;
            RelationshipEndMember newTarget;
            VisitRelationshipEnds(entityRef.SourceEnd, entityRef.TargetEnd, out newSource, out newTarget); 
            DbExpression newTargetRef = this.VisitExpression(entityRef.TargetEntityReference);
 
            if (!object.ReferenceEquals(entityRef.SourceEnd, newSource) || 
                !object.ReferenceEquals(entityRef.TargetEnd, newTarget) ||
                !object.ReferenceEquals(entityRef.TargetEntityReference, newTargetRef)) 
            {
                return CqtBuilder.CreateRelatedEntityRef(newSource, newTarget, newTargetRef);
            }
            else 
            {
                return entityRef; 
            } 
        }
 
        private void VisitRelationshipEnds(RelationshipEndMember source, RelationshipEndMember target, out RelationshipEndMember newSource, out RelationshipEndMember newTarget)
        {
            //
            Debug.Assert(source.DeclaringType.EdmEquals(target.DeclaringType), "Relationship ends not declared by same relationship type?"); 
            RelationshipType mappedType = (RelationshipType)this.VisitType(target.DeclaringType);
 
            newSource = mappedType.RelationshipEndMembers[source.Name]; 
            newTarget = mappedType.RelationshipEndMembers[target.Name];
        } 

        private DbExpression VisitTerminal(DbExpression expression, Func reconstructor)
        {
            DbExpression result = expression; 
            TypeUsage newType = this.VisitTypeUsage(expression.ResultType);
            if (!object.ReferenceEquals(expression.ResultType, newType)) 
            { 
                result = reconstructor(newType);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        private void RebindVariable(DbVariableReferenceExpression from, DbVariableReferenceExpression to)
        { 
            // 
            // The variable is only considered rebound if the name and/or type is different.
            // Otherwise, the original variable reference and the new variable reference are 
            // equivalent, and no rebinding of references to the old variable is necessary.
            //
            // When considering the new/old result types,  the TypeUsage instance may be equal
            // or equivalent, but the EdmType must be the same instance, so that expressions 
            // such as a DbPropertyExpression with the DbVariableReferenceExpression as the Instance
            // continue to be valid. 
            // 
            if (!from.VariableName.Equals(to.VariableName, StringComparison.Ordinal) ||
                !object.ReferenceEquals(from.ResultType.EdmType, to.ResultType.EdmType) || 
                !from.ResultType.EdmEquals(to.ResultType))
            {
                this.varMappings[from] = to;
                this.OnVariableRebound(from, to); 
            }
        } 
 
        private DbExpressionBinding VisitExpressionBindingEnterScope(DbExpressionBinding binding)
        { 
            DbExpressionBinding result = this.VisitExpressionBinding(binding);
            this.OnEnterScope(new[] { result.Variable });
            return result;
        } 

        private void EnterScope(params DbVariableReferenceExpression[] scopeVars) 
        { 
            this.OnEnterScope(scopeVars);
        } 

        private void ExitScope()
        {
            this.OnExitScope(); 
        }
 
        #endregion 

        #region DbExpressionVisitor Members 

        public override DbExpression Visit(DbExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            throw EntityUtil.NotSupported(System.Data.Entity.Strings.Cqt_General_UnsupportedExpression(expression.GetType().FullName)); 
        } 

        public override DbExpression Visit(DbConstantExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            // Note that it is only safe to call DbConstantExpression.GetValue because the call to 
            // DbExpressionBuilder.Constant must clone immutable values (byte[]).
            return VisitTerminal(expression, newType => CqtBuilder.Constant(newType, expression.GetValue())); 
        } 

        public override DbExpression Visit(DbNullExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitTerminal(expression, CqtBuilder.Null); 
        }
 
        public override DbExpression Visit(DbVariableReferenceExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression;
            DbVariableReferenceExpression newRef;
            if (this.varMappings.TryGetValue(expression, out newRef)) 
            {
                result = newRef; 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbParameterReferenceExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitTerminal(expression, newType => CqtBuilder.Parameter(newType, expression.ParameterName)); 
        }
 
        public override DbExpression Visit(DbFunctionExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
            IList newArguments = this.VisitExpressionList(expression.Arguments); 
            EdmFunction newFunction = this.VisitFunction(expression.Function); 
            if (!object.ReferenceEquals(expression.Arguments, newArguments) ||
                !object.ReferenceEquals(expression.Function, newFunction)) 
            {
                result = CqtBuilder.Invoke(newFunction, newArguments);
            }
 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbLambdaExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 
            IList newArguments = this.VisitExpressionList(expression.Arguments);
            DbLambda newLambda = this.VisitLambda(expression.Lambda); 
 
            if (!object.ReferenceEquals(expression.Arguments, newArguments) ||
                !object.ReferenceEquals(expression.Lambda, newLambda)) 
            {
                result = CqtBuilder.Invoke(newLambda, newArguments);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbPropertyExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
            DbExpression newInstance = this.VisitExpression(expression.Instance); 
            if (!object.ReferenceEquals(expression.Instance, newInstance))
            { 
                result = CqtBuilder.Property(newInstance, expression.Property.Name); 
            }
            NotifyIfChanged(expression, result); 
            return result;
        }

        public override DbExpression Visit(DbComparisonExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            switch(expression.ExpressionKind)
            { 
                case DbExpressionKind.Equals:
                    return this.VisitBinary(expression, CqtBuilder.Equal);

                case DbExpressionKind.NotEquals: 
                    return this.VisitBinary(expression, CqtBuilder.NotEqual);
 
                case DbExpressionKind.GreaterThan: 
                    return this.VisitBinary(expression, CqtBuilder.GreaterThan);
 
                case DbExpressionKind.GreaterThanOrEquals:
                    return this.VisitBinary(expression, CqtBuilder.GreaterThanOrEqual);

                case DbExpressionKind.LessThan: 
                    return this.VisitBinary(expression, CqtBuilder.LessThan);
 
                case DbExpressionKind.LessThanOrEquals: 
                    return this.VisitBinary(expression, CqtBuilder.LessThanOrEqual);
 
                default:
                    throw EntityUtil.NotSupported();
            }
        } 

        public override DbExpression Visit(DbLikeExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpression newArgument = this.VisitExpression(expression.Argument);
            DbExpression newPattern = this.VisitExpression(expression.Pattern); 
            DbExpression newEscape = this.VisitExpression(expression.Escape);
 
            if (!object.ReferenceEquals(expression.Argument, newArgument) || 
                !object.ReferenceEquals(expression.Pattern, newPattern) ||
                !object.ReferenceEquals(expression.Escape, newEscape)) 
            {
                result = CqtBuilder.Like(newArgument, newPattern, newEscape);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbLimitExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            DbExpression newLimit = this.VisitExpression(expression.Limit); 
 
            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(expression.Limit, newLimit)) 
            {
                Debug.Assert(!expression.WithTies, "Limit.WithTies == true?");
                result = CqtBuilder.Limit(newArgument, newLimit);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbIsNullExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitUnary(expression, exp => 
                {
                    if(TypeSemantics.IsRowType(exp.ResultType)) 
                    { 
                        //
                        return CqtBuilder.CreateIsNullExpressionAllowingRowTypeArgument(exp); 
                    }
                    else
                    {
                        return CqtBuilder.IsNull(exp); 
                    }
                } 
            ); 
        }
 
        public override DbExpression Visit(DbArithmeticExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
            IList newArguments = this.VisitExpressionList(expression.Arguments); 
            if (!object.ReferenceEquals(expression.Arguments, newArguments)) 
            {
                switch(expression.ExpressionKind) 
                {
                    case DbExpressionKind.Divide:
                        result = CqtBuilder.Divide(newArguments[0], newArguments[1]);
                        break; 

                    case DbExpressionKind.Minus: 
                        result = CqtBuilder.Minus(newArguments[0], newArguments[1]); 
                        break;
 
                    case DbExpressionKind.Modulo:
                        result = CqtBuilder.Modulo(newArguments[0], newArguments[1]);
                        break;
 
                    case DbExpressionKind.Multiply:
                        result = CqtBuilder.Multiply(newArguments[0], newArguments[1]); 
                        break; 

                    case DbExpressionKind.Plus: 
                        result = CqtBuilder.Plus(newArguments[0], newArguments[1]);
                        break;

                    case DbExpressionKind.UnaryMinus: 
                        result = CqtBuilder.UnaryMinus(newArguments[0]);
                        break; 
 
                    default:
                        throw EntityUtil.NotSupported(); 
                }
            }
            NotifyIfChanged(expression, result);
            return result; 
        }
 
        public override DbExpression Visit(DbAndExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.And);
        }
 
        public override DbExpression Visit(DbOrExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.Or); 
        }

        public override DbExpression Visit(DbNotExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitUnary(expression, CqtBuilder.Not); 
        }
 
        public override DbExpression Visit(DbDistinctExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitUnary(expression, CqtBuilder.Distinct);
        } 
 
        public override DbExpression Visit(DbElementExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            Func resultConstructor;
            if (expression.IsSinglePropertyUnwrapped) 
            {
                // 
                resultConstructor = CqtBuilder.CreateElementExpressionUnwrapSingleProperty; 
            }
            else 
            {
                resultConstructor = CqtBuilder.Element;
            }
 
            return VisitUnary(expression, resultConstructor);
        } 
 
        public override DbExpression Visit(DbIsEmptyExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            return VisitUnary(expression, CqtBuilder.IsEmpty);
        } 

        public override DbExpression Visit(DbUnionAllExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return VisitBinary(expression, CqtBuilder.UnionAll);
        }

        public override DbExpression Visit(DbIntersectExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            return VisitBinary(expression, CqtBuilder.Intersect);
        } 

        public override DbExpression Visit(DbExceptExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return VisitBinary(expression, CqtBuilder.Except); 
        } 

        public override DbExpression Visit(DbTreatExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            return this.VisitTypeUnary(expression, expression.ResultType, CqtBuilder.TreatAs); 
        }
 
        public override DbExpression Visit(DbIsOfExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            if (expression.ExpressionKind == DbExpressionKind.IsOfOnly)
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.IsOfOnly); 
            }
            else 
            { 
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.IsOf);
            } 
        }

        public override DbExpression Visit(DbCastExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return this.VisitTypeUnary(expression, expression.ResultType, CqtBuilder.CastTo); 
        }
 
        public override DbExpression Visit(DbCaseExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;
 
            IList newWhens = this.VisitExpressionList(expression.When); 
            IList newThens = this.VisitExpressionList(expression.Then);
            DbExpression newElse = this.VisitExpression(expression.Else); 

            if (!object.ReferenceEquals(expression.When, newWhens) ||
                !object.ReferenceEquals(expression.Then, newThens) ||
                !object.ReferenceEquals(expression.Else, newElse)) 
            {
                result = CqtBuilder.Case(newWhens, newThens, newElse); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbOfTypeExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            if (expression.ExpressionKind == DbExpressionKind.OfTypeOnly) 
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.OfTypeOnly); 
            }
            else
            {
                return this.VisitTypeUnary(expression, expression.OfType, CqtBuilder.OfType); 
            }
        } 
 
        public override DbExpression Visit(DbNewInstanceExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
            TypeUsage newType = this.VisitTypeUsage(expression.ResultType); 
            IList newArguments = this.VisitExpressionList(expression.Arguments);
            bool unchanged = (object.ReferenceEquals(expression.ResultType, newType) && object.ReferenceEquals(expression.Arguments, newArguments)); 
            if (expression.HasRelatedEntityReferences) 
            {
                IList newRefs = this.VisitList(expression.RelatedEntityReferences, this.VisitRelatedEntityRef); 
                if (!unchanged ||
                    !object.ReferenceEquals(expression.RelatedEntityReferences, newRefs))
                {
                    result = CqtBuilder.CreateNewEntityWithRelationshipsExpression((EntityType)newType.EdmType, newArguments, newRefs); 
                }
            } 
            else 
            {
                if (!unchanged) 
                {
                    result = CqtBuilder.New(newType, System.Linq.Enumerable.ToArray(newArguments));
                }
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbRefExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            EntityType targetType = (EntityType)TypeHelpers.GetEdmType(expression.ResultType).ElementType; 
 
            DbExpression newArgument = this.VisitExpression(expression.Argument);
            EntityType newType = (EntityType)this.VisitType(targetType); 
            EntitySet newSet = (EntitySet)this.VisitEntitySet(expression.EntitySet);
            if (!object.ReferenceEquals(expression.Argument, newArgument) ||
                !object.ReferenceEquals(targetType, newType) ||
                !object.ReferenceEquals(expression.EntitySet, newSet)) 
            {
                result = CqtBuilder.RefFromKey(newSet, newArgument, newType); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbRelationshipNavigationExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression; 

            RelationshipEndMember newFrom; 
            RelationshipEndMember newTo;
            VisitRelationshipEnds(expression.NavigateFrom, expression.NavigateTo, out newFrom, out newTo);
            DbExpression newNavSource = this.VisitExpression(expression.NavigationSource);
 
            if (!object.ReferenceEquals(expression.NavigateFrom, newFrom) ||
                !object.ReferenceEquals(expression.NavigateTo, newTo) || 
                !object.ReferenceEquals(expression.NavigationSource, newNavSource)) 
            {
                result = CqtBuilder.Navigate(newNavSource, newFrom, newTo); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbDerefExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            return this.VisitUnary(expression, CqtBuilder.Deref);
        }

        public override DbExpression Visit(DbRefKeyExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 
 
            return this.VisitUnary(expression, CqtBuilder.GetRefKey);
        } 

        public override DbExpression Visit(DbEntityRefExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            return this.VisitUnary(expression, CqtBuilder.GetEntityRef); 
        } 

        public override DbExpression Visit(DbScanExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            EntitySetBase newSet = this.VisitEntitySet(expression.Target); 
            if (!object.ReferenceEquals(expression.Target, newSet)) 
            {
                result = CqtBuilder.Scan(newSet); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbFilterExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpression predicate = this.VisitExpression(expression.Predicate); 
            this.ExitScope();
            if (!object.ReferenceEquals(expression.Input, input) || 
                !object.ReferenceEquals(expression.Predicate, predicate)) 
            {
                result = CqtBuilder.Filter(input, predicate); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbProjectExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpression projection = this.VisitExpression(expression.Projection); 
            this.ExitScope();
            if (!object.ReferenceEquals(expression.Input, input) || 
                !object.ReferenceEquals(expression.Projection, projection)) 
            {
                result = CqtBuilder.Project(input, projection); 
            }
            NotifyIfChanged(expression, result);
            return result;
        } 

        public override DbExpression Visit(DbCrossJoinExpression expression) 
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression;

            IList newInputs = this.VisitExpressionBindingList(expression.Inputs);
            if (!object.ReferenceEquals(expression.Inputs, newInputs)) 
            {
                result = CqtBuilder.CrossJoin(newInputs); 
            } 
            NotifyIfChanged(expression, result);
            return result; 
        }

        public override DbExpression Visit(DbJoinExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            DbExpression result = expression; 

            DbExpressionBinding newLeft = this.VisitExpressionBinding(expression.Left); 
            DbExpressionBinding newRight = this.VisitExpressionBinding(expression.Right);

            this.EnterScope(newLeft.Variable, newRight.Variable);
            DbExpression newCondition = this.VisitExpression(expression.JoinCondition); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Left, newLeft) || 
                !object.ReferenceEquals(expression.Right, newRight) ||
                !object.ReferenceEquals(expression.JoinCondition, newCondition)) 
            {
                if (DbExpressionKind.InnerJoin == expression.ExpressionKind)
                {
                    result = CqtBuilder.InnerJoin(newLeft, newRight, newCondition); 
                }
                else if (DbExpressionKind.LeftOuterJoin == expression.ExpressionKind) 
                { 
                    result = CqtBuilder.LeftOuterJoin(newLeft, newRight, newCondition);
                } 
                else
                {
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.FullOuterJoin, "DbJoinExpression had ExpressionKind other than InnerJoin, LeftOuterJoin or FullOuterJoin?");
                    result = CqtBuilder.FullOuterJoin(newLeft, newRight, newCondition); 
                }
            } 
            NotifyIfChanged(expression, result); 
            return result;
        } 

        public override DbExpression Visit(DbApplyExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 
 
            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            DbExpressionBinding newApply = this.VisitExpressionBinding(expression.Apply); 
            this.ExitScope();

            if (!object.ReferenceEquals(expression.Input, newInput) ||
                !object.ReferenceEquals(expression.Apply, newApply)) 
            {
                if (DbExpressionKind.CrossApply == expression.ExpressionKind) 
                { 
                    result = CqtBuilder.CrossApply(newInput, newApply);
                } 
                else
                {
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.OuterApply, "DbApplyExpression had ExpressionKind other than CrossApply or OuterApply?");
                    result = CqtBuilder.OuterApply(newInput, newApply); 
                }
            } 
            NotifyIfChanged(expression, result); 
            return result;
        } 

        public override DbExpression Visit(DbGroupByExpression expression)
        {
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 
 
            DbGroupExpressionBinding newInput = this.VisitGroupExpressionBinding(expression.Input);
            this.EnterScope(newInput.Variable); 
            IList newKeys = this.VisitExpressionList(expression.Keys);
            this.ExitScope();
            this.EnterScope(newInput.GroupVariable);
            IList newAggs = this.VisitList(expression.Aggregates, this.VisitAggregate); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.Keys, newKeys) ||
                !object.ReferenceEquals(expression.Aggregates, newAggs)) 
            {
                RowType groupOutput =
                    TypeHelpers.GetEdmType(TypeHelpers.GetEdmType(expression.ResultType).TypeUsage);
 
                var boundKeys = groupOutput.Properties.Take(newKeys.Count).Select(p => p.Name).Zip(newKeys).ToList();
                var boundAggs = groupOutput.Properties.Skip(newKeys.Count).Select(p => p.Name).Zip(newAggs).ToList(); 
 
                result = CqtBuilder.GroupBy(newInput, boundKeys, boundAggs);
            } 
            NotifyIfChanged(expression, result);
            return result;
        }
 
        public override DbExpression Visit(DbSkipExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression"); 

            DbExpression result = expression; 

            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            IList newSortOrder = this.VisitSortOrder(expression.SortOrder);
            this.ExitScope(); 
            DbExpression newCount = this.VisitExpression(expression.Count);
 
            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.SortOrder, newSortOrder) ||
                !object.ReferenceEquals(expression.Count, newCount)) 
            {
                result = CqtBuilder.Skip(newInput, newSortOrder, newCount);
            }
            NotifyIfChanged(expression, result); 
            return result;
        } 
 
        public override DbExpression Visit(DbSortExpression expression)
        { 
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression;
 
            DbExpressionBinding newInput = this.VisitExpressionBindingEnterScope(expression.Input);
            IList newSortOrder = this.VisitSortOrder(expression.SortOrder); 
            this.ExitScope(); 

            if (!object.ReferenceEquals(expression.Input, newInput) || 
                !object.ReferenceEquals(expression.SortOrder, newSortOrder))
            {
                result = CqtBuilder.Sort(newInput, newSortOrder);
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        public override DbExpression Visit(DbQuantifierExpression expression) 
        {
            EntityUtil.CheckArgumentNull(expression, "expression");

            DbExpression result = expression; 

            DbExpressionBinding input = this.VisitExpressionBindingEnterScope(expression.Input); 
            DbExpression predicate = this.VisitExpression(expression.Predicate); 
            this.ExitScope();
 
            if (!object.ReferenceEquals(expression.Input, input) ||
                !object.ReferenceEquals(expression.Predicate, predicate))
            {
                if (DbExpressionKind.All == expression.ExpressionKind) 
                {
                    result = CqtBuilder.All(input, predicate); 
                } 
                else
                { 
                    Debug.Assert(expression.ExpressionKind == DbExpressionKind.Any, "DbQuantifierExpression had ExpressionKind other than All or Any?");
                    result = CqtBuilder.Any(input, predicate);
                }
            } 
            NotifyIfChanged(expression, result);
            return result; 
        } 

        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK