Propagator.JoinPropagator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / Propagator.JoinPropagator.cs / 2 / Propagator.JoinPropagator.cs

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

using System.Data.Common.CommandTrees; 
using System.Collections.Generic;
using System.Data.Common.Utils;
using System.Diagnostics;
using System.Data.Metadata.Edm; 
namespace System.Data.Mapping.Update.Internal
{ 
    internal partial class Propagator 
    {
        ///  
        /// Performs join propagation. The basic strategy is to identify changes (inserts, deletes)
        /// on either side of the join that are related according to the join criteria. Support is restricted
        /// to conjunctions of equality predicates of the form left property == right property.
        /// When a group of related changes is identified, rules are applied based on the existence of 
        /// different components (e.g., a left insert + right insert).
        ///  
        ///  
        /// The joins handled by this class are degenerate in the sense that a row in the 'left' input always
        /// joins with at most one row in the 'right' input. The restrictions that allow for this assumption 
        /// are described in the update design spec (see 'Level 5 Optimization').
        /// 
        /// 
        /// Propagation rules for joins are stored in static fields of the class (initialized in the static 
        /// constructor for the class).
        ///  
        private partial class JoinPropagator 
        {
            #region Constructors 
            /// 
            /// Constructs a join propagator.
            /// 
            /// Result of propagating changes in the left input to the join 
            /// Result of propagating changes in the right input to the join
            /// Join operator in update mapping view over which to propagate changes 
            /// Handler of propagation for the entire update mapping view 
            internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent)
            { 
                EntityUtil.CheckArgumentNull(left, "left");
                EntityUtil.CheckArgumentNull(right, "right");
                EntityUtil.CheckArgumentNull(node, "node");
                EntityUtil.CheckArgumentNull(parent, "parent"); 

                Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " + 
                    "caller must ensure only left outer and inner joins are requested"); 

                m_joinExpression = node; 
                m_left = left;
                m_right = right;
                m_parent = parent;
 
                Initialize();
            } 
            #endregion 

            #region Fields 
            #region Propagation rules
            /**
             * These static dictionaries are initialized by the static constructor for this class.
             * They describe for each combination of input elements (the key) propagation rules, which 
             * are expressions over the input expressions.
             * */ 
            private static Dictionary s_innerJoinInsertRules; 
            private static Dictionary s_innerJoinDeleteRules;
            private static Dictionary s_leftOuterJoinInsertRules; 
            private static Dictionary s_leftOuterJoinDeleteRules;
            private static bool s_rulesInitialized;
            private static object s_initializeRulesLockObject = new object();
            #endregion 

            private DbExpression[] m_leftProperties; 
            private DbExpression[] m_rightProperties; 
            private Dictionary m_leftInserts;
            private Dictionary m_leftDeletes; 
            private Dictionary m_rightInserts;
            private Dictionary m_rightDeletes;
            private Set m_allKeys;
            private DbJoinExpression m_joinExpression; 
            private ChangeNode m_left;
            private ChangeNode m_right; 
            private Propagator m_parent; 
            private Dictionary m_insertRules;
            private Dictionary m_deleteRules; 
            private Dictionary m_leftKeyMap;
            private Dictionary m_rightKeyMap;
            #endregion
 
