1 //---------------------------------------------------------------------
2 // <copyright file="SpanIndex.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;
11 using System.Collections.Generic;
12 using System.Diagnostics;
13 using System.Data.Common;
14 using System.Data.Common.Utils;
15 using System.Data.Metadata.Edm;
16 using System.Data.Common.CommandTrees;
17 
18 namespace System.Data.Objects.Internal
19 {
20     /// <summary>
21     /// An index containing information about how the query was spanned
22     /// This helps to determine how to materialize the query result
23     /// </summary>
24     internal sealed class SpanIndex
25     {
26         #region Nested types
27 
28         /// <summary>
29         /// Helper class to compare two RowTypes using EdmEquals instead of reference equality.
30         /// </summary>
31         sealed private class RowTypeEqualityComparer : IEqualityComparer<RowType>
32         {
RowTypeEqualityComparer()33             private RowTypeEqualityComparer() { }
34             internal static readonly RowTypeEqualityComparer Instance = new RowTypeEqualityComparer();
35 
36             #region IEqualityComparer<RowType> Members
37 
Equals(RowType x, RowType y)38             public bool Equals(RowType x, RowType y)
39             {
40                 if (x == null || y == null)
41                 {
42                     return false;
43                 }
44 
45                 return x.EdmEquals(y);
46             }
47 
GetHashCode(RowType obj)48             public int GetHashCode(RowType obj)
49             {
50                 return obj.Identity.GetHashCode();
51             }
52 
53             #endregion
54         }
55         #endregion
56 
57         // When a query is spanned, the result is always a RowType
58         // The _spanMap index maps RowTypes that are a span result to a map between
59         // column ordinal and end member metadata of the type that is spanned
60         private Dictionary<RowType, Dictionary<int, AssociationEndMember>> _spanMap;
61 
62         // A map from a spanned RowType (or parent RowType) to the original TypeUsage prior
63         // to the query being rewritten
64         private Dictionary<RowType, TypeUsage> _rowMap;
65 
SpanIndex()66         internal SpanIndex()
67         {
68         }
69 
AddSpannedRowType(RowType spannedRowType, TypeUsage originalRowType)70         internal void AddSpannedRowType(RowType spannedRowType, TypeUsage originalRowType)
71         {
72             Debug.Assert(spannedRowType != null, "Spanned RowType cannot be null");
73             Debug.Assert(originalRowType != null, "Original RowType cannot be null");
74             Debug.Assert(originalRowType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType, "Original RowType must be a RowType");
75 
76             if (null == _rowMap)
77             {
78                 _rowMap = new Dictionary<RowType, TypeUsage>(RowTypeEqualityComparer.Instance);
79             }
80 
81             _rowMap[spannedRowType] = originalRowType;
82         }
83 
GetSpannedRowType(RowType spannedRowType)84         internal TypeUsage GetSpannedRowType(RowType spannedRowType)
85         {
86             TypeUsage retType;
87             if (_rowMap != null && _rowMap.TryGetValue(spannedRowType, out retType))
88             {
89                 return retType;
90             }
91             return null;
92         }
93 
HasSpanMap(RowType spanRowType)94         internal bool HasSpanMap(RowType spanRowType)
95         {
96             Debug.Assert(spanRowType != null, "Span RowType cannot be null");
97             if (null == _spanMap)
98             {
99                 return false;
100             }
101 
102             return _spanMap.ContainsKey(spanRowType);
103         }
104 
AddSpanMap(RowType rowType, Dictionary<int, AssociationEndMember> columnMap)105         internal void AddSpanMap(RowType rowType, Dictionary<int, AssociationEndMember> columnMap)
106         {
107             Debug.Assert(rowType != null, "Span row type cannot be null");
108             Debug.Assert(columnMap != null, "Span column map cannot be null");
109 
110             if (null == _spanMap)
111             {
112                 _spanMap = new Dictionary<RowType, Dictionary<int, AssociationEndMember>>(RowTypeEqualityComparer.Instance);
113             }
114 
115             _spanMap[rowType] = columnMap;
116         }
117 
GetSpanMap(RowType rowType)118         internal Dictionary<int, AssociationEndMember> GetSpanMap(RowType rowType)
119         {
120             Dictionary<int, AssociationEndMember> retMap = null;
121             if (_spanMap != null && _spanMap.TryGetValue(rowType, out retMap))
122             {
123                 return retMap;
124             }
125 
126             return null;
127         }
128     }
129 }
130