ViewSimplifier.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Common / CommandTrees / Internal / ViewSimplifier.cs / 2 / ViewSimplifier.cs

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

using System.Data.Common.CommandTrees; 
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Data.Common.Utils; 
using System.Linq;
using System.Globalization; 
namespace System.Data.Common.CommandTrees.Internal 
{
 
    /// 
    /// Utility class that walks a mapping view and returns a simplified expression with projection
    /// nodes collapsed. Specifically recognizes the following common pattern in mapping views:
    /// 
    ///     outerProject(outerBinding(innerProject(innerBinding, innerNew)), outerProjection)
    /// 
    /// Recognizes simple disciminator patterns of the form: 
    ///
    ///     select 
    ///         case when Disc = value1 then value Type1(...)
    ///         case when Disc = value2 then value Type2(...)
    ///         ...
    /// 
    /// Recognizes redundant case statement of the form:
    /// 
    ///     select 
    ///         case when (case when Predicate1 then true else false) ...
    /// 
    /// 
    internal static class ViewSimplifier
    {
        internal static DbQueryCommandTree SimplifyView(DbQueryCommandTree view) 
        {
            view = view.Clone(); 
 
            view.Replace(CollapseProject);
 
            view.Replace(SimplifyCaseStatements);

            return view;
        } 

        ///  
        /// This expression replacer delegate supports collapsing a nested projection matching the pattern described above. 
        ///
        /// For instance: 
        ///
        ///     select T.a as x, T.b as y, true as z from (select E.a as x, E.b as y from Extent E)
        ///
        /// resolves to: 
        ///
        ///     select E.a, E.b, true as z from Extent E 
        /// 
        /// In general,
        /// 
        ///     outerProject(
        ///         outerBinding(
        ///             innerProject(innerBinding, innerNew)
        ///         ), 
        ///         outerNew)
        /// 
        /// resolves to: 
        ///
        ///     replacementOuterProject( 
        ///         innerBinding,
        ///         replacementOuterNew)
        ///
        /// The outer projection is bound to the inner input source (outerBinding -> innerBinding) and 
        /// the outer new instance expression has its properties remapped to the inner new instance
        /// expression member expressions. 
        ///  
        private static void CollapseProject(ExpressionReplacement replacement)
        { 
            // retrieve the replacement candidate
            DbExpression candidate = replacement.Current;

            DbProjectExpression outerProject; 
            DbExpression outerProjection;
            DbProjectExpression innerProject; 
            DbNewInstanceExpression innerNew; 

            // determine if the candidate matches the pattern we know how to rewrite 
            if (TryMatchNestedProjectPattern(candidate, out outerProject, out outerProjection,
                out innerProject, out innerNew))
            {
                CollapseNestedProjection(replacement, outerProject, outerProjection, innerProject, innerNew); 
            }
        } 
 
        /// 
        /// determines if an expression is of the form outerProject(outerProjection(innerProject(innerNew))), 
        /// returning these elements
        /// 
        private static bool TryMatchNestedProjectPattern(DbExpression outerCandidate,
            out DbProjectExpression outerProject, 
            out DbExpression outerProjection,
            out DbProjectExpression innerProject, 
            out DbNewInstanceExpression innerNew) 
        {
            // init output parameters 
            outerProject = null;
            outerProjection = null;
            innerProject = null;
            innerNew = null; 

            // check the pattern 
            if (outerCandidate.ExpressionKind != DbExpressionKind.Project) { return false; } 
            outerProject = (DbProjectExpression)outerCandidate;
            outerProjection = outerProject.Projection; 

            if (outerProject.Input.Expression.ExpressionKind != DbExpressionKind.Project) { return false; }
            innerProject = (DbProjectExpression)outerProject.Input.Expression;
            if (innerProject.Projection.ExpressionKind != DbExpressionKind.NewInstance) { return false; } 
            innerNew = (DbNewInstanceExpression)innerProject.Projection;
 
            return true; 
        }
 