            #region Methods
            ///  
            /// Initialize rules. 
            /// 
            private static void InitializeRules() 
            {
                s_innerJoinInsertRules = new Dictionary(EqualityComparer.Default);
                s_innerJoinDeleteRules = new Dictionary(EqualityComparer.Default);
                s_leftOuterJoinInsertRules = new Dictionary(EqualityComparer.Default); 
                s_leftOuterJoinDeleteRules = new Dictionary(EqualityComparer.Default);
 
                #region Initialize propagation rules 
                // 
                InitializeRule(Ops.LeftUpdate | Ops.RightUpdate, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete, 
                    Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete);

                InitializeRule(Ops.LeftDelete | Ops.RightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete,
                    Ops.Nothing, Ops.LeftDeleteJoinRightDelete); 

                InitializeRule(Ops.LeftInsert | Ops.RightInsert, Ops.LeftInsertJoinRightInsert, Ops.Nothing, 
                    Ops.LeftInsertJoinRightInsert, Ops.Nothing); 

                InitializeRule(Ops.LeftUpdate, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended, 
                    Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended);

                InitializeRule(Ops.RightUpdate, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended,
                    Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended); 

                InitializeRule(Ops.LeftUpdate | Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertNullModifiedExtended, Ops.LeftDeleteJoinRightDelete); 

                InitializeRule(Ops.LeftUpdate | Ops.RightInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteNullModifiedExtended);

                InitializeRule(Ops.LeftDelete, Ops.Nothing, Ops.Nothing,
                    Ops.Nothing, Ops.LeftDeleteNullPreserveExtended); 

                InitializeRule(Ops.LeftInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertNullModifiedExtended, Ops.Nothing); 

                InitializeRule(Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftUnknownNullModifiedExtended, Ops.RightDeleteUnknownExtended);

                InitializeRule(Ops.RightInsert, Ops.Nothing, Ops.Nothing,
                    Ops.RightInsertUnknownExtended, Ops.LeftUnknownNullModifiedExtended); 

                InitializeRule(Ops.LeftDelete | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing); 

                InitializeRule(Ops.LeftDelete | Ops.RightInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing);

                InitializeRule(Ops.LeftInsert | Ops.RightUpdate, Ops.Nothing, Ops.Nothing,
                    Ops.Nothing, Ops.Nothing); 

                InitializeRule(Ops.LeftInsert | Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing); 
                #endregion
            } 

