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