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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MsmqHostedTransportManager.cs
- MarshalByRefObject.cs
- TextControlDesigner.cs
- GACIdentityPermission.cs
- PopupRootAutomationPeer.cs
- DbModificationCommandTree.cs
- DataViewListener.cs
- TabletDeviceInfo.cs
- IndexOutOfRangeException.cs
- VectorAnimationUsingKeyFrames.cs
- NativeCppClassAttribute.cs
- DataGridViewColumnHeaderCell.cs
- Mouse.cs
- _SafeNetHandles.cs
- EnumerableRowCollectionExtensions.cs
- ExpandedProjectionNode.cs
- ManipulationInertiaStartingEventArgs.cs
- CellConstant.cs
- UpdateDelegates.Generated.cs
- CachedPathData.cs
- ExplicitDiscriminatorMap.cs
- GenericTextProperties.cs
- Gdiplus.cs
- Point.cs
- contentDescriptor.cs
- Slider.cs
- TransformConverter.cs
- CallSiteOps.cs
- TypeElementCollection.cs
- CodeExpressionStatement.cs
- EntityDataSourceEntitySetNameItem.cs
- mda.cs
- EmissiveMaterial.cs
- StagingAreaInputItem.cs
- ToolStripDesignerAvailabilityAttribute.cs
- PagerSettings.cs
- CheckBoxBaseAdapter.cs
- TempEnvironment.cs
- ObjectHandle.cs
- CornerRadius.cs
- PasswordBox.cs
- XmlDownloadManager.cs
- TextBoxAutoCompleteSourceConverter.cs
- ObjectViewQueryResultData.cs
- EventProvider.cs
- LiteralTextContainerControlBuilder.cs
- EntityKey.cs
- ObjectListDataBindEventArgs.cs
- MouseDevice.cs
- VectorConverter.cs
- SQLInt64Storage.cs
- WorkflowOwnershipException.cs
- GenericXmlSecurityToken.cs
- XmlRawWriter.cs
- DetailsViewPagerRow.cs
- HealthMonitoringSectionHelper.cs
- ClientScriptManager.cs
- TcpTransportManager.cs
- TypographyProperties.cs
- UIElement.cs
- CheckableControlBaseAdapter.cs
- GridViewColumnCollectionChangedEventArgs.cs
- Buffer.cs
- HtmlPageAdapter.cs
- SqlGatherProducedAliases.cs
- WebHttpSecurityModeHelper.cs
- DSACryptoServiceProvider.cs
- PersistChildrenAttribute.cs
- Process.cs
- EllipseGeometry.cs
- Function.cs
- Sequence.cs
- MdImport.cs
- SiteMapDataSourceView.cs
- InstanceNameConverter.cs
- WebCodeGenerator.cs
- DesignerVerb.cs
- DataGridViewColumnTypeEditor.cs
- RecordBuilder.cs
- TableColumn.cs
- SafeViewOfFileHandle.cs
- TextServicesHost.cs
- EndPoint.cs
- TemplateControl.cs
- DataKeyCollection.cs
- SequenceDesigner.cs
- ValueSerializerAttribute.cs
- Object.cs
- TypefaceMap.cs
- BindingsCollection.cs
- RequestCachePolicy.cs
- HtmlObjectListAdapter.cs
- SettingsPropertyWrongTypeException.cs
- PointLight.cs
- ProtectedConfiguration.cs
- HttpStreamXmlDictionaryWriter.cs
- KeyFrames.cs
- WebPartTransformerAttribute.cs
- ILGenerator.cs
- CallSiteBinder.cs