            /// 
            /// Initializes propagation rules for a specific input combination.
            ///  
            /// Describes the elements available in the input
            /// Describes the rule for inserts when the operator is an inner join 
            /// Describes the rule for deletes when the operator is an inner join 
            /// Describes the rule for inserts when the operator is a left outer join
            /// Describes the rule for deletes when the operator is a left outer join 
            private static void InitializeRule(Ops input, Ops joinInsert, Ops joinDelete, Ops lojInsert, Ops lojDelete)
            {
                s_innerJoinInsertRules.Add(input, joinInsert);
                s_innerJoinDeleteRules.Add(input, joinDelete); 
                s_leftOuterJoinInsertRules.Add(input, lojInsert);
                s_leftOuterJoinDeleteRules.Add(input, lojDelete); 
 
                // Ensure that the right hand side of each rule contains no requests for specific row values
                // that are not also in the input. 
                Debug.Assert((((joinInsert | joinDelete | lojInsert | lojDelete) &
                    (Ops.LeftInsert | Ops.LeftDelete | Ops.RightInsert | Ops.RightDelete)) & (~input)) == Ops.Nothing,
                    "(Update/JoinPropagator/Initialization) Rules can't use unavailable data");
 
                // An unknown value can appear in both the delete and insert rule result or neither.
                Debug.Assert(((joinInsert ^ joinDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing && 
                    ((lojInsert ^ lojDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing, 
                    "(Update/JoinPropagator/Initialization) Unknowns must appear in both delete and insert rules " +
                    "or in neither (in other words, for updates only)"); 
            }


            ///  
            /// Determines locations of join key components in .
            ///  
            /// Empty record used for null/unknown extensions in propagation 
            /// rules
            /// Expressions describing the location of join key properties. 
            /// Map from expressions in the placeholder to join key ordinals.
            private Dictionary GetKeyMap(PropagatorResult placeholder,
                DbExpression[] properties)
            { 
                Dictionary map = new Dictionary();
                for (int i = 0; i < properties.Length; i++) 
                { 
                    // Determine the position of the key property in the placeholder
                    DbExpression keyProperty = properties[i]; 
                    PropagatorResult locationInPlaceholder = Evaluator.Evaluate(keyProperty, placeholder, m_parent);
                    Debug.Assert(locationInPlaceholder.IsSimple, "key values must be simple constants");
                    map[locationInPlaceholder] = i;
                } 
                return map;
            } 
 
            /// 
            /// Performs join propagation. 
            /// 
            /// Changes propagated to the current join node in the update mapping view.
            internal ChangeNode ExecutePropagation()
            { 
                // Construct an empty change node for the result
                ChangeNode result = Propagator.BuildChangeNode(m_joinExpression); 
 
                // Perform propagation one key at a time
                foreach (CompositeKey key in m_allKeys) 
                {
                    Propagate(key, result);
                }
 
                // Construct a new placeholder (see ChangeNode.Placeholder) for the join result node.
                result.Placeholder = Join(m_left.Placeholder, m_right.Placeholder, result); 
 
                return result;
            } 

            /// 
            /// Joins rows that are related.
            ///  
            /// Left row.
            /// Right row. 
            /// Result change node; used for type information. 
            /// Result of joining the input rows.
            private static PropagatorResult Join(PropagatorResult left, PropagatorResult right, ChangeNode result) 
            {
                PropagatorResult[] joinRecordValues = new PropagatorResult[2];
                joinRecordValues[0] = left;
                joinRecordValues[1] = right; 
                PropagatorResult join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false);
                return join; 
            } 

            ///  
            /// Propagate all changes associated with a particular join key.
            /// 
            /// Key.
            /// Resulting changes are added to this result. 
            private void Propagate(CompositeKey key, ChangeNode result)
            { 
                // Retrieve changes associates with this join key 
                PropagatorResult leftInsert = null;
                PropagatorResult leftDelete = null; 
                PropagatorResult rightInsert = null;
                PropagatorResult rightDelete = null;

                Ops input = Ops.Nothing; 

                if (m_leftInserts.TryGetValue(key, out leftInsert)) { input |= Ops.LeftInsert; } 
                if (m_leftDeletes.TryGetValue(key, out leftDelete)) { input |= Ops.LeftDelete; } 
                if (m_rightInserts.TryGetValue(key, out rightInsert)) { input |= Ops.RightInsert; }
                if (m_rightDeletes.TryGetValue(key, out rightDelete)) { input |= Ops.RightDelete; } 

                // Get propagation rules for the changes
                Ops insertRule = m_insertRules[input];
                Ops deleteRule = m_deleteRules[input]; 

                if (Ops.Unsupported == insertRule || Ops.Unsupported == deleteRule) 
                { 
                    Debug.Fail("no propagation rules specify unsupported");
                    throw EntityUtil.NotSupported(); 
                }

                // Where needed, substitute null/unknown placeholders. In some of the join propagation
                // rules, we handle the case where a side of the join is 'unknown', or where one side 
                // of a join is comprised of an record containing only nulls. For instance, we may update
                // only one extent appearing in a row of a table (unknown), or; we may insert only 
                // the left hand side of a left outer join, in which case the right hand side is 'null'. 
                if (0 != (Ops.LeftUnknown & insertRule)) { leftInsert = LeftPlaceholder(key, PopulateMode.Unknown); }
 
                if (0 != (Ops.LeftUnknown & deleteRule)) { leftDelete = LeftPlaceholder(key, PopulateMode.Unknown); }

                if (0 != (Ops.RightNullModified & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullModified); }
                else if (0 != (Ops.RightNullPreserve & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullPreserve); } 
                else if (0 != (Ops.RightUnknown & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.Unknown); }
 
                if (0 != (Ops.RightNullModified & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullModified); } 
                else if (0 != (Ops.RightNullPreserve & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullPreserve); }
                else if (0 != (Ops.RightUnknown & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.Unknown); } 

                if (null != leftInsert && null != rightInsert)
                {
                    result.Inserted.Add(Join(leftInsert, rightInsert, result)); 
                }
 
                if (null != leftDelete && null != leftDelete) 
                {
                    result.Deleted.Add(Join(leftDelete, rightDelete, result)); 
                }

            }
 
            /// 
            /// Constructs a new placeholder record for the left hand side of the join. Values taken 
            /// from the join key are injected into the record. 
            /// 
            /// Key producing the left hand side. 
            /// Mode used to populate the placeholder
            /// Record corresponding to the type of the left input to the join. Each value in
            /// the record is flagged as  except when it is
            /// a component of the key. 
            private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode)
            { 
                return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator); 
            }
 
            /// 
            /// See 
            /// 
            ///  
            /// 
            ///  
            private PropagatorResult RightPlaceholder(CompositeKey key, PopulateMode mode) 
            {
                return PlaceholderPopulator.Populate(m_right.Placeholder, key, m_rightKeyMap, mode, m_parent.UpdateTranslator); 
            }

            /// 
            /// Initialize all structures. 
            /// 
            private void Initialize() 
            { 
                // Check that static rule definitions have been initialized
                lock (s_initializeRulesLockObject) 
                {
                    if (!s_rulesInitialized)
                    {
                        InitializeRules(); 
                        s_rulesInitialized = true;
                    } 
                } 

                // Extract join key properties from the left and right sides of the join 
                JoinPredicateVisitor.ExtractEquijoinProperties(m_joinExpression.JoinCondition, out m_leftProperties, out m_rightProperties);

                // Initialize key maps, which map from expressions in the placeholders for the join inputs to
                // ordinals in the join key. See ChangeNode.Placeholder and HashJoinKey for additional context. 
                m_leftKeyMap = GetKeyMap(m_left.Placeholder, m_leftProperties);
                m_rightKeyMap = GetKeyMap(m_right.Placeholder, m_rightProperties); 
 
                // Retrieve propagation rules for the join type of the expression.
                if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind) 
                {
                    m_insertRules = s_innerJoinInsertRules;
                    m_deleteRules = s_innerJoinDeleteRules;
                } 
                else
                { 
                    m_insertRules = s_leftOuterJoinInsertRules; 
                    m_deleteRules = s_leftOuterJoinDeleteRules;
                } 

                // Determine key values for keys in the insert and delete sets from the left and right hand sides
                // of the join input. Also construct a set of all keys.
                m_allKeys = new Set(m_parent.UpdateTranslator.KeyComparer); 
                m_leftInserts = ProcessKeys(m_left.Inserted, m_leftProperties);
                m_leftDeletes = ProcessKeys(m_left.Deleted, m_leftProperties); 
                m_rightInserts = ProcessKeys(m_right.Inserted, m_rightProperties); 
                m_rightDeletes = ProcessKeys(m_right.Deleted, m_rightProperties);
            } 

