1 //--------------------------------------------------------------------- 2 // <copyright file="Propagator.JoinPropagator.SubstitutingCloneVisitor.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 using System.Collections.Generic; 11 using System.Data.Common; 12 13 namespace System.Data.Mapping.Update.Internal 14 { 15 internal partial class Propagator 16 { 17 private partial class JoinPropagator 18 { 19 /// <summary> 20 /// Describes the mode of behavior for the <see cref="PlaceholderPopulator"/>. 21 /// </summary> 22 private enum PopulateMode 23 { 24 /// <summary> 25 /// Produce a null extension record (for outer joins) marked as modified 26 /// </summary> 27 NullModified, 28 /// <summary> 29 /// Produce a null extension record (for outer joins) marked as preserve 30 /// </summary> 31 NullPreserve, 32 /// <summary> 33 /// Produce a placeholder for a record that is known to exist but whose specific 34 /// values are unknown. 35 /// </summary> 36 Unknown, 37 } 38 39 /// <summary> 40 /// Fills in a placeholder with join key data (also performs a clone so that the 41 /// placeholder can be reused). 42 /// </summary> 43 /// <remarks> 44 /// Clones of placeholder nodes are created when either the structure of the node 45 /// needs to change or the record markup for the node needs to change. 46 /// </remarks> 47 private static class PlaceholderPopulator 48 { 49 #region Methods 50 /// <summary> 51 /// Construct a new placeholder with the shape of the given placeholder. Key values are 52 /// injected into the resulting place holder and default values are substituted with 53 /// either propagator constants or progagator nulls depending on the mode established 54 /// by the <paramref name="mode"/> flag. 55 /// </summary> 56 /// <remarks> 57 /// The key is essentially an array of values. The key map indicates that for a particular 58 /// placeholder an expression (keyMap.Keys) corresponds to some ordinal in the key array. 59 /// </remarks> 60 /// <param name="placeholder">Placeholder to clone</param> 61 /// <param name="key">Key to substitute</param> 62 /// <param name="placeholderKey">Key elements in the placeholder (ordinally aligned with 'key')</param> 63 /// <param name="mode">Mode of operation.</param> 64 /// <param name="translator">Translator context.</param> 65 /// <returns>Cloned placeholder with key values</returns> Populate(PropagatorResult placeholder, CompositeKey key, CompositeKey placeholderKey, PopulateMode mode, UpdateTranslator translator)66 internal static PropagatorResult Populate(PropagatorResult placeholder, CompositeKey key, 67 CompositeKey placeholderKey, PopulateMode mode, UpdateTranslator translator) 68 { 69 EntityUtil.CheckArgumentNull(placeholder, "placeholder"); 70 EntityUtil.CheckArgumentNull(key, "key"); 71 EntityUtil.CheckArgumentNull(placeholderKey, "placeholderKey"); 72 EntityUtil.CheckArgumentNull(translator, "translator"); 73 74 // Figure out which flags to apply to generated elements. 75 bool isNull = mode == PopulateMode.NullModified || mode == PopulateMode.NullPreserve; 76 bool preserve = mode == PopulateMode.NullPreserve || mode == PopulateMode.Unknown; 77 PropagatorFlags flags = PropagatorFlags.NoFlags; 78 if (!isNull) { flags |= PropagatorFlags.Unknown; } // only null values are known 79 if (preserve) { flags |= PropagatorFlags.Preserve; } 80 81 PropagatorResult result = placeholder.Replace(node => 82 { 83 // See if this is a key element 84 int keyIndex = -1; 85 for (int i = 0; i < placeholderKey.KeyComponents.Length; i++) 86 { 87 if (placeholderKey.KeyComponents[i] == node) 88 { 89 keyIndex = i; 90 break; 91 } 92 } 93 94 if (keyIndex != -1) 95 { 96 // Key value. 97 return key.KeyComponents[keyIndex]; 98 } 99 else 100 { 101 // for simple entries, just return using the markup context for this 102 // populator 103 object value = isNull ? null : node.GetSimpleValue(); 104 return PropagatorResult.CreateSimpleValue(flags, value); 105 } 106 }); 107 108 return result; 109 } 110 #endregion 111 } 112 } 113 } 114 } 115