        /// 
        /// Collapses outerProject(outerProjection(innerProject(innerNew)))
        /// 
        private static void CollapseNestedProjection(ExpressionReplacement replacement, 
            DbProjectExpression outerProject, DbExpression outerProjection, DbProjectExpression innerProject,
            DbNewInstanceExpression innerNew) 
        { 
            replacement.VisitReplacement = true; // continue collapsing projection until the pattern no longer matches
 
            // get membername -> expression bindings for the inner select so that we know how map property
            // references to the inner projectio
            Dictionary bindings = new Dictionary(innerNew.Arguments.Count);
            TypeUsage innerResultTypeUsage = innerNew.ResultType; 
            RowType innerResultType = (RowType)innerResultTypeUsage.EdmType;
 
            for (int ordinal = 0; ordinal < innerResultType.Members.Count; ordinal++) 
            {
                bindings[innerResultType.Members[ordinal].Name] = innerNew.Arguments[ordinal]; 
            }

            // initialize an expression replacer that knows how to map arguments to the outer projection
            // to the inner projection source 
            ProjectionCollapser collapser = new ProjectionCollapser(bindings, outerProject.Input);
            ExpressionReplacer replacer = new ExpressionReplacer(collapser.CollapseProjection); 
 
            // replace all property references to the inner projection
            var replacementOuterProjection = replacer.Replace(outerProjection); 
            DbProjectExpression replacementOuterProject = outerProject.CommandTree.CreateProjectExpression(
                innerProject.Input, replacementOuterProjection);

            // make sure the collapsing was successful; if not, give up on simplification 
            if (collapser.IsDoomed) { return; }
 
            // set replacement value so that the expression replacer infrastructure can substitute 
            // the collapsed projection in the expression tree
            replacement.Replacement = replacementOuterProject; 
        }

        private static void SimplifyCaseStatements(ExpressionReplacement replacement)
        { 
            var candidate = replacement.Current;
            if (candidate.ExpressionKind != DbExpressionKind.Case) { return; } 
 
            var caseExpression = (DbCaseExpression)replacement.Current;
 
            // try simplifying predicates
            bool predicateSimplified = false;
            List rewrittenPredicates = new List(caseExpression.When.Count);
            foreach (var when in caseExpression.When) 
            {
                DbExpression simplifiedPredicate; 
                if (TrySimplifyPredicate(when, out simplifiedPredicate)) 
                {
                    rewrittenPredicates.Add(simplifiedPredicate); 
                    predicateSimplified = true;
                }
                else
                { 
                    rewrittenPredicates.Add(when);
                } 
            } 

            if (!predicateSimplified) { return; } 

            replacement.Replacement = caseExpression.CommandTree.CreateCaseExpression(
                rewrittenPredicates, caseExpression.Then, caseExpression.Else);
            replacement.VisitReplacement = true; 
        }
 
        private static bool TrySimplifyPredicate(DbExpression predicate, out DbExpression simplified) 
        {
            simplified = null; 
            if (predicate.ExpressionKind != DbExpressionKind.Case) { return false; }
            var caseExpression = (DbCaseExpression)predicate;
            if (caseExpression.Then.Count != 1 && caseExpression.Then[0].ExpressionKind == DbExpressionKind.Constant)
            { 
                return false;
            } 
            var then = (DbConstantExpression)caseExpression.Then[0]; 
            if (!true.Equals(then.Value)) { return false; }
            if (caseExpression.Else != null) 
            {
                if (caseExpression.Else.ExpressionKind != DbExpressionKind.Constant) { return false; }
                var when = (DbConstantExpression)caseExpression.Else;
                if (!false.Equals(when.Value)) { return false; } 
            }
            simplified = caseExpression.When[0]; 
            return true; 
        }
 
        /// 
        /// replacer used to simplify argument value in a new instance expression OuterNew from
        /// an expression of the form:
        /// 
        ///      outerProject(outerBinding(innerProject(innerBinding, innerNew)), outerProjection)
        /// 
        /// The replacer collapses the outer project terms to point at the innerNew expression. 
        /// Where possible, VarRef_outer.Property_outer is collapsed to VarRef_inner.Property.
        ///  
        private class ProjectionCollapser
        {
            // the replacer context keeps track of member bindings for var refs and the expression
            // binding for the outer projection being remapped 
            private Dictionary m_varRefMemberBindings;
            private DbExpressionBinding m_outerBinding; 
            private bool m_doomed; 
            internal ProjectionCollapser(Dictionary varRefMemberBindings,
                DbExpressionBinding outerBinding) 
            {
                m_varRefMemberBindings = varRefMemberBindings;
                m_outerBinding = outerBinding;
            } 