            /// 
            /// Produces a hash table of all instances and processes join keys, adding them to the list
            /// of keys handled by this node. 
            /// 
            /// List of instances (whether delete or insert) for this node. 
            /// Properties of an instance that constitute the join key. 
            /// A map from join keys to instances.
            private Dictionary ProcessKeys(IEnumerable instances, 
                DbExpression[] properties)
            {
                Dictionary hash = new Dictionary(
                    m_parent.UpdateTranslator.KeyComparer); 

                foreach (PropagatorResult instance in instances) 
                { 
                    CompositeKey key = new CompositeKey(GetKeyConstants(instance, properties));
 
                    // check if this key has been added already (if not, add it)
                    if (!m_allKeys.Contains(key))
                    {
                        m_allKeys.Add(key); 
                    }
                    hash[key] = instance; 
                } 

                return hash; 
            }

            // extracts key values from row expression
            private PropagatorResult[] GetKeyConstants(PropagatorResult change, DbExpression[] properties) 
            {
                Debug.Assert(null != change && null != properties); 
                PropagatorResult[] keyConstants = new PropagatorResult[properties.Length]; 
                for (int i = 0; i < properties.Length; i++)
                { 
                    PropagatorResult constant = Evaluator.Evaluate(properties[i], change, m_parent);
                    keyConstants[i] = constant;
                }
                return keyConstants; 
            }
            #endregion 
 
            #region Nested types
            ///  
            /// Flags indicating which change elements are available (0-4) and propagation
            /// rules (0, 5-512)
            /// 
            [Flags] 
            enum Ops : uint
            { 
                Nothing = 0, 
                LeftInsert = 1,
                LeftDelete = 2, 
                RightInsert = 4,
                RightDelete = 8,
                LeftUnknown = 32,
                RightNullModified = 128, 
                RightNullPreserve = 256,
                RightUnknown = 512, 
                LeftUpdate = LeftInsert | LeftDelete, 
                RightUpdate = RightInsert | RightDelete,
                Unsupported = 4096, 
                #region Propagation rule descriptions
                LeftInsertJoinRightInsert = LeftInsert | RightInsert,
                LeftDeleteJoinRightDelete = LeftDelete | RightDelete,
                LeftInsertNullModifiedExtended = LeftInsert | RightNullModified, 
                LeftInsertNullPreserveExtended = LeftInsert | RightNullPreserve,
                LeftInsertUnknownExtended = LeftInsert | RightUnknown, 
                LeftDeleteNullModifiedExtended = LeftDelete | RightNullModified, 
                LeftDeleteNullPreserveExtended = LeftDelete | RightNullPreserve,
                LeftDeleteUnknownExtended = LeftDelete | RightUnknown, 
                LeftUnknownNullModifiedExtended = LeftUnknown | RightNullModified,
                LeftUnknownNullPreserveExtended = LeftUnknown | RightNullPreserve,
                RightInsertUnknownExtended = LeftUnknown | RightInsert,
                RightDeleteUnknownExtended = LeftUnknown | RightDelete, 
                #endregion
            } 
            #endregion 
        }
    } 
}

