File: System\Data\Mapping\Update\Internal\Propagator.JoinPropagator.SubstitutingCloneVisitor.cs
Project: ndp\fx\src\DataEntity\System.Data.Entity.csproj (System.Data.Entity)
//---------------------------------------------------------------------
// <copyright file="Propagator.JoinPropagator.SubstitutingCloneVisitor.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
 
using System.Collections.Generic;
using System.Data.Common;
 
namespace System.Data.Mapping.Update.Internal
{
    internal partial class Propagator
    {
        private partial class JoinPropagator
        {
            /// <summary>
            /// Describes the mode of behavior for the <see cref="PlaceholderPopulator"/>.
            /// </summary>
            private enum PopulateMode
            {
                /// <summary>
                /// Produce a null extension record (for outer joins) marked as modified
                /// </summary>
                NullModified,
                /// <summary>
                /// Produce a null extension record (for outer joins) marked as preserve
                /// </summary>
                NullPreserve,
                /// <summary>
                /// Produce a placeholder for a record that is known to exist but whose specific
                /// values are unknown.
                /// </summary>
                Unknown,
            }
 
            /// <summary>
            /// Fills in a placeholder with join key data (also performs a clone so that the
            /// placeholder can be reused).
            /// </summary>
            /// <remarks>
            /// Clones of placeholder nodes are created when either the structure of the node
            /// needs to change or the record markup for the node needs to change.
            /// </remarks>
            private static class PlaceholderPopulator
            {
                #region Methods
                /// <summary>
                /// Construct a new placeholder with the shape of the given placeholder. Key values are
                /// injected into the resulting place holder and default values are substituted with
                /// either propagator constants or progagator nulls depending on the mode established
                /// by the <paramref name="mode"/> flag.
                /// </summary>
                /// <remarks>
                /// The key is essentially an array of values. The key map indicates that for a particular
                /// placeholder an expression (keyMap.Keys) corresponds to some ordinal in the key array.
                /// </remarks>
                /// <param name="placeholder">Placeholder to clone</param>
                /// <param name="key">Key to substitute</param>
                /// <param name="placeholderKey">Key elements in the placeholder (ordinally aligned with 'key')</param>
                /// <param name="mode">Mode of operation.</param>
                /// <param name="translator">Translator context.</param>
                /// <returns>Cloned placeholder with key values</returns>
                internal static PropagatorResult Populate(PropagatorResult placeholder, CompositeKey key, 
                    CompositeKey placeholderKey, PopulateMode mode, UpdateTranslator translator)
                {
                    EntityUtil.CheckArgumentNull(placeholder, "placeholder");
                    EntityUtil.CheckArgumentNull(key, "key");
                    EntityUtil.CheckArgumentNull(placeholderKey, "placeholderKey");
                    EntityUtil.CheckArgumentNull(translator, "translator");
 
                    // Figure out which flags to apply to generated elements.
                    bool isNull = mode == PopulateMode.NullModified || mode == PopulateMode.NullPreserve;
                    bool preserve = mode == PopulateMode.NullPreserve || mode == PopulateMode.Unknown;
                    PropagatorFlags flags = PropagatorFlags.NoFlags;
                    if (!isNull) { flags |= PropagatorFlags.Unknown; } // only null values are known
                    if (preserve) { flags |= PropagatorFlags.Preserve; }
 
                    PropagatorResult result = placeholder.Replace(node =>
                        {
                            // See if this is a key element
                            int keyIndex = -1;
                            for (int i = 0; i < placeholderKey.KeyComponents.Length; i++)
                            {
                                if (placeholderKey.KeyComponents[i] == node)
                                {
                                    keyIndex = i;
                                    break;
                                }
                            }
 
                            if (keyIndex != -1)
                            {
                                // Key value.
                                return key.KeyComponents[keyIndex];
                            }
                            else
                            {
                                // for simple entries, just return using the markup context for this
                                // populator
                                object value = isNull ? null : node.GetSimpleValue();
                                return PropagatorResult.CreateSimpleValue(flags, value);
                            }
                        });
                    
                    return result;
                }
                #endregion
            }
        }
    }
}