            // replacer delegate that identifies the Property(VarRef "Outer binding") pattern, 
            // and remaps the property to the appropriate inner projection member 
            internal void CollapseProjection(ExpressionReplacement replacement)
            { 
                // check for a property of the outer projection binding (that can be remapped)
                if (replacement.Current.ExpressionKind == DbExpressionKind.Property)
                {
                    var property = (DbPropertyExpression)replacement.Current; 
                    if (property.Instance.ExpressionKind == DbExpressionKind.VariableReference &&
                        IsOuterBindingVarRef((DbVariableReferenceExpression)property.Instance)) 
                    { 
                        replacement.VisitReplacement = false;
                        replacement.Replacement = m_varRefMemberBindings[property.Property.Name]; 
                    }
                }
                else if (replacement.Current.ExpressionKind == DbExpressionKind.VariableReference)
                { 
                    // if we encounter an unsubstitutued var ref, give up...
                    var varRef = (DbVariableReferenceExpression)replacement.Current; 
                    if (IsOuterBindingVarRef(varRef)) 
                    {
                        m_doomed = true; 
                    }
                }
            }
 
            /// 
            /// Heuristic check to make sure the var ref is the one we're supposed to be replacing. 
            ///  
            private bool IsOuterBindingVarRef(DbVariableReferenceExpression varRef)
            { 
                return varRef.VariableName == m_outerBinding.VariableName;
            }

            ///  
            /// Returns a value indicating that the transformation has failed.
            ///  
            internal bool IsDoomed 
            {
                get { return m_doomed; } 
            }
        }
        /*
        private abstract class DiscriminatorValueCollection 
        {
            ///  
            /// Add a new discriminator value. Returns true if the value is unique. 
            /// 
            internal abstract bool TryAddDiscriminatorValue(object value); 

            /// 
            /// Associate a discriminator value with the given type. Returns true if the value is known.
            ///  
            internal abstract bool TryAddDiscriminatorValueAssignment(object value, EntityType entityType);
 
            ///  
            ///
            ///  
            internal abstract bool TryAssignDefaultType(EntityType entityType);

            private class TypedDiscriminatorValueCollection
            { 
                private readonly TryConvert _convert;
                private readonly Func, T> _generateUniqueDiscriminator; 
                private readonly HashSet _discriminatorValues; 
                private readonly Dictionary _discriminatorAssignments;
 

            }

            private delegate bool TryConvert(object input, out T output); 
        }
         * */ 
    } 
}

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

using System.Data.Common.CommandTrees; 
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Data.Common.Utils; 
using System.Linq;
using System.Globalization; 
namespace System.Data.Common.CommandTrees.Internal 
{
 
    /// 
    /// Utility class that walks a mapping view and returns a simplified expression with projection
    /// nodes collapsed. Specifically recognizes the following common pattern in mapping views:
    /// 
    ///     outerProject(outerBinding(innerProject(innerBinding, innerNew)), outerProjection)
    /// 
    /// Recognizes simple disciminator patterns of the form: 
    ///
    ///     select 
    ///         case when Disc = value1 then value Type1(...)
    ///         case when Disc = value2 then value Type2(...)
    ///         ...
    /// 
    /// Recognizes redundant case statement of the form:
    /// 
    ///     select 
    ///         case when (case when Predicate1 then true else false) ...
    /// 
    /// 
    internal static class ViewSimplifier
    {
        internal static DbQueryCommandTree SimplifyView(DbQueryCommandTree view) 
        {
            view = view.Clone(); 
 
            view.Replace(CollapseProject);
 
            view.Replace(SimplifyCaseStatements);

            return view;
        } 

        ///  
        /// This expression replacer delegate supports collapsing a nested projection matching the pattern described above. 
        ///
        /// For instance: 
        ///
        ///     select T.a as x, T.b as y, true as z from (select E.a as x, E.b as y from Extent E)
        ///
        /// resolves to: 
        ///
        ///     select E.a, E.b, true as z from Extent E 
        /// 
        /// In general,
        /// 
        ///     outerProject(
        ///         outerBinding(
        ///             innerProject(innerBinding, innerNew)
        ///         ), 
        ///         outerNew)
        /// 
        /// resolves to: 
        ///
        ///     replacementOuterProject( 
        ///         innerBinding,
        ///         replacementOuterNew)
        ///
        /// The outer projection is bound to the inner input source (outerBinding -> innerBinding) and 
        /// the outer new instance expression has its properties remapped to the inner new instance
        /// expression member expressions. 
        ///  
        private static void CollapseProject(ExpressionReplacement replacement)
        { 
            // retrieve the replacement candidate
            DbExpression candidate = replacement.Current;

            DbProjectExpression outerProject; 
            DbExpression outerProjection;
            DbProjectExpression innerProject; 
            DbNewInstanceExpression innerNew; 

            // determine if the candidate matches the pattern we know how to rewrite 
            if (TryMatchNestedProjectPattern(candidate, out outerProject, out outerProjection,
                out innerProject, out innerNew))
            {
                CollapseNestedProjection(replacement, outerProject, outerProjection, innerProject, innerNew); 
            }
        } 
 