// 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.Common.Utils;
using System.Diagnostics;
using System.Data.Metadata.Edm; 
namespace System.Data.Mapping.Update.Internal
{ 
    internal partial class Propagator 
    {
        ///  
        /// Performs join propagation. The basic strategy is to identify changes (inserts, deletes)
        /// on either side of the join that are related according to the join criteria. Support is restricted
        /// to conjunctions of equality predicates of the form left property == right property.
        /// When a group of related changes is identified, rules are applied based on the existence of 
        /// different components (e.g., a left insert + right insert).
        ///  
        ///  
        /// The joins handled by this class are degenerate in the sense that a row in the 'left' input always
        /// joins with at most one row in the 'right' input. The restrictions that allow for this assumption 
        /// are described in the update design spec (see 'Level 5 Optimization').
        /// 
        /// 
        /// Propagation rules for joins are stored in static fields of the class (initialized in the static 
        /// constructor for the class).
        ///  
        private partial class JoinPropagator 
        {
            #region Constructors 
            /// 
            /// Constructs a join propagator.
            /// 
            /// Result of propagating changes in the left input to the join 
            /// Result of propagating changes in the right input to the join
            /// Join operator in update mapping view over which to propagate changes 
            /// Handler of propagation for the entire update mapping view 
            internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent)
            { 
                EntityUtil.CheckArgumentNull(left, "left");
                EntityUtil.CheckArgumentNull(right, "right");
                EntityUtil.CheckArgumentNull(node, "node");
                EntityUtil.CheckArgumentNull(parent, "parent"); 

                Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " + 
                    "caller must ensure only left outer and inner joins are requested"); 

                m_joinExpression = node; 
                m_left = left;
                m_right = right;
                m_parent = parent;
 
                Initialize();
            } 
            #endregion 

            #region Fields 
            #region Propagation rules
            /**
             * These static dictionaries are initialized by the static constructor for this class.
             * They describe for each combination of input elements (the key) propagation rules, which 
             * are expressions over the input expressions.
             * */ 
            private static Dictionary s_innerJoinInsertRules; 
            private static Dictionary s_innerJoinDeleteRules;
            private static Dictionary s_leftOuterJoinInsertRules; 
            private static Dictionary s_leftOuterJoinDeleteRules;
            private static bool s_rulesInitialized;
            private static object s_initializeRulesLockObject = new object();
            #endregion 

            private DbExpression[] m_leftProperties; 
            private DbExpression[] m_rightProperties; 
            private Dictionary m_leftInserts;
            private Dictionary m_leftDeletes; 
            private Dictionary m_rightInserts;
            private Dictionary m_rightDeletes;
            private Set m_allKeys;
            private DbJoinExpression m_joinExpression; 
            private ChangeNode m_left;
            private ChangeNode m_right; 
            private Propagator m_parent; 
            private Dictionary m_insertRules;
            private Dictionary m_deleteRules; 
            private Dictionary m_leftKeyMap;
            private Dictionary m_rightKeyMap;
            #endregion
 
            #region Methods
            ///  
            /// Initialize rules. 
            /// 
            private static void InitializeRules() 
            {
                s_innerJoinInsertRules = new Dictionary(EqualityComparer.Default);
                s_innerJoinDeleteRules = new Dictionary(EqualityComparer.Default);
                s_leftOuterJoinInsertRules = new Dictionary(EqualityComparer.Default); 
                s_leftOuterJoinDeleteRules = new Dictionary(EqualityComparer.Default);
 
                #region Initialize propagation rules 
                // 
                InitializeRule(Ops.LeftUpdate | Ops.RightUpdate, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete, 
                    Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete);

                InitializeRule(Ops.LeftDelete | Ops.RightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete,
                    Ops.Nothing, Ops.LeftDeleteJoinRightDelete); 

                InitializeRule(Ops.LeftInsert | Ops.RightInsert, Ops.LeftInsertJoinRightInsert, Ops.Nothing, 
                    Ops.LeftInsertJoinRightInsert, Ops.Nothing); 

                InitializeRule(Ops.LeftUpdate, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended, 
                    Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended);

                InitializeRule(Ops.RightUpdate, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended,
                    Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended); 

                InitializeRule(Ops.LeftUpdate | Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertNullModifiedExtended, Ops.LeftDeleteJoinRightDelete); 

                InitializeRule(Ops.LeftUpdate | Ops.RightInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteNullModifiedExtended);

                InitializeRule(Ops.LeftDelete, Ops.Nothing, Ops.Nothing,
                    Ops.Nothing, Ops.LeftDeleteNullPreserveExtended); 

                InitializeRule(Ops.LeftInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftInsertNullModifiedExtended, Ops.Nothing); 

                InitializeRule(Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.LeftUnknownNullModifiedExtended, Ops.RightDeleteUnknownExtended);

                InitializeRule(Ops.RightInsert, Ops.Nothing, Ops.Nothing,
                    Ops.RightInsertUnknownExtended, Ops.LeftUnknownNullModifiedExtended); 

                InitializeRule(Ops.LeftDelete | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing); 

                InitializeRule(Ops.LeftDelete | Ops.RightInsert, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing);

                InitializeRule(Ops.LeftInsert | Ops.RightUpdate, Ops.Nothing, Ops.Nothing,
                    Ops.Nothing, Ops.Nothing); 

                InitializeRule(Ops.LeftInsert | Ops.RightDelete, Ops.Nothing, Ops.Nothing, 
                    Ops.Nothing, Ops.Nothing); 
                #endregion
            } 

