f4fa3a2a0729cf03d88140817c7e0ea5fd991964
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / Update / Internal / Propagator.JoinPropagator.SubstitutingCloneVisitor.cs
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>
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 }