Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / SqlClient / SqlGen / Sql8ExpressionRewriter.cs / 2 / Sql8ExpressionRewriter.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Common.CommandTrees.Internal; using System.Data.Metadata.Edm; namespace System.Data.SqlClient.SqlGen { ////// Rewrites an expression tree to make it suitable for translation to SQL appropriate for SQL Server 2000 /// In particular, it replaces expressions that are not directly supported on SQL Server 2000 /// with alternative translations. The following expressions are translated: /// internal class Sql8ExpressionRewriter : ExpressionCopier { #region Entry Point //////
/// /// The other expressions are copied unmodified. /// The new expression belongs to a new query command tree. ///- ///
- ///
- ///
/// The only entry point. /// Rewrites the given tree by replacing expressions that are not directly supported on SQL Server 2000 /// with alterntive translations. /// /// The tree to rewrite ///The new tree internal static DbQueryCommandTree Rewrite(DbQueryCommandTree originalTree) { Debug.Assert(originalTree != null, "OriginalTree is null"); DbQueryCommandTree newTree = new DbQueryCommandTree(originalTree.MetadataWorkspace, originalTree.DataSpace); originalTree.CopyParametersTo(newTree); Sql8ExpressionRewriter rewriter = new Sql8ExpressionRewriter(newTree); newTree.Query = rewriter.VisitExpr(originalTree.Query); return newTree; } #endregion #region Constructor ////// Private Constructor. /// /// private Sql8ExpressionRewriter(DbQueryCommandTree newTree) :base(newTree, MetadataMapper.IdentityMapper) { } #endregion #region DbExpressionVisitorMembers /// /// /// ////// public override DbExpression Visit(DbExceptExpression e) { return TransformIntersectOrExcept(VisitExpr(e.Left), VisitExpr(e.Right), DbExpressionKind.Except); } /// /// /// ////// public override DbExpression Visit(DbIntersectExpression e) { return TransformIntersectOrExcept(VisitExpr(e.Left), VisitExpr(e.Right), DbExpressionKind.Intersect); } /// /// Logicaly, /// ///translates to: /// SELECT Y.x1, Y.x2, ..., Y.xn /// FROM ( /// SELECT X.x1, X.x2, ..., X.xn, /// FROM input AS X /// EXCEPT /// SELECT TOP(count) Z.x1, Z.x2, ..., Z.xn /// FROM input AS Z /// ORDER BY sk1, sk2, ... /// ) AS Y /// ORDER BY sk1, sk2, ... /// /// Here, input refers to the input of the , and count to the count property of the . /// The implementation of EXCEPT is non-duplicate eliminating, and does equality comparison only over the /// equality comparable columns of the input. /// /// This corresponds to the following expression tree: /// /// SORT /// | /// NON-DISTINCT EXCEPT (specially translated, /// | /// | - Left: clone of input /// | - Right: /// | /// Limit /// | /// | - Limit: Count /// | - Input /// | /// Sort /// | /// input /// /// public override DbExpression Visit(DbSkipExpression e) { //Build the right input of the except DbExpression rightInput = CommandTree.CreateLimitExpression( CommandTree.CreateSortExpression( VisitBinding(e.Input), VisitSortOrder(e.SortOrder)), VisitExpr(e.Count)); //Build the left input for the except DbExpression leftInput = VisitExpr(e.Input.Expression); //Another copy of the input List sortOrder = VisitSortOrder(e.SortOrder); //Another copy of the sort order // Create a list of the sort expressions to be used for translating except IList sortExpressions = new List (e.SortOrder.Count); foreach (DbSortClause sortClause in sortOrder) { //We only care about property expressions, not about constants if (sortClause.Expression.ExpressionKind == DbExpressionKind.Property) { sortExpressions.Add((DbPropertyExpression)sortClause.Expression); } } DbExpression exceptExpression = TransformIntersectOrExcept(leftInput, rightInput, DbExpressionKind.Skip, sortExpressions, e.Input.VariableName); DbExpression result = CommandTree.CreateSortExpression( CommandTree.CreateExpressionBinding(exceptExpression, e.Input.VariableName), sortOrder); return result; } #endregion #region DbExpressionVisitor Member Helpers /// /// This method is invoked when tranforming /// /// /// ///and by doing comparison over all input columns. /// /// private DbExpression TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind) { return TransformIntersectOrExcept( left, right, expressionKind, null, null); } /// /// This method is used for translating /// /// /// /// note that this list gets destroyed by this method /// ///and , /// and for translating the "Except" part of . /// into the follwoing expression: /// /// A INTERSECT B, A EXCEPT B /// /// (DISTINCT) /// | /// FILTER /// | /// | - Input: A /// | - Predicate:(NOT) /// | /// ANY /// | /// | - Input: B /// | - Predicate: (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) /// AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) /// AND ... /// AND (B.bn = A.an or (B.bn is null and A.an is null))) /// /// Here, A corresponds to right and B to left. /// (NOT) is present when transforming Except /// for the purpose of translating or . /// (DISTINCT) is present when transforming for the purpose of translating /// or . /// /// For , the input to ANY is caped with project which projects out only /// the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate. /// This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these. /// private DbExpression TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { bool negate = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip); bool distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect); DbExpressionBinding leftInputBinding = this.CommandTree.CreateExpressionBinding(left); DbExpressionBinding rightInputBinding = this.CommandTree.CreateExpressionBinding(right); IList leftFlattenedProperties = new List (); IList rightFlattenedProperties = new List (); FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties); FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties); //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and // the properties in the list sortExpressionsOverLeft // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these // are non equal comparable, SQL Server 2000 throws. if (expressionKind == DbExpressionKind.Skip) { if (RemoveNonSortProperties(leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName, sortExpressionsBindingVariableName)) { rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties); } } Debug.Assert(leftFlattenedProperties.Count == rightFlattenedProperties.Count, "The left and the right input to INTERSECT or EXCEPT have a different number of properties"); Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties"); //Build the predicate for the quantifier: // (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) DbExpression existsPredicate = null; for (int i = 0; i < leftFlattenedProperties.Count; i++) { //A.ai == B.bi DbExpression equalsExpression = CommandTree.CreateEqualsExpression(leftFlattenedProperties[i], rightFlattenedProperties[i]); //A.ai is null AND B.bi is null DbExpression leftIsNullExpression = CommandTree.CreateIsNullExpression(leftFlattenedProperties[i].Clone() as DbExpression); DbExpression rightIsNullExpression = CommandTree.CreateIsNullExpression(rightFlattenedProperties[i].Clone() as DbExpression); DbExpression bothNullExpression = CommandTree.CreateAndExpression(leftIsNullExpression, rightIsNullExpression); DbExpression orExpression = CommandTree.CreateOrExpression(equalsExpression, bothNullExpression); if (i == 0) { existsPredicate = orExpression; } else { existsPredicate = CommandTree.CreateAndExpression(existsPredicate, orExpression); } } //Build the quantifier DbExpression quantifierExpression = CommandTree.CreateAnyExpression(rightInputBinding, existsPredicate); DbExpression filterPredicate; //Negate if needed if (negate) { filterPredicate = CommandTree.CreateNotExpression(quantifierExpression); } else { filterPredicate = quantifierExpression; } //Build the filter DbExpression result = CommandTree.CreateFilterExpression(leftInputBinding, filterPredicate); //Apply distinct in needed if (distinct) { result = CommandTree.CreateDistinctExpression(result); } return result; } /// /// Adds the flattened properties on the input to the flattenedProperties list. /// /// /// private void FlattenProperties(DbExpression input, IListflattenedProperties) { IList properties = TypeHelpers.GetProperties(input.ResultType); Debug.Assert(properties.Count != 0, "No nested properties when FlattenProperties called?"); for (int i = 0; i < properties.Count; i++) { DbExpression propertyInput = (i == 0) ? input : (input.Clone() as DbExpression); DbPropertyExpression propertyExpression = CommandTree.CreatePropertyExpression(properties[i], propertyInput); if (TypeSemantics.IsPrimitiveType(properties[i].TypeUsage)) { flattenedProperties.Add(propertyExpression); } else { Debug.Assert(TypeSemantics.IsEntityType(properties[i].TypeUsage) || TypeSemantics.IsRowType(properties[i].TypeUsage), "The input to FlattenProperties is not of EntityType or RowType?"); FlattenProperties(propertyExpression, flattenedProperties); } } } /// /// Helper method for /// /// /// /// /// ////// Removes all pairs of property expressions from list1 and list2, for which the property expression in list1 /// does not have a 'matching' property expression in list2. /// The lists list1 and list2 are known to not create duplicate, and the purpose of the sortList is just for this method. /// Thus, to optimize the match process, we remove the seen property expressions from the sort list in /// when iterating both list simultaneously. /// private static bool RemoveNonSortProperties(IList list1, IList list2, IList sortList, string list1BindingVariableName, string sortExpressionsBindingVariableName) { bool result = false; for (int i = list1.Count - 1; i >= 0; i--) { if (!HasMatchInList(list1[i], sortList, list1BindingVariableName, sortExpressionsBindingVariableName)) { list1.RemoveAt(i); list2.RemoveAt(i); result = true; } } return result; } /// /// Helper method for /// /// /// /// ////// Checks whether expr has a 'match' in the given list of property expressions. /// If it does, the matching expression is removed form the list, to speed up future matching. /// private static bool HasMatchInList(DbPropertyExpression expr, IList list, string exprBindingVariableName, string listExpressionsBindingVariableName) { for (int i=0; i /// Determines whether two expressions match. /// They match if they are of the shape /// expr1 -> DbPropertyExpression(... (DbPropertyExpression(DbVariableReferenceExpression(expr1BindingVariableName), nameX), ..., name1) /// expr1 -> DbPropertyExpression(... (DbPropertyExpression(DbVariableReferenceExpression(expr2BindingVariableName), nameX), ..., name1), /// /// i.e. if they only differ in the name of the binding. /// /// /// /// /// /// private static bool AreMatching(DbPropertyExpression expr1, DbPropertyExpression expr2, string expr1BindingVariableName, string expr2BindingVariableName) { if (expr1.Property.Name != expr2.Property.Name) { return false; } if (expr1.Instance.ExpressionKind != expr2.Instance.ExpressionKind) { return false; } if (expr1.Instance.ExpressionKind == DbExpressionKind.Property) { return AreMatching((DbPropertyExpression)expr1.Instance, (DbPropertyExpression)expr2.Instance, expr1BindingVariableName, expr2BindingVariableName); } DbVariableReferenceExpression instance1 = (DbVariableReferenceExpression)expr1.Instance; DbVariableReferenceExpression instance2 = (DbVariableReferenceExpression)expr2.Instance; return (String.Equals(instance1.VariableName, expr1BindingVariableName, StringComparison.Ordinal) && String.Equals(instance2.VariableName, expr2BindingVariableName, StringComparison.Ordinal)); } /// /// Helper method for /// /// ////// Creates a over the given inputBinding that projects out the given flattenedProperties. /// and updates the flattenedProperties to be over the newly created project. /// An private DbExpressionBinding CapWithProject(DbExpressionBinding inputBinding, IListover the newly created flattenedProperties) { List > projectColumns = new List >(flattenedProperties.Count); //List of all the columnNames used in the projection. Dictionary columnNames = new Dictionary (flattenedProperties.Count); foreach (DbPropertyExpression pe in flattenedProperties) { //There may be conflicting property names, thus we may need to rename. string name = pe.Property.Name; int i; if (columnNames.TryGetValue(name, out i)) { string newName; do { ++i; newName = name + i.ToString(System.Globalization.CultureInfo.InvariantCulture); } while (columnNames.ContainsKey(newName)); columnNames[name] = i; name = newName; } // Add this column name to list of known names so that there are no subsequent // collisions columnNames[name] = 0; projectColumns.Add(new KeyValuePair (name, pe)); } //Build the project DbExpression rowExpr = CommandTree.CreateNewRowExpression(projectColumns); DbProjectExpression projectExpression = CommandTree.CreateProjectExpression(inputBinding, rowExpr); //Create the new inputBinding DbExpressionBinding resultBinding = this.CommandTree.CreateExpressionBinding(projectExpression); //Create the list of flattenedProperties over the new project flattenedProperties.Clear(); RowType rowExprType = (RowType)rowExpr.ResultType.EdmType; foreach (KeyValuePair column in projectColumns) { EdmProperty prop = rowExprType.Properties[column.Key]; flattenedProperties.Add( CommandTree.CreatePropertyExpression( prop, CommandTree.CreateVariableReferenceExpression(resultBinding.VariableName, resultBinding.VariableType))); } return resultBinding; } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Common.CommandTrees.Internal; using System.Data.Metadata.Edm; namespace System.Data.SqlClient.SqlGen { ////// Rewrites an expression tree to make it suitable for translation to SQL appropriate for SQL Server 2000 /// In particular, it replaces expressions that are not directly supported on SQL Server 2000 /// with alternative translations. The following expressions are translated: /// internal class Sql8ExpressionRewriter : ExpressionCopier { #region Entry Point //////
/// /// The other expressions are copied unmodified. /// The new expression belongs to a new query command tree. ///- ///
- ///
- ///
/// The only entry point. /// Rewrites the given tree by replacing expressions that are not directly supported on SQL Server 2000 /// with alterntive translations. /// /// The tree to rewrite ///The new tree internal static DbQueryCommandTree Rewrite(DbQueryCommandTree originalTree) { Debug.Assert(originalTree != null, "OriginalTree is null"); DbQueryCommandTree newTree = new DbQueryCommandTree(originalTree.MetadataWorkspace, originalTree.DataSpace); originalTree.CopyParametersTo(newTree); Sql8ExpressionRewriter rewriter = new Sql8ExpressionRewriter(newTree); newTree.Query = rewriter.VisitExpr(originalTree.Query); return newTree; } #endregion #region Constructor ////// Private Constructor. /// /// private Sql8ExpressionRewriter(DbQueryCommandTree newTree) :base(newTree, MetadataMapper.IdentityMapper) { } #endregion #region DbExpressionVisitorMembers /// /// /// ////// public override DbExpression Visit(DbExceptExpression e) { return TransformIntersectOrExcept(VisitExpr(e.Left), VisitExpr(e.Right), DbExpressionKind.Except); } /// /// /// ////// public override DbExpression Visit(DbIntersectExpression e) { return TransformIntersectOrExcept(VisitExpr(e.Left), VisitExpr(e.Right), DbExpressionKind.Intersect); } /// /// Logicaly, /// ///translates to: /// SELECT Y.x1, Y.x2, ..., Y.xn /// FROM ( /// SELECT X.x1, X.x2, ..., X.xn, /// FROM input AS X /// EXCEPT /// SELECT TOP(count) Z.x1, Z.x2, ..., Z.xn /// FROM input AS Z /// ORDER BY sk1, sk2, ... /// ) AS Y /// ORDER BY sk1, sk2, ... /// /// Here, input refers to the input of the , and count to the count property of the . /// The implementation of EXCEPT is non-duplicate eliminating, and does equality comparison only over the /// equality comparable columns of the input. /// /// This corresponds to the following expression tree: /// /// SORT /// | /// NON-DISTINCT EXCEPT (specially translated, /// | /// | - Left: clone of input /// | - Right: /// | /// Limit /// | /// | - Limit: Count /// | - Input /// | /// Sort /// | /// input /// /// public override DbExpression Visit(DbSkipExpression e) { //Build the right input of the except DbExpression rightInput = CommandTree.CreateLimitExpression( CommandTree.CreateSortExpression( VisitBinding(e.Input), VisitSortOrder(e.SortOrder)), VisitExpr(e.Count)); //Build the left input for the except DbExpression leftInput = VisitExpr(e.Input.Expression); //Another copy of the input List sortOrder = VisitSortOrder(e.SortOrder); //Another copy of the sort order // Create a list of the sort expressions to be used for translating except IList sortExpressions = new List (e.SortOrder.Count); foreach (DbSortClause sortClause in sortOrder) { //We only care about property expressions, not about constants if (sortClause.Expression.ExpressionKind == DbExpressionKind.Property) { sortExpressions.Add((DbPropertyExpression)sortClause.Expression); } } DbExpression exceptExpression = TransformIntersectOrExcept(leftInput, rightInput, DbExpressionKind.Skip, sortExpressions, e.Input.VariableName); DbExpression result = CommandTree.CreateSortExpression( CommandTree.CreateExpressionBinding(exceptExpression, e.Input.VariableName), sortOrder); return result; } #endregion #region DbExpressionVisitor Member Helpers /// /// This method is invoked when tranforming /// /// /// ///and by doing comparison over all input columns. /// /// private DbExpression TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind) { return TransformIntersectOrExcept( left, right, expressionKind, null, null); } /// /// This method is used for translating /// /// /// /// note that this list gets destroyed by this method /// ///and , /// and for translating the "Except" part of . /// into the follwoing expression: /// /// A INTERSECT B, A EXCEPT B /// /// (DISTINCT) /// | /// FILTER /// | /// | - Input: A /// | - Predicate:(NOT) /// | /// ANY /// | /// | - Input: B /// | - Predicate: (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) /// AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) /// AND ... /// AND (B.bn = A.an or (B.bn is null and A.an is null))) /// /// Here, A corresponds to right and B to left. /// (NOT) is present when transforming Except /// for the purpose of translating or . /// (DISTINCT) is present when transforming for the purpose of translating /// or . /// /// For , the input to ANY is caped with project which projects out only /// the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate. /// This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these. /// private DbExpression TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { bool negate = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip); bool distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect); DbExpressionBinding leftInputBinding = this.CommandTree.CreateExpressionBinding(left); DbExpressionBinding rightInputBinding = this.CommandTree.CreateExpressionBinding(right); IList leftFlattenedProperties = new List (); IList rightFlattenedProperties = new List (); FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties); FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties); //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and // the properties in the list sortExpressionsOverLeft // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these // are non equal comparable, SQL Server 2000 throws. if (expressionKind == DbExpressionKind.Skip) { if (RemoveNonSortProperties(leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName, sortExpressionsBindingVariableName)) { rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties); } } Debug.Assert(leftFlattenedProperties.Count == rightFlattenedProperties.Count, "The left and the right input to INTERSECT or EXCEPT have a different number of properties"); Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties"); //Build the predicate for the quantifier: // (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) DbExpression existsPredicate = null; for (int i = 0; i < leftFlattenedProperties.Count; i++) { //A.ai == B.bi DbExpression equalsExpression = CommandTree.CreateEqualsExpression(leftFlattenedProperties[i], rightFlattenedProperties[i]); //A.ai is null AND B.bi is null DbExpression leftIsNullExpression = CommandTree.CreateIsNullExpression(leftFlattenedProperties[i].Clone() as DbExpression); DbExpression rightIsNullExpression = CommandTree.CreateIsNullExpression(rightFlattenedProperties[i].Clone() as DbExpression); DbExpression bothNullExpression = CommandTree.CreateAndExpression(leftIsNullExpression, rightIsNullExpression); DbExpression orExpression = CommandTree.CreateOrExpression(equalsExpression, bothNullExpression); if (i == 0) { existsPredicate = orExpression; } else { existsPredicate = CommandTree.CreateAndExpression(existsPredicate, orExpression); } } //Build the quantifier DbExpression quantifierExpression = CommandTree.CreateAnyExpression(rightInputBinding, existsPredicate); DbExpression filterPredicate; //Negate if needed if (negate) { filterPredicate = CommandTree.CreateNotExpression(quantifierExpression); } else { filterPredicate = quantifierExpression; } //Build the filter DbExpression result = CommandTree.CreateFilterExpression(leftInputBinding, filterPredicate); //Apply distinct in needed if (distinct) { result = CommandTree.CreateDistinctExpression(result); } return result; } /// /// Adds the flattened properties on the input to the flattenedProperties list. /// /// /// private void FlattenProperties(DbExpression input, IListflattenedProperties) { IList properties = TypeHelpers.GetProperties(input.ResultType); Debug.Assert(properties.Count != 0, "No nested properties when FlattenProperties called?"); for (int i = 0; i < properties.Count; i++) { DbExpression propertyInput = (i == 0) ? input : (input.Clone() as DbExpression); DbPropertyExpression propertyExpression = CommandTree.CreatePropertyExpression(properties[i], propertyInput); if (TypeSemantics.IsPrimitiveType(properties[i].TypeUsage)) { flattenedProperties.Add(propertyExpression); } else { Debug.Assert(TypeSemantics.IsEntityType(properties[i].TypeUsage) || TypeSemantics.IsRowType(properties[i].TypeUsage), "The input to FlattenProperties is not of EntityType or RowType?"); FlattenProperties(propertyExpression, flattenedProperties); } } } /// /// Helper method for /// /// /// /// /// ////// Removes all pairs of property expressions from list1 and list2, for which the property expression in list1 /// does not have a 'matching' property expression in list2. /// The lists list1 and list2 are known to not create duplicate, and the purpose of the sortList is just for this method. /// Thus, to optimize the match process, we remove the seen property expressions from the sort list in /// when iterating both list simultaneously. /// private static bool RemoveNonSortProperties(IList list1, IList list2, IList sortList, string list1BindingVariableName, string sortExpressionsBindingVariableName) { bool result = false; for (int i = list1.Count - 1; i >= 0; i--) { if (!HasMatchInList(list1[i], sortList, list1BindingVariableName, sortExpressionsBindingVariableName)) { list1.RemoveAt(i); list2.RemoveAt(i); result = true; } } return result; } /// /// Helper method for /// /// /// /// ////// Checks whether expr has a 'match' in the given list of property expressions. /// If it does, the matching expression is removed form the list, to speed up future matching. /// private static bool HasMatchInList(DbPropertyExpression expr, IList list, string exprBindingVariableName, string listExpressionsBindingVariableName) { for (int i=0; i /// Determines whether two expressions match. /// They match if they are of the shape /// expr1 -> DbPropertyExpression(... (DbPropertyExpression(DbVariableReferenceExpression(expr1BindingVariableName), nameX), ..., name1) /// expr1 -> DbPropertyExpression(... (DbPropertyExpression(DbVariableReferenceExpression(expr2BindingVariableName), nameX), ..., name1), /// /// i.e. if they only differ in the name of the binding. /// /// /// /// /// /// private static bool AreMatching(DbPropertyExpression expr1, DbPropertyExpression expr2, string expr1BindingVariableName, string expr2BindingVariableName) { if (expr1.Property.Name != expr2.Property.Name) { return false; } if (expr1.Instance.ExpressionKind != expr2.Instance.ExpressionKind) { return false; } if (expr1.Instance.ExpressionKind == DbExpressionKind.Property) { return AreMatching((DbPropertyExpression)expr1.Instance, (DbPropertyExpression)expr2.Instance, expr1BindingVariableName, expr2BindingVariableName); } DbVariableReferenceExpression instance1 = (DbVariableReferenceExpression)expr1.Instance; DbVariableReferenceExpression instance2 = (DbVariableReferenceExpression)expr2.Instance; return (String.Equals(instance1.VariableName, expr1BindingVariableName, StringComparison.Ordinal) && String.Equals(instance2.VariableName, expr2BindingVariableName, StringComparison.Ordinal)); } /// /// Helper method for /// /// ////// Creates a over the given inputBinding that projects out the given flattenedProperties. /// and updates the flattenedProperties to be over the newly created project. /// An private DbExpressionBinding CapWithProject(DbExpressionBinding inputBinding, IListover the newly created flattenedProperties) { List > projectColumns = new List >(flattenedProperties.Count); //List of all the columnNames used in the projection. Dictionary columnNames = new Dictionary (flattenedProperties.Count); foreach (DbPropertyExpression pe in flattenedProperties) { //There may be conflicting property names, thus we may need to rename. string name = pe.Property.Name; int i; if (columnNames.TryGetValue(name, out i)) { string newName; do { ++i; newName = name + i.ToString(System.Globalization.CultureInfo.InvariantCulture); } while (columnNames.ContainsKey(newName)); columnNames[name] = i; name = newName; } // Add this column name to list of known names so that there are no subsequent // collisions columnNames[name] = 0; projectColumns.Add(new KeyValuePair (name, pe)); } //Build the project DbExpression rowExpr = CommandTree.CreateNewRowExpression(projectColumns); DbProjectExpression projectExpression = CommandTree.CreateProjectExpression(inputBinding, rowExpr); //Create the new inputBinding DbExpressionBinding resultBinding = this.CommandTree.CreateExpressionBinding(projectExpression); //Create the list of flattenedProperties over the new project flattenedProperties.Clear(); RowType rowExprType = (RowType)rowExpr.ResultType.EdmType; foreach (KeyValuePair column in projectColumns) { EdmProperty prop = rowExprType.Properties[column.Key]; flattenedProperties.Add( CommandTree.CreatePropertyExpression( prop, CommandTree.CreateVariableReferenceExpression(resultBinding.VariableName, resultBinding.VariableType))); } return resultBinding; } #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
- SqlBuffer.cs
- DbgUtil.cs
- SafeRightsManagementQueryHandle.cs
- StorageMappingItemCollection.cs
- CodeDomSerializer.cs
- DataServiceCollectionOfT.cs
- Transform.cs
- CodeExpressionCollection.cs
- XmlValueConverter.cs
- JavaScriptString.cs
- OdbcCommandBuilder.cs
- MemberAssignment.cs
- SemanticResultKey.cs
- CompatibleComparer.cs
- DiscoveryEndpointElement.cs
- HtmlFormParameterWriter.cs
- XmlSchemaAll.cs
- EventItfInfo.cs
- XamlPointCollectionSerializer.cs
- PermissionAttributes.cs
- securestring.cs
- URLString.cs
- DiagnosticTrace.cs
- mediapermission.cs
- DiscoveryRequestHandler.cs
- EastAsianLunisolarCalendar.cs
- WindowsListViewGroupSubsetLink.cs
- EpmTargetPathSegment.cs
- Helpers.cs
- ErrorCodes.cs
- dataprotectionpermissionattribute.cs
- PlainXmlSerializer.cs
- PropertyRecord.cs
- PerformanceCounterPermissionAttribute.cs
- SamlConstants.cs
- GreenMethods.cs
- HtmlFormAdapter.cs
- ComponentEditorPage.cs
- TextViewElement.cs
- Error.cs
- DataObjectPastingEventArgs.cs
- NullRuntimeConfig.cs
- SelectionProviderWrapper.cs
- SlipBehavior.cs
- BamlResourceContent.cs
- ToolStripItemClickedEventArgs.cs
- BrowserDefinitionCollection.cs
- DynamicFilterExpression.cs
- LogAppendAsyncResult.cs
- GenericTypeParameterBuilder.cs
- BulletedListEventArgs.cs
- ScrollViewerAutomationPeer.cs
- Claim.cs
- ArrayEditor.cs
- ComEventsSink.cs
- VariableQuery.cs
- ListParaClient.cs
- EntityDataSourceSelectingEventArgs.cs
- XmlParserContext.cs
- MemberAccessException.cs
- InputBinding.cs
- PropertyDescriptor.cs
- SoapCodeExporter.cs
- ColumnMapCopier.cs
- SoapSchemaExporter.cs
- DataGridViewCellFormattingEventArgs.cs
- GestureRecognitionResult.cs
- GenericEnumConverter.cs
- SequenceDesignerAccessibleObject.cs
- SchemaAttDef.cs
- Table.cs
- ConnectionStringsExpressionBuilder.cs
- EventHandlerList.cs
- WorkflowServiceBehavior.cs
- SystemParameters.cs
- TraceFilter.cs
- GreenMethods.cs
- SoapFormatter.cs
- XmlRootAttribute.cs
- SqlServices.cs
- PropertySegmentSerializationProvider.cs
- AdapterDictionary.cs
- EnterpriseServicesHelper.cs
- ActivationProxy.cs
- RectConverter.cs
- InvalidProgramException.cs
- MimeTypePropertyAttribute.cs
- StandardCommands.cs
- wgx_exports.cs
- DbInsertCommandTree.cs
- Adorner.cs
- _SSPIWrapper.cs
- TransferRequestHandler.cs
- DrawingContextDrawingContextWalker.cs
- EqualityComparer.cs
- HashCodeCombiner.cs
- IriParsingElement.cs
- DataGridViewRowsAddedEventArgs.cs
- TransactionManager.cs
- EmptyEnumerator.cs