            /// 
            /// Initializes propagation rules for a specific input combination.
            ///  
            /// Describes the elements available in the input
            /// Describes the rule for inserts when the operator is an inner join 
            /// Describes the rule for deletes when the operator is an inner join 
            /// Describes the rule for inserts when the operator is a left outer join
            /// Describes the rule for deletes when the operator is a left outer join 
            private static void InitializeRule(Ops input, Ops joinInsert, Ops joinDelete, Ops lojInsert, Ops lojDelete)
            {
                s_innerJoinInsertRules.Add(input, joinInsert);
                s_innerJoinDeleteRules.Add(input, joinDelete); 
                s_leftOuterJoinInsertRules.Add(input, lojInsert);
                s_leftOuterJoinDeleteRules.Add(input, lojDelete); 
 
                // Ensure that the right hand side of each rule contains no requests for specific row values
                // that are not also in the input. 
                Debug.Assert((((joinInsert | joinDelete | lojInsert | lojDelete) &
                    (Ops.LeftInsert | Ops.LeftDelete | Ops.RightInsert | Ops.RightDelete)) & (~input)) == Ops.Nothing,
                    "(Update/JoinPropagator/Initialization) Rules can't use unavailable data");
 
                // An unknown value can appear in both the delete and insert rule result or neither.
                Debug.Assert(((joinInsert ^ joinDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing && 
                    ((lojInsert ^ lojDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing, 
                    "(Update/JoinPropagator/Initialization) Unknowns must appear in both delete and insert rules " +
                    "or in neither (in other words, for updates only)"); 
            }


            ///  
            /// Determines locations of join key components in .
            ///  
            /// Empty record used for null/unknown extensions in propagation 
            /// rules
            /// Expressions describing the location of join key properties. 
            /// Map from expressions in the placeholder to join key ordinals.
            private Dictionary GetKeyMap(PropagatorResult placeholder,
                DbExpression[] properties)
            { 
                Dictionary map = new Dictionary();
                for (int i = 0; i < properties.Length; i++) 
                { 
                    // Determine the position of the key property in the placeholder
                    DbExpression keyProperty = properties[i]; 
                    PropagatorResult locationInPlaceholder = Evaluator.Evaluate(keyProperty, placeholder, m_parent);
                    Debug.Assert(locationInPlaceholder.IsSimple, "key values must be simple constants");
                    map[locationInPlaceholder] = i;
                } 
                return map;
            } 
 
            /// 
            /// Performs join propagation. 
            /// 
            /// Changes propagated to the current join node in the update mapping view.
            internal ChangeNode ExecutePropagation()
            { 
                // Construct an empty change node for the result
                ChangeNode result = Propagator.BuildChangeNode(m_joinExpression); 
 
                // Perform propagation one key at a time
                foreach (CompositeKey key in m_allKeys) 
                {
                    Propagate(key, result);
                }
 
                // Construct a new placeholder (see ChangeNode.Placeholder) for the join result node.
                result.Placeholder = Join(m_left.Placeholder, m_right.Placeholder, result); 
 
                return result;
            } 

            /// 
            /// Joins rows that are related.
            ///  
            /// Left row.
            /// Right row. 
            /// Result change node; used for type information. 
            /// Result of joining the input rows.
            private static PropagatorResult Join(PropagatorResult left, PropagatorResult right, ChangeNode result) 
            {
                PropagatorResult[] joinRecordValues = new PropagatorResult[2];
                joinRecordValues[0] = left;
                joinRecordValues[1] = right; 
                PropagatorResult join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false);
                return join; 
            } 

            ///  
            /// Propagate all changes associated with a particular join key.
            /// 
            /// Key.
            /// Resulting changes are added to this result. 
            private void Propagate(CompositeKey key, ChangeNode result)
            { 
                // Retrieve changes associates with this join key 
                PropagatorResult leftInsert = null;
                PropagatorResult leftDelete = null; 
                PropagatorResult rightInsert = null;
                PropagatorResult rightDelete = null;

                Ops input = Ops.Nothing; 

                if (m_leftInserts.TryGetValue(key, out leftInsert)) { input |= Ops.LeftInsert; } 
                if (m_leftDeletes.TryGetValue(key, out leftDelete)) { input |= Ops.LeftDelete; } 
                if (m_rightInserts.TryGetValue(key, out rightInsert)) { input |= Ops.RightInsert; }
                if (m_rightDeletes.TryGetValue(key, out rightDelete)) { input |= Ops.RightDelete; } 

                // Get propagation rules for the changes
                Ops insertRule = m_insertRules[input];
                Ops deleteRule = m_deleteRules[input]; 

                if (Ops.Unsupported == insertRule || Ops.Unsupported == deleteRule) 
                { 
                    Debug.Fail("no propagation rules specify unsupported");
                    throw EntityUtil.NotSupported(); 
                }

                // Where needed, substitute null/unknown placeholders. In some of the join propagation
                // rules, we handle the case where a side of the join is 'unknown', or where one side 
                // of a join is comprised of an record containing only nulls. For instance, we may update
                // only one extent appearing in a row of a table (unknown), or; we may insert only 
                // the left hand side of a left outer join, in which case the right hand side is 'null'. 
                if (0 != (Ops.LeftUnknown & insertRule)) { leftInsert = LeftPlaceholder(key, PopulateMode.Unknown); }
 
                if (0 != (Ops.LeftUnknown & deleteRule)) { leftDelete = LeftPlaceholder(key, PopulateMode.Unknown); }

                if (0 != (Ops.RightNullModified & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullModified); }
                else if (0 != (Ops.RightNullPreserve & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullPreserve); } 
                else if (0 != (Ops.RightUnknown & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.Unknown); }
 
                if (0 != (Ops.RightNullModified & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullModified); } 
                else if (0 != (Ops.RightNullPreserve & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullPreserve); }
                else if (0 != (Ops.RightUnknown & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.Unknown); } 

                if (null != leftInsert && null != rightInsert)
                {
                    result.Inserted.Add(Join(leftInsert, rightInsert, result)); 
                }
 
                if (null != leftDelete && null != leftDelete) 
                {
                    result.Deleted.Add(Join(leftDelete, rightDelete, result)); 
                }

            }
 
            /// 
            /// Constructs a new placeholder record for the left hand side of the join. Values taken 
            /// from the join key are injected into the record. 
            /// 
            /// Key producing the left hand side. 
            /// Mode used to populate the placeholder
            /// Record corresponding to the type of the left input to the join. Each value in
            /// the record is flagged as  except when it is
            /// a component of the key. 
            private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode)
            { 
                return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator); 
            }
 
            /// 
            /// See 
            /// 
            ///  
            /// 
            ///  
            private PropagatorResult RightPlaceholder(CompositeKey key, PopulateMode mode) 
            {
                return PlaceholderPopulator.Populate(m_right.Placeholder, key, m_rightKeyMap, mode, m_parent.UpdateTranslator); 
            }

            /// 
            /// Initialize all structures. 
            /// 
            private void Initialize() 
            { 
                // Check that static rule definitions have been initialized
                lock (s_initializeRulesLockObject) 
                {
                    if (!s_rulesInitialized)
                    {
                        InitializeRules(); 
                        s_rulesInitialized = true;
                    } 
                } 

                // Extract join key properties from the left and right sides of the join 
                JoinPredicateVisitor.ExtractEquijoinProperties(m_joinExpression.JoinCondition, out m_leftProperties, out m_rightProperties);

                // Initialize key maps, which map from expressions in the placeholders for the join inputs to
                // ordinals in the join key. See ChangeNode.Placeholder and HashJoinKey for additional context. 
                m_leftKeyMap = GetKeyMap(m_left.Placeholder, m_leftProperties);
                m_rightKeyMap = GetKeyMap(m_right.Placeholder, m_rightProperties); 
 
                // Retrieve propagation rules for the join type of the expression.
                if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind) 
                {
                    m_insertRules = s_innerJoinInsertRules;
                    m_deleteRules = s_innerJoinDeleteRules;
                } 
                else
                { 
                    m_insertRules = s_leftOuterJoinInsertRules; 
                    m_deleteRules = s_leftOuterJoinDeleteRules;
                } 

                // Determine key values for keys in the insert and delete sets from the left and right hand sides
                // of the join input. Also construct a set of all keys.
                m_allKeys = new Set(m_parent.UpdateTranslator.KeyComparer); 
                m_leftInserts = ProcessKeys(m_left.Inserted, m_leftProperties);
                m_leftDeletes = ProcessKeys(m_left.Deleted, m_leftProperties); 
                m_rightInserts = ProcessKeys(m_right.Inserted, m_rightProperties); 
                m_rightDeletes = ProcessKeys(m_right.Deleted, m_rightProperties);
            } 

