1- // Copyright (C) 2009-2020 Xtensive LLC.
1+ // Copyright (C) 2009-2021 Xtensive LLC.
22// This code is distributed under MIT license terms.
33// See the License.txt file in the project root for more information.
44// Created by: Alexander Nikolaev
1919
2020namespace Xtensive . Orm . Internals . Prefetch
2121{
22- [ Serializable ]
23- internal sealed class EntitySetTask : IEquatable < EntitySetTask >
22+ internal readonly struct ItemsQueryCacheKey : IEquatable < ItemsQueryCacheKey >
2423 {
25- #region Nested classes
24+ public readonly FieldInfo ReferencingField ;
25+ public readonly int ? ItemCountLimit ;
26+ private readonly int cachedHashCode ;
2627
27- private struct CacheKey : IEquatable < CacheKey >
28+ public bool Equals ( ItemsQueryCacheKey other )
2829 {
29- public readonly FieldInfo ReferencingField ;
30- public readonly int ? ItemCountLimit ;
31- private readonly int cachedHashCode ;
32-
33- public bool Equals ( CacheKey other )
34- {
35- return ( ItemCountLimit == null ) == ( other . ItemCountLimit == null )
36- && Equals ( other . ReferencingField , ReferencingField ) ;
37- }
30+ return ( ItemCountLimit == null ) == ( other . ItemCountLimit == null )
31+ && Equals ( other . ReferencingField , ReferencingField ) ;
32+ }
3833
39- public override bool Equals ( object obj ) =>
40- obj is CacheKey other && Equals ( other ) ;
34+ public override bool Equals ( object obj ) =>
35+ obj is ItemsQueryCacheKey other && Equals ( other ) ;
4136
42- public override int GetHashCode ( ) => cachedHashCode ;
37+ public override int GetHashCode ( ) => cachedHashCode ;
4338
44- // Constructors
39+ // Constructors
4540
46- public CacheKey ( FieldInfo referencingField , int ? itemCountLimit )
47- {
48- ReferencingField = referencingField ;
49- ItemCountLimit = itemCountLimit ;
50- unchecked {
51- cachedHashCode = ( ReferencingField . GetHashCode ( ) * 397 )
52- ^ ( ItemCountLimit . HasValue ? 1 : 0 ) ;
53- }
41+ public ItemsQueryCacheKey ( FieldInfo referencingField , int ? itemCountLimit )
42+ {
43+ ReferencingField = referencingField ;
44+ ItemCountLimit = itemCountLimit ;
45+ unchecked {
46+ cachedHashCode = ( ReferencingField . GetHashCode ( ) * 397 )
47+ ^ ( ItemCountLimit . HasValue ? 1 : 0 ) ;
5448 }
5549 }
50+ }
5651
57- #endregion
58-
59- private static readonly object itemsQueryCachingRegion = new object ( ) ;
52+ [ Serializable ]
53+ internal sealed class EntitySetTask : IEquatable < EntitySetTask >
54+ {
6055 private static readonly Parameter < Tuple > ownerParameter = new Parameter < Tuple > ( WellKnown . KeyFieldName ) ;
6156 private static readonly Parameter < int > itemCountLimitParameter = new Parameter < int > ( "ItemCountLimit" ) ;
6257
58+ private static readonly Func < ItemsQueryCacheKey , CompilableProvider > CreateRecordSetLoadingItems = cachingKey => {
59+ var association = cachingKey . ReferencingField . Associations . Last ( ) ;
60+ var primaryTargetIndex = association . TargetType . Indexes . PrimaryIndex ;
61+ var resultColumns = new List < int > ( primaryTargetIndex . Columns . Count ) ;
62+ var result = association . AuxiliaryType == null
63+ ? CreateQueryForDirectAssociation ( cachingKey , primaryTargetIndex , resultColumns )
64+ : CreateQueryForAssociationViaAuxType ( cachingKey , primaryTargetIndex , resultColumns ) ;
65+ result = result . Select ( resultColumns ) ;
66+ if ( cachingKey . ItemCountLimit != null )
67+ result = result . Take ( context => context . GetValue ( itemCountLimitParameter ) ) ;
68+ return result ;
69+ } ;
70+
6371 private readonly Key ownerKey ;
6472 private readonly bool isOwnerCached ;
6573 private readonly PrefetchManager manager ;
6674 private QueryTask itemsQueryTask ;
6775 private readonly PrefetchFieldDescriptor referencingFieldDescriptor ;
68- private readonly CacheKey cacheKey ;
76+ private readonly ItemsQueryCacheKey cacheKey ;
6977
7078 public FieldInfo ReferencingField { get { return referencingFieldDescriptor . Field ; } }
7179
@@ -166,36 +174,19 @@ private QueryTask CreateQueryTask()
166174 parameterContext . SetValue ( itemCountLimitParameter , ItemCountLimit . Value ) ;
167175 }
168176
169- object key = new Pair < object , CacheKey > ( itemsQueryCachingRegion , cacheKey ) ;
170- Func < object , object > generator = CreateRecordSetLoadingItems ;
171177 var session = manager . Owner . Session ;
172178 var scope = new CompiledQueryProcessingScope ( null , null , parameterContext , false ) ;
173- QueryProvider = ( CompilableProvider ) session . StorageNode . InternalQueryCache . GetOrAdd ( key , generator ) ;
179+ QueryProvider = session . StorageNode . EntitySetFetchQueryCache . GetOrAdd ( cacheKey , CreateRecordSetLoadingItems ) ;
174180 ExecutableProvider executableProvider ;
175181 using ( scope . Enter ( ) ) {
176182 executableProvider = session . Compile ( QueryProvider ) ;
177183 }
178184 return new QueryTask ( executableProvider , session . GetLifetimeToken ( ) , parameterContext ) ;
179185 }
180186
181- private static CompilableProvider CreateRecordSetLoadingItems ( object cachingKey )
182- {
183- var pair = ( Pair < object , CacheKey > ) cachingKey ;
184- var association = pair . Second . ReferencingField . Associations . Last ( ) ;
185- var primaryTargetIndex = association . TargetType . Indexes . PrimaryIndex ;
186- var resultColumns = new List < int > ( primaryTargetIndex . Columns . Count ) ;
187- var result = association . AuxiliaryType == null
188- ? CreateQueryForDirectAssociation ( pair , primaryTargetIndex , resultColumns )
189- : CreateQueryForAssociationViaAuxType ( pair , primaryTargetIndex , resultColumns ) ;
190- result = result . Select ( resultColumns ) ;
191- if ( pair . Second . ItemCountLimit != null )
192- result = result . Take ( context => context . GetValue ( itemCountLimitParameter ) ) ;
193- return result ;
194- }
195-
196- private static CompilableProvider CreateQueryForAssociationViaAuxType ( Pair < object , CacheKey > pair , IndexInfo primaryTargetIndex , List < int > resultColumns )
187+ private static CompilableProvider CreateQueryForAssociationViaAuxType ( in ItemsQueryCacheKey cachingKey , IndexInfo primaryTargetIndex , List < int > resultColumns )
197188 {
198- var association = pair . Second . ReferencingField . Associations . Last ( ) ;
189+ var association = cachingKey . ReferencingField . Associations . Last ( ) ;
199190 var associationIndex = association . UnderlyingIndex ;
200191 var joiningColumns = GetJoiningColumnIndexes ( primaryTargetIndex , associationIndex ,
201192 association . AuxiliaryType != null ) ;
@@ -214,10 +205,10 @@ private static CompilableProvider CreateQueryForAssociationViaAuxType(Pair<objec
214205 . Join ( primaryTargetIndex . GetQuery ( ) , joiningColumns ) ;
215206 }
216207
217- private static CompilableProvider CreateQueryForDirectAssociation ( Pair < object , CacheKey > pair , IndexInfo primaryTargetIndex , List < int > resultColumns )
208+ private static CompilableProvider CreateQueryForDirectAssociation ( in ItemsQueryCacheKey cachingKey , IndexInfo primaryTargetIndex , List < int > resultColumns )
218209 {
219210 AddResultColumnIndexes ( resultColumns , primaryTargetIndex , 0 ) ;
220- var association = pair . Second . ReferencingField . Associations . Last ( ) ;
211+ var association = cachingKey . ReferencingField . Associations . Last ( ) ;
221212 var field = association . Reversed . OwnerField ;
222213 var keyColumnTypes = field . Columns . Select ( column => column . ValueType ) . ToList ( ) ;
223214 return primaryTargetIndex
@@ -273,7 +264,7 @@ public EntitySetTask(Key ownerKey, PrefetchFieldDescriptor referencingFieldDescr
273264 this . isOwnerCached = isOwnerCached ;
274265 ItemCountLimit = referencingFieldDescriptor . EntitySetItemCountLimit ;
275266 this . manager = manager ;
276- cacheKey = new CacheKey ( ReferencingField , ItemCountLimit ) ;
267+ cacheKey = new ItemsQueryCacheKey ( ReferencingField , ItemCountLimit ) ;
277268 }
278269 }
279270}
0 commit comments