        /// 
        /// determines if an expression is of the form outerProject(outerProjection(innerProject(innerNew))), 
        /// returning these elements
        /// 
        private static bool TryMatchNestedProjectPattern(DbExpression outerCandidate,
            out DbProjectExpression outerProject, 
            out DbExpression outerProjection,
            out DbProjectExpression innerProject, 
            out DbNewInstanceExpression innerNew) 
        {
            // init output parameters 
            outerProject = null;
            outerProjection = null;
            innerProject = null;
            innerNew = null; 

            // check the pattern 
            if (outerCandidate.ExpressionKind != DbExpressionKind.Project) { return false; } 
            outerProject = (DbProjectExpression)outerCandidate;
            outerProjection = outerProject.Projection; 

            if (outerProject.Input.Expression.ExpressionKind != DbExpressionKind.Project) { return false; }
            innerProject = (DbProjectExpression)outerProject.Input.Expression;
            if (innerProject.Projection.ExpressionKind != DbExpressionKind.NewInstance) { return false; } 
            innerNew = (DbNewInstanceExpression)innerProject.Projection;
 
            return true; 
        }
 
        /// 
        /// Collapses outerProject(outerProjection(innerProject(innerNew)))
        /// 
        private static void CollapseNestedProjection(ExpressionReplacement replacement, 
            DbProjectExpression outerProject, DbExpression outerProjection, DbProjectExpression innerProject,
            DbNewInstanceExpression innerNew) 
        { 
            replacement.VisitReplacement = true; // continue collapsing projection until the pattern no longer matches
 
            // get membername -> expression bindings for the inner select so that we know how map property
            // references to the inner projectio
            Dictionary bindings = new Dictionary(innerNew.Arguments.Count);
            TypeUsage innerResultTypeUsage = innerNew.ResultType; 
            RowType innerResultType = (RowType)innerResultTypeUsage.EdmType;
 
            for (int ordinal = 0; ordinal < innerResultType.Members.Count; ordinal++) 
            {
                bindings[innerResultType.Members[ordinal].Name] = innerNew.Arguments[ordinal]; 
            }

            // initialize an expression replacer that knows how to map arguments to the outer projection
            // to the inner projection source 
            ProjectionCollapser collapser = new ProjectionCollapser(bindings, outerProject.Input);
            ExpressionReplacer replacer = new ExpressionReplacer(collapser.CollapseProjection); 
 
            // replace all property references to the inner projection
            var replacementOuterProjection = replacer.Replace(outerProjection); 
            DbProjectExpression replacementOuterProject = outerProject.CommandTree.CreateProjectExpression(
                innerProject.Input, replacementOuterProjection);

            // make sure the collapsing was successful; if not, give up on simplification 
            if (collapser.IsDoomed) { return; }
 
            // set replacement value so that the expression replacer infrastructure can substitute 
            // the collapsed projection in the expression tree
            replacement.Replacement = replacementOuterProject; 
        }

        private static void SimplifyCaseStatements(ExpressionReplacement replacement)
        { 
            var candidate = replacement.Current;
            if (candidate.ExpressionKind != DbExpressionKind.Case) { return; } 
 
            var caseExpression = (DbCaseExpression)replacement.Current;
 
            // try simplifying predicates
            bool predicateSimplified = false;
            List rewrittenPredicates = new List(caseExpression.When.Count);
            foreach (var when in caseExpression.When) 
            {
                DbExpression simplifiedPredicate; 
                if (TrySimplifyPredicate(when, out simplifiedPredicate)) 
                {
                    rewrittenPredicates.Add(simplifiedPredicate); 
                    predicateSimplified = true;
                }
                else
                { 
                    rewrittenPredicates.Add(when);
                } 
            } 

            if (!predicateSimplified) { return; } 

            replacement.Replacement = caseExpression.CommandTree.CreateCaseExpression(
                rewrittenPredicates, caseExpression.Then, caseExpression.Else);
            replacement.VisitReplacement = true; 
        }
 