            /// 
            /// Produces a hash table of all instances and processes join keys, adding them to the list
            /// of keys handled by this node. 
            /// 
            /// List of instances (whether delete or insert) for this node. 
            /// Properties of an instance that constitute the join key. 
            /// A map from join keys to instances.
            private Dictionary ProcessKeys(IEnumerable instances, 
                DbExpression[] properties)
            {
                Dictionary hash = new Dictionary(
                    m_parent.UpdateTranslator.KeyComparer); 

                foreach (PropagatorResult instance in instances) 
                { 
                    CompositeKey key = new CompositeKey(GetKeyConstants(instance, properties));
 
                    // check if this key has been added already (if not, add it)
                    if (!m_allKeys.Contains(key))
                    {
                        m_allKeys.Add(key); 
                    }
                    hash[key] = instance; 
                } 

                return hash; 
            }

            // extracts key values from row expression
            private PropagatorResult[] GetKeyConstants(PropagatorResult change, DbExpression[] properties) 
            {
                Debug.Assert(null != change && null != properties); 
                PropagatorResult[] keyConstants = new PropagatorResult[properties.Length]; 
                for (int i = 0; i < properties.Length; i++)
                { 
                    PropagatorResult constant = Evaluator.Evaluate(properties[i], change, m_parent);
                    keyConstants[i] = constant;
                }
                return keyConstants; 
            }
            #endregion 
 
