1 //---------------------------------------------------------------------
2 // <copyright file="MemberProjectionIndex.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Collections.Generic;
12 using System.Data.Common.Utils;
13 using System.Data.Common;
14 using System.Data.Mapping.ViewGeneration.Structures;
15 using System.Diagnostics;
16 using System.Data.Metadata.Edm;
18 namespace System.Data.Mapping.ViewGeneration.Structures
21 /// Manages <see cref="MemberPath"/>s of the members of the types stored in an extent.
22 /// This is a bi-directional dictionary of <see cref="MemberPath"/>s to integer indexes and back.
24 internal sealed class MemberProjectionIndex : InternalBase
27 private readonly Dictionary<MemberPath, int> m_indexMap;
28 private readonly List<MemberPath> m_members;
31 #region Constructor/Factory
33 /// Recursively generates <see cref="MemberPath"/>s for the members of the types stored in the <paramref name="extent"/>.
35 internal static MemberProjectionIndex Create(EntitySetBase extent, EdmItemCollection edmItemCollection)
37 // We generate the indices for the projected slots as we traverse the metadata.
38 MemberProjectionIndex index = new MemberProjectionIndex();
39 GatherPartialSignature(index, edmItemCollection, new MemberPath(extent), false); // need not only keys
44 /// Creates an empty index.
46 private MemberProjectionIndex()
48 m_indexMap = new Dictionary<MemberPath, int>(MemberPath.EqualityComparer);
49 m_members = new List<MemberPath>();
56 get { return m_members.Count; }
59 internal MemberPath this[int index]
61 get { return m_members[index]; }
65 /// Returns the indexes of the key slots corresponding to fields in this for which IsPartOfKey is true.
67 internal IEnumerable<int> KeySlots
71 List<int> result = new List<int>();
72 for (int slotNum = 0; slotNum < Count; slotNum++)
74 // We pass for numboolslots since we know that this is not a
76 if (this.IsKeySlot(slotNum, 0))
86 /// Returns an enumeration of all members
88 internal IEnumerable<MemberPath> Members
90 get { return m_members; }
96 /// Returns a non-negative index of the <paramref name="member"/> if found, otherwise -1.
98 internal int IndexOf(MemberPath member)
101 if (m_indexMap.TryGetValue(member, out index))
112 /// If an index already exists for member, this is a no-op. Else creates the next index available for member and returns it.
114 internal int CreateIndex(MemberPath member)
117 if (false == m_indexMap.TryGetValue(member, out index))
119 index = m_indexMap.Count;
120 m_indexMap[member] = index;
121 m_members.Add(member);
127 /// Given the <paramref name="slotNum"/>, returns the output member path that this slot contributes/corresponds to in the extent view.
128 /// If the slot corresponds to one of the boolean variables, returns null.
130 internal MemberPath GetMemberPath(int slotNum, int numBoolSlots)
132 MemberPath result = this.IsBoolSlot(slotNum, numBoolSlots) ? null : this[slotNum];
137 /// Given the index of a boolean variable (e.g., of from1), returns the slot number for that boolean in this.
139 internal int BoolIndexToSlot(int boolIndex, int numBoolSlots)
141 // Booleans appear after the regular slots
142 Debug.Assert(boolIndex >= 0 && boolIndex < numBoolSlots, "No such boolean in this node");
143 return this.Count + boolIndex;
147 /// Given the <paramref name="slotNum"/> corresponding to a boolean slot, returns the cell number that the cell corresponds to.
149 internal int SlotToBoolIndex(int slotNum, int numBoolSlots)
151 Debug.Assert(slotNum < this.Count + numBoolSlots && slotNum >= this.Count, "No such boolean slot");
152 return slotNum - this.Count;
156 /// Returns true if <paramref name="slotNum"/> corresponds to a key slot in the output extent view.
158 internal bool IsKeySlot(int slotNum, int numBoolSlots)
160 Debug.Assert(slotNum < this.Count + numBoolSlots, "No such slot in tree");
161 return slotNum < this.Count && this[slotNum].IsPartOfKey;
165 /// Returns true if <paramref name="slotNum"/> corresponds to a bool slot and not a regular field.
167 internal bool IsBoolSlot(int slotNum, int numBoolSlots)
169 Debug.Assert(slotNum < this.Count + numBoolSlots, "Boolean slot does not exist in tree");
170 return slotNum >= this.Count;
173 internal override void ToCompactString(StringBuilder builder)
176 StringUtil.ToCommaSeparatedString(builder, m_members);
181 #region Signature construction
183 /// Starting at the <paramref name="member"/>, recursively generates <see cref="MemberPath"/>s for the fields embedded in it.
185 /// <param name="member">corresponds to a value of an Entity or Complex or Association type</param>
186 /// <param name="needKeysOnly">indicates whether we need to only collect members that are keys</param>
187 private static void GatherPartialSignature(MemberProjectionIndex index, EdmItemCollection edmItemCollection, MemberPath member, bool needKeysOnly)
189 EdmType memberType = member.EdmType;
190 ComplexType complexTypemember = memberType as ComplexType;
191 Debug.Assert(complexTypemember != null ||
192 memberType is EntityType || // for entity sets
193 memberType is AssociationType || // For association sets
194 memberType is RefType, // for association ends
195 "GatherPartialSignature can be called only for complex types, entity sets, association ends");
197 if (memberType is ComplexType && needKeysOnly)
199 // Check if the complex type needs to be traversed or not. If not, just return
200 // from here. Else we need to continue to the code below. Right now, we do not
201 // allow keys inside complex types
205 // Make sure that this member is in the slot map before any of its embedded objects.
206 index.CreateIndex(member);
208 // Consider each possible type value -- each type value conributes to a tuple in the result.
209 // For that possible type, add all the type members into the signature.
210 foreach (EdmType possibleType in MetadataHelper.GetTypeAndSubtypesOf(memberType, edmItemCollection, false /*includeAbstractTypes*/))
212 StructuralType possibleStructuralType = possibleType as StructuralType;
213 Debug.Assert(possibleStructuralType != null, "Non-structural subtype?");
215 GatherSignatureFromTypeStructuralMembers(index, edmItemCollection, member, possibleStructuralType, needKeysOnly);
220 /// Given the <paramref name="member"/> and one of its <paramref name="possibleType"/>s, determine the attributes that are relevant
221 /// for this <paramref name="possibleType"/> and return a <see cref="MemberPath"/> signature corresponding to the <paramref name="possibleType"/> and the attributes.
222 /// If <paramref name="needKeysOnly"/>=true, collect the key fields only.
224 /// <param name="possibleType">the <paramref name="member"/>'s type or one of its subtypes</param>
225 private static void GatherSignatureFromTypeStructuralMembers(MemberProjectionIndex index,
226 EdmItemCollection edmItemCollection,
228 StructuralType possibleType,
231 // For each child member of this type, collect all the relevant scalar fields
232 foreach (EdmMember structuralMember in Helper.GetAllStructuralMembers(possibleType))
234 if (MetadataHelper.IsNonRefSimpleMember(structuralMember))
236 if (!needKeysOnly || MetadataHelper.IsPartOfEntityTypeKey(structuralMember))
238 MemberPath nonStructuredMember = new MemberPath(member, structuralMember);
239 // Note: scalarMember's parent has already been added to the projectedSlotMap
240 index.CreateIndex(nonStructuredMember);
245 Debug.Assert(structuralMember.TypeUsage.EdmType is ComplexType ||
246 structuralMember.TypeUsage.EdmType is RefType, // for association ends
247 "Only non-scalars expected - complex types, association ends");
251 MemberPath structuredMember = new MemberPath(member, structuralMember);
252 GatherPartialSignature(index,
255 // Only keys are required for entities referenced by association ends of an association.
256 needKeysOnly || Helper.IsAssociationEndMember(structuralMember));