        private static bool TrySimplifyPredicate(DbExpression predicate, out DbExpression simplified) 
        {
            simplified = null; 
            if (predicate.ExpressionKind != DbExpressionKind.Case) { return false; }
            var caseExpression = (DbCaseExpression)predicate;
            if (caseExpression.Then.Count != 1 && caseExpression.Then[0].ExpressionKind == DbExpressionKind.Constant)
            { 
                return false;
            } 
            var then = (DbConstantExpression)caseExpression.Then[0]; 
            if (!true.Equals(then.Value)) { return false; }
            if (caseExpression.Else != null) 
            {
                if (caseExpression.Else.ExpressionKind != DbExpressionKind.Constant) { return false; }
                var when = (DbConstantExpression)caseExpression.Else;
                if (!false.Equals(when.Value)) { return false; } 
            }
            simplified = caseExpression.When[0]; 
            return true; 
        }
 
        /// 
        /// replacer used to simplify argument value in a new instance expression OuterNew from
        /// an expression of the form:
        /// 
        ///      outerProject(outerBinding(innerProject(innerBinding, innerNew)), outerProjection)
        /// 
        /// The replacer collapses the outer project terms to point at the innerNew expression. 
        /// Where possible, VarRef_outer.Property_outer is collapsed to VarRef_inner.Property.
        ///  
        private class ProjectionCollapser
        {
            // the replacer context keeps track of member bindings for var refs and the expression
            // binding for the outer projection being remapped 
            private Dictionary m_varRefMemberBindings;
            private DbExpressionBinding m_outerBinding; 
            private bool m_doomed; 
            internal ProjectionCollapser(Dictionary varRefMemberBindings,
                DbExpressionBinding outerBinding) 
            {
                m_varRefMemberBindings = varRefMemberBindings;
                m_outerBinding = outerBinding;
            } 

            // replacer delegate that identifies the Property(VarRef "Outer binding") pattern, 
            // and remaps the property to the appropriate inner projection member 
            internal void CollapseProjection(ExpressionReplacement replacement)
            { 
                // check for a property of the outer projection binding (that can be remapped)
                if (replacement.Current.ExpressionKind == DbExpressionKind.Property)
                {
                    var property = (DbPropertyExpression)replacement.Current; 
                    if (property.Instance.ExpressionKind == DbExpressionKind.VariableReference &&
                        IsOuterBindingVarRef((DbVariableReferenceExpression)property.Instance)) 
                    { 
                        replacement.VisitReplacement = false;
                        replacement.Replacement = m_varRefMemberBindings[property.Property.Name]; 
                    }
                }
                else if (replacement.Current.ExpressionKind == DbExpressionKind.VariableReference)
                { 
                    // if we encounter an unsubstitutued var ref, give up...
                    var varRef = (DbVariableReferenceExpression)replacement.Current; 
                    if (IsOuterBindingVarRef(varRef)) 
                    {
                        m_doomed = true; 
                    }
                }
            }
 
            /// 
            /// Heuristic check to make sure the var ref is the one we're supposed to be replacing. 
            ///  
            private bool IsOuterBindingVarRef(DbVariableReferenceExpression varRef)
            { 
                return varRef.VariableName == m_outerBinding.VariableName;
            }

            ///  
            /// Returns a value indicating that the transformation has failed.
            ///  
            internal bool IsDoomed 
            {
                get { return m_doomed; } 
            }
        }
        /*
        private abstract class DiscriminatorValueCollection 
        {
            ///  
            /// Add a new discriminator value. Returns true if the value is unique. 
            /// 
            internal abstract bool TryAddDiscriminatorValue(object value); 

            /// 
            /// Associate a discriminator value with the given type. Returns true if the value is known.
            ///  
            internal abstract bool TryAddDiscriminatorValueAssignment(object value, EntityType entityType);
 
            ///  
            ///
            ///  
            internal abstract bool TryAssignDefaultType(EntityType entityType);

            private class TypedDiscriminatorValueCollection
            { 
                private readonly TryConvert _convert;
                private readonly Func, T> _generateUniqueDiscriminator; 
                private readonly HashSet _discriminatorValues; 
                private readonly Dictionary _discriminatorAssignments;
 

            }

            private delegate bool TryConvert(object input, out T output); 
        }
         * */ 
    } 
}

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

                        

Link Menu

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