            #region Nested types
            ///  
            /// Flags indicating which change elements are available (0-4) and propagation
            /// rules (0, 5-512)
            /// 
            [Flags] 
            enum Ops : uint
            { 
                Nothing = 0, 
                LeftInsert = 1,
                LeftDelete = 2, 
                RightInsert = 4,
                RightDelete = 8,
                LeftUnknown = 32,
                RightNullModified = 128, 
                RightNullPreserve = 256,
                RightUnknown = 512, 
                LeftUpdate = LeftInsert | LeftDelete, 
                RightUpdate = RightInsert | RightDelete,
                Unsupported = 4096, 
                #region Propagation rule descriptions
                LeftInsertJoinRightInsert = LeftInsert | RightInsert,
                LeftDeleteJoinRightDelete = LeftDelete | RightDelete,
                LeftInsertNullModifiedExtended = LeftInsert | RightNullModified, 
                LeftInsertNullPreserveExtended = LeftInsert | RightNullPreserve,
                LeftInsertUnknownExtended = LeftInsert | RightUnknown, 
                LeftDeleteNullModifiedExtended = LeftDelete | RightNullModified, 
                LeftDeleteNullPreserveExtended = LeftDelete | RightNullPreserve,
                LeftDeleteUnknownExtended = LeftDelete | RightUnknown, 
                LeftUnknownNullModifiedExtended = LeftUnknown | RightNullModified,
                LeftUnknownNullPreserveExtended = LeftUnknown | RightNullPreserve,
                RightInsertUnknownExtended = LeftUnknown | RightInsert,
                RightDeleteUnknownExtended = LeftUnknown | RightDelete, 
                #endregion
            } 
            #endregion 
        }
    } 
}

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

                        

Link Menu

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