1
- // Copyright (C) 2003-2010 Xtensive LLC.
2
- // All rights reserved .
3
- // For conditions of distribution and use, see license .
1
+ // Copyright (C) 2009-2020 Xtensive LLC.
2
+ // This code is distributed under MIT license terms .
3
+ // See the License.txt file in the project root for more information .
4
4
// Created by: Alexander Nikolaev
5
5
// Created: 2009.09.09
6
6
@@ -28,35 +28,33 @@ private struct CacheKey : IEquatable<CacheKey>
28
28
{
29
29
public readonly FieldInfo ReferencingField ;
30
30
public readonly int ? ItemCountLimit ;
31
- private int cachedHashCode ;
31
+ private readonly int cachedHashCode ;
32
32
33
33
public bool Equals ( CacheKey other )
34
34
{
35
- return ( ItemCountLimit == null ) == ( other . ItemCountLimit == null )
35
+ return ( ItemCountLimit == null ) == ( other . ItemCountLimit == null )
36
36
&& Equals ( other . ReferencingField , ReferencingField ) ;
37
37
}
38
38
39
39
public override bool Equals ( object obj )
40
40
{
41
- if ( ReferenceEquals ( null , obj ) )
41
+ if ( ReferenceEquals ( null , obj ) ) {
42
42
return false ;
43
- if ( obj . GetType ( ) != typeof ( CacheKey ) )
43
+ }
44
+ if ( obj . GetType ( ) != typeof ( CacheKey ) ) {
44
45
return false ;
46
+ }
45
47
return Equals ( ( CacheKey ) obj ) ;
46
48
}
47
49
48
- public override int GetHashCode ( )
49
- {
50
- return cachedHashCode ;
51
- }
52
-
50
+ public override int GetHashCode ( ) => cachedHashCode ;
53
51
54
52
// Constructors
55
53
56
54
public CacheKey ( FieldInfo referencingField , int ? itemCountLimit )
57
55
{
58
- this . ReferencingField = referencingField ;
59
- this . ItemCountLimit = itemCountLimit ;
56
+ ReferencingField = referencingField ;
57
+ ItemCountLimit = itemCountLimit ;
60
58
unchecked {
61
59
cachedHashCode = ( ReferencingField . GetHashCode ( ) * 397 )
62
60
^ ( ItemCountLimit . HasValue ? 1 : 0 ) ;
@@ -69,16 +67,15 @@ public CacheKey(FieldInfo referencingField, int? itemCountLimit)
69
67
private static readonly object itemsQueryCachingRegion = new object ( ) ;
70
68
private static readonly Parameter < Tuple > ownerParameter = new Parameter < Tuple > ( WellKnown . KeyFieldName ) ;
71
69
private static readonly Parameter < int > itemCountLimitParameter = new Parameter < int > ( "ItemCountLimit" ) ;
72
- private static readonly MethodInfo getValueMethodDefinition = typeof ( Tuple )
73
- . GetMethods ( BindingFlags . Public | BindingFlags . Instance )
74
- . Where ( method => method . Name == "GetValue" && method . GetParameters ( ) . Length == 1
75
- && method . IsGenericMethodDefinition ) . Single ( ) ;
70
+ // private static readonly MethodInfo getValueMethodDefinition = typeof (Tuple)
71
+ // .GetMethods(BindingFlags.Public | BindingFlags.Instance)
72
+ // .Where(method => method.Name=="GetValue" && method.GetParameters().Length == 1
73
+ // && method.IsGenericMethodDefinition).Single();
76
74
77
75
private readonly Key ownerKey ;
78
76
private readonly bool isOwnerCached ;
79
77
private readonly PrefetchManager manager ;
80
78
private QueryTask itemsQueryTask ;
81
- private int ? cachedHashCode ;
82
79
private readonly PrefetchFieldDescriptor referencingFieldDescriptor ;
83
80
private readonly CacheKey cacheKey ;
84
81
@@ -90,80 +87,96 @@ public CacheKey(FieldInfo referencingField, int? itemCountLimit)
90
87
91
88
public void RegisterQueryTask ( )
92
89
{
93
- EntitySetState state ;
94
- if ( isOwnerCached && manager . Owner . LookupState ( ownerKey , ReferencingField , out state ) )
95
- if ( state == null || state . IsFullyLoaded )
90
+ if ( isOwnerCached && manager . Owner . LookupState ( ownerKey , ReferencingField , out var state ) ) {
91
+ if ( state == null || ( state . IsFullyLoaded && ! state . ShouldUseForcePrefetch ( referencingFieldDescriptor . PrefetchOperationId ) ) ) {
96
92
return ;
93
+ }
94
+ }
95
+
97
96
itemsQueryTask = CreateQueryTask ( ) ;
98
97
manager . Owner . Session . RegisterInternalDelayedQuery ( itemsQueryTask ) ;
99
98
}
100
99
101
100
public void UpdateCache ( )
102
101
{
103
- if ( itemsQueryTask == null )
102
+ if ( itemsQueryTask == null ) {
104
103
return ;
104
+ }
105
+
105
106
var areToNotifyAboutKeys = ! manager . Owner . Session . Domain . Model
106
107
. Types [ referencingFieldDescriptor . Field . ItemType ] . IsLeaf ;
107
108
var reader = manager . Owner . Session . Domain . RecordSetReader ;
108
109
var records = reader . Read ( itemsQueryTask . Result , QueryProvider . Header , manager . Owner . Session ) ;
109
110
var entityKeys = new List < Key > ( itemsQueryTask . Result . Count ) ;
110
- List < Pair < Key , Tuple > > auxEntities = null ;
111
111
var association = ReferencingField . Associations . Last ( ) ;
112
- if ( association . AuxiliaryType != null )
113
- auxEntities = new List < Pair < Key , Tuple > > ( itemsQueryTask . Result . Count ) ;
112
+ var auxEntities = ( association . AuxiliaryType != null )
113
+ ? new List < Pair < Key , Tuple > > ( itemsQueryTask . Result . Count )
114
+ : null ;
115
+
114
116
foreach ( var record in records ) {
115
- for ( int i = 0 ; i < record . Count ; i ++ ) {
117
+ for ( var i = 0 ; i < record . Count ; i ++ ) {
116
118
var key = record . GetKey ( i ) ;
117
- if ( key == null )
119
+ if ( key == null ) {
118
120
continue ;
121
+ }
119
122
var tuple = record . GetTuple ( i ) ;
120
- if ( tuple == null )
123
+ if ( tuple == null ) {
121
124
continue ;
122
- if ( association . AuxiliaryType != null )
123
- if ( i == 0 )
125
+ }
126
+ if ( association . AuxiliaryType != null ) {
127
+ if ( i == 0 ) {
124
128
auxEntities . Add ( new Pair < Key , Tuple > ( key , tuple ) ) ;
129
+ }
125
130
else {
126
131
manager . SaveStrongReference ( manager . Owner . UpdateState ( key , tuple ) ) ;
127
132
entityKeys . Add ( key ) ;
128
- if ( areToNotifyAboutKeys )
133
+ if ( areToNotifyAboutKeys ) {
129
134
referencingFieldDescriptor . NotifySubscriber ( ownerKey , key ) ;
135
+ }
130
136
}
137
+ }
131
138
else {
132
139
manager . SaveStrongReference ( manager . Owner . UpdateState ( key , tuple ) ) ;
133
140
entityKeys . Add ( key ) ;
134
- if ( areToNotifyAboutKeys )
141
+ if ( areToNotifyAboutKeys ) {
135
142
referencingFieldDescriptor . NotifySubscriber ( ownerKey , key ) ;
143
+ }
136
144
}
137
145
}
138
146
}
139
- manager . Owner . UpdateState ( ownerKey , ReferencingField ,
140
- ItemCountLimit == null || entityKeys . Count < ItemCountLimit , entityKeys , auxEntities ) ;
147
+ var updatedState = manager . Owner . UpdateState ( ownerKey , ReferencingField ,
148
+ ItemCountLimit == null || entityKeys . Count < ItemCountLimit , entityKeys , auxEntities ) ;
149
+ if ( updatedState != null ) {
150
+ updatedState . SetLastManualPrefetchId ( referencingFieldDescriptor . PrefetchOperationId ) ;
151
+ }
141
152
}
142
153
143
154
public bool Equals ( EntitySetTask other )
144
155
{
145
- if ( ReferenceEquals ( null , other ) )
156
+ if ( ReferenceEquals ( null , other ) ) {
146
157
return false ;
147
- if ( ReferenceEquals ( this , other ) )
158
+ }
159
+ if ( ReferenceEquals ( this , other ) ) {
148
160
return true ;
161
+ }
149
162
return other . cacheKey . Equals ( cacheKey ) ;
150
163
}
151
164
152
165
public override bool Equals ( object obj )
153
166
{
154
- if ( ReferenceEquals ( null , obj ) )
167
+ if ( ReferenceEquals ( null , obj ) ) {
155
168
return false ;
156
- if ( ReferenceEquals ( this , obj ) )
169
+ }
170
+ if ( ReferenceEquals ( this , obj ) ) {
157
171
return true ;
158
- if ( obj . GetType ( ) != typeof ( EntitySetTask ) )
172
+ }
173
+ if ( obj . GetType ( ) != typeof ( EntitySetTask ) ) {
159
174
return false ;
175
+ }
160
176
return Equals ( ( EntitySetTask ) obj ) ;
161
177
}
162
178
163
- public override int GetHashCode ( )
164
- {
165
- return cacheKey . GetHashCode ( ) ;
166
- }
179
+ public override int GetHashCode ( ) => cacheKey . GetHashCode ( ) ;
167
180
168
181
#region Private / internal methods
169
182
@@ -172,8 +185,9 @@ private QueryTask CreateQueryTask()
172
185
var parameterContext = new ParameterContext ( ) ;
173
186
using ( parameterContext . Activate ( ) ) {
174
187
ownerParameter . Value = ownerKey . Value ;
175
- if ( ItemCountLimit != null )
188
+ if ( ItemCountLimit != null ) {
176
189
itemCountLimitParameter . Value = ItemCountLimit . Value ;
190
+ }
177
191
object key = new Pair < object , CacheKey > ( itemsQueryCachingRegion , cacheKey ) ;
178
192
Func < object , object > generator = CreateRecordSetLoadingItems ;
179
193
var session = manager . Owner . Session ;
@@ -190,14 +204,13 @@ private static CompilableProvider CreateRecordSetLoadingItems(object cachingKey)
190
204
var primaryTargetIndex = association . TargetType . Indexes . PrimaryIndex ;
191
205
var resultColumns = new List < int > ( primaryTargetIndex . Columns . Count ) ;
192
206
ParameterExpression tupleParameter ;
193
- CompilableProvider result ;
194
- if ( association . AuxiliaryType == null )
195
- result = CreateQueryForDirectAssociation ( pair , primaryTargetIndex , resultColumns ) ;
196
- else
197
- result = CreateQueryForAssociationViaAuxType ( pair , primaryTargetIndex , resultColumns ) ;
207
+ var result = association . AuxiliaryType == null
208
+ ? CreateQueryForDirectAssociation ( pair , primaryTargetIndex , resultColumns )
209
+ : CreateQueryForAssociationViaAuxType ( pair , primaryTargetIndex , resultColumns ) ;
198
210
result = result . Select ( resultColumns . ToArray ( ) ) ;
199
- if ( pair . Second . ItemCountLimit != null )
211
+ if ( pair . Second . ItemCountLimit != null ) {
200
212
result = result . Take ( ( ) => itemCountLimitParameter . Value ) ;
213
+ }
201
214
return result ;
202
215
}
203
216
@@ -236,26 +249,31 @@ private static CompilableProvider CreateQueryForDirectAssociation(Pair<object, C
236
249
private static void AddResultColumnIndexes ( ICollection < int > indexes , IndexInfo index ,
237
250
int columnIndexOffset )
238
251
{
239
- for ( int i = 0 ; i < index . Columns . Count ; i ++ ) {
252
+ for ( var i = 0 ; i < index . Columns . Count ; i ++ ) {
240
253
var column = index . Columns [ i ] ;
241
- if ( PrefetchHelper . IsFieldToBeLoadedByDefault ( column . Field ) )
254
+ if ( PrefetchHelper . IsFieldToBeLoadedByDefault ( column . Field ) ) {
242
255
indexes . Add ( i + columnIndexOffset ) ;
256
+ }
243
257
}
244
258
}
245
259
246
260
private static Pair < int > [ ] GetJoiningColumnIndexes ( IndexInfo primaryIndex , IndexInfo associationIndex , bool hasAuxType )
247
261
{
248
262
var joiningColumns = new Pair < int > [ primaryIndex . KeyColumns . Count ] ;
249
263
var firstColumnIndex = primaryIndex . Columns . IndexOf ( primaryIndex . KeyColumns [ 0 ] . Key ) ;
250
- for ( int i = 0 ; i < joiningColumns . Length ; i ++ )
251
- if ( hasAuxType )
264
+ for ( var i = 0 ; i < joiningColumns . Length ; i ++ ) {
265
+ if ( hasAuxType ) {
252
266
joiningColumns [ i ] =
253
267
new Pair < int > ( associationIndex . Columns . IndexOf ( associationIndex . ValueColumns [ i ] ) ,
254
268
firstColumnIndex + i ) ;
255
- else
269
+ }
270
+ else {
256
271
joiningColumns [ i ] =
257
272
new Pair < int > ( associationIndex . Columns . IndexOf ( primaryIndex . KeyColumns [ i ] . Key ) ,
258
273
firstColumnIndex + i ) ;
274
+ }
275
+ }
276
+
259
277
return joiningColumns ;
260
278
}
261
279
0 commit comments