@@ -213,6 +213,351 @@ public async Task MultipleGetReadOnlyCollectionTestAsync()
213213 }
214214 }
215215
216+ [ Test ]
217+ public async Task GetManyReadWriteTestAsync ( )
218+ {
219+ var persister = Sfi . GetEntityPersister ( typeof ( ReadWrite ) . FullName ) ;
220+ Assert . That ( persister . Cache . Cache , Is . Not . Null ) ;
221+ Assert . That ( persister . Cache . Cache , Is . TypeOf < BatchableCache > ( ) ) ;
222+ int [ ] getIds ;
223+ int [ ] loadIds ;
224+
225+ using ( var s = Sfi . OpenSession ( ) )
226+ using ( var tx = s . BeginTransaction ( ) )
227+ {
228+ var items = await ( s . Query < ReadWrite > ( ) . ToListAsync ( ) ) ;
229+ loadIds = getIds = items . OrderBy ( o => o . Id ) . Select ( o => o . Id ) . ToArray ( ) ;
230+ await ( tx . CommitAsync ( ) ) ;
231+ }
232+
233+ // Batch size 3
234+ var parentTestCases = new List < Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > >
235+ {
236+ // When the cache is empty, GetMany will be called three times. First time in type
237+ // DefaultLoadEventListener, the second time in BatchingEntityLoader and third in ReadWriteCache.
238+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
239+ loadIds ,
240+ 0 ,
241+ new [ ]
242+ {
243+ new [ ] { 0 , 1 , 2 } , // Triggered by LoadFromSecondLevelCache method of DefaultLoadEventListener type
244+ new [ ] { 1 , 2 , 3 } , // Triggered by Load method of BatchingEntityLoader type
245+ new [ ] { 0 , 1 , 2 } // Triggered by PutMany method of ReadWriteCache type
246+ } ,
247+ new [ ] { 0 , 1 , 2 } ,
248+ null
249+ ) ,
250+ // When there are not enough uninitialized entities after the demanded one to fill the batch,
251+ // the nearest before the demanded entity are added.
252+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
253+ loadIds ,
254+ 4 ,
255+ new [ ]
256+ {
257+ new [ ] { 4 , 5 , 3 } ,
258+ new [ ] { 5 , 3 , 2 } ,
259+ new [ ] { 4 , 5 , 3 } ,
260+ } ,
261+ new [ ] { 3 , 4 , 5 } ,
262+ null
263+ ) ,
264+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
265+ loadIds ,
266+ 5 ,
267+ new [ ]
268+ {
269+ new [ ] { 5 , 4 , 3 } ,
270+ new [ ] { 4 , 3 , 2 } ,
271+ new [ ] { 5 , 4 , 3 } ,
272+ } ,
273+ new [ ] { 3 , 4 , 5 } ,
274+ null
275+ ) ,
276+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
277+ loadIds ,
278+ 0 ,
279+ new [ ]
280+ {
281+ new [ ] { 0 , 1 , 2 } // 0 get assembled and no further processing is done
282+ } ,
283+ null ,
284+ ( i ) => i % 2 == 0 // Cache all even indexes before loading
285+ ) ,
286+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
287+ loadIds ,
288+ 1 ,
289+ new [ ]
290+ {
291+ new [ ] { 1 , 2 , 3 } , // 2 gets assembled inside LoadFromSecondLevelCache
292+ new [ ] { 3 , 4 , 5 } ,
293+ new [ ] { 1 , 3 , 5 }
294+ } ,
295+ new [ ] { 1 , 3 , 5 } ,
296+ ( i ) => i % 2 == 0
297+ ) ,
298+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
299+ loadIds ,
300+ 5 ,
301+ new [ ]
302+ {
303+ new [ ] { 5 , 4 , 3 } , // 4 gets assembled inside LoadFromSecondLevelCache
304+ new [ ] { 3 , 2 , 1 } ,
305+ new [ ] { 1 , 3 , 5 }
306+ } ,
307+ new [ ] { 1 , 3 , 5 } ,
308+ ( i ) => i % 2 == 0
309+ ) ,
310+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
311+ loadIds ,
312+ 0 ,
313+ new [ ]
314+ {
315+ new [ ] { 0 , 1 , 2 } , // 1 gets assembled inside LoadFromSecondLevelCache
316+ new [ ] { 2 , 3 , 4 } ,
317+ new [ ] { 0 , 2 , 4 }
318+ } ,
319+ new [ ] { 0 , 2 , 4 } ,
320+ ( i ) => i % 2 != 0
321+ ) ,
322+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
323+ loadIds ,
324+ 4 ,
325+ new [ ]
326+ {
327+ new [ ] { 4 , 5 , 3 } , // 5 and 3 get assembled inside LoadFromSecondLevelCache
328+ new [ ] { 2 , 1 , 0 } ,
329+ new [ ] { 0 , 2 , 4 }
330+ } ,
331+ new [ ] { 0 , 2 , 4 } ,
332+ ( i ) => i % 2 != 0
333+ ) ,
334+ // Tests by loading different ids
335+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
336+ loadIds . Where ( ( v , i ) => i != 0 ) . ToArray ( ) ,
337+ 0 ,
338+ new [ ]
339+ {
340+ new [ ] { 0 , 5 , 4 } , // Triggered by LoadFromSecondLevelCache method of DefaultLoadEventListener type
341+ new [ ] { 3 , 4 , 5 } , // Triggered by Load method of BatchingEntityLoader type
342+ new [ ] { 0 , 4 , 5 } , // Triggered by PutMany method of ReadWriteCache type
343+ } ,
344+ new [ ] { 0 , 4 , 5 } ,
345+ null
346+ ) ,
347+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
348+ loadIds . Where ( ( v , i ) => i != 4 ) . ToArray ( ) ,
349+ 4 ,
350+ new [ ]
351+ {
352+ new [ ] { 4 , 5 , 3 } ,
353+ new [ ] { 5 , 3 , 2 } ,
354+ new [ ] { 3 , 4 , 5 }
355+ } ,
356+ new [ ] { 3 , 4 , 5 } ,
357+ null
358+ ) ,
359+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
360+ loadIds . Where ( ( v , i ) => i != 0 ) . ToArray ( ) ,
361+ 0 ,
362+ new [ ]
363+ {
364+ new [ ] { 0 , 5 , 4 } // 0 get assembled and no further processing is done
365+ } ,
366+ null ,
367+ ( i ) => i % 2 == 0 // Cache all even indexes before loading
368+ ) ,
369+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
370+ loadIds . Where ( ( v , i ) => i != 1 ) . ToArray ( ) ,
371+ 1 ,
372+ new [ ]
373+ {
374+ new [ ] { 1 , 5 , 4 } , // 4 gets assembled inside LoadFromSecondLevelCache
375+ new [ ] { 5 , 3 , 2 } ,
376+ new [ ] { 1 , 3 , 5 }
377+ } ,
378+ new [ ] { 1 , 3 , 5 } ,
379+ ( i ) => i % 2 == 0
380+ )
381+ } ;
382+
383+ foreach ( var tuple in parentTestCases )
384+ {
385+ await ( AssertMultipleCacheCallsAsync < ReadWrite > ( tuple . Item1 , getIds , tuple . Item2 , tuple . Item3 , tuple . Item4 , tuple . Item5 ) ) ;
386+ }
387+ }
388+
389+ [ Test ]
390+ public async Task GetManyReadWriteItemTestAsync ( )
391+ {
392+ var persister = Sfi . GetEntityPersister ( typeof ( ReadWriteItem ) . FullName ) ;
393+ Assert . That ( persister . Cache . Cache , Is . Not . Null ) ;
394+ Assert . That ( persister . Cache . Cache , Is . TypeOf < BatchableCache > ( ) ) ;
395+ int [ ] getIds ;
396+ int [ ] loadIds ;
397+
398+ using ( var s = Sfi . OpenSession ( ) )
399+ using ( var tx = s . BeginTransaction ( ) )
400+ {
401+ var items = await ( s . Query < ReadWriteItem > ( ) . Take ( 6 ) . ToListAsync ( ) ) ;
402+ loadIds = getIds = items . OrderBy ( o => o . Id ) . Select ( o => o . Id ) . ToArray ( ) ;
403+ await ( tx . CommitAsync ( ) ) ;
404+ }
405+ // Batch size 4
406+ var parentTestCases = new List < Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > >
407+ {
408+ // When the cache is empty, GetMany will be called three times. First time in type
409+ // DefaultLoadEventListener, the second time in BatchingEntityLoader and third in ReadWriteCache.
410+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
411+ loadIds ,
412+ 0 ,
413+ new [ ]
414+ {
415+ new [ ] { 0 , 1 , 2 , 3 } , // Triggered by LoadFromSecondLevelCache method of DefaultLoadEventListener type
416+ new [ ] { 1 , 2 , 3 , 4 } , // Triggered by Load method of BatchingEntityLoader type
417+ new [ ] { 0 , 1 , 2 , 3 } // Triggered by PutMany method of ReadWriteCache type
418+ } ,
419+ new [ ] { 0 , 1 , 2 , 3 } ,
420+ null
421+ ) ,
422+ // When there are not enough uninitialized entities after the demanded one to fill the batch,
423+ // the nearest before the demanded entity are added.
424+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
425+ loadIds ,
426+ 4 ,
427+ new [ ]
428+ {
429+ new [ ] { 4 , 5 , 3 , 2 } ,
430+ new [ ] { 5 , 3 , 2 , 1 } ,
431+ new [ ] { 4 , 5 , 3 , 2 }
432+ } ,
433+ new [ ] { 2 , 3 , 4 , 5 } ,
434+ null
435+ ) ,
436+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
437+ loadIds ,
438+ 5 ,
439+ new [ ]
440+ {
441+ new [ ] { 5 , 4 , 3 , 2 } ,
442+ new [ ] { 4 , 3 , 2 , 1 } ,
443+ new [ ] { 5 , 4 , 3 , 2 }
444+ } ,
445+ new [ ] { 2 , 3 , 4 , 5 } ,
446+ null
447+ ) ,
448+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
449+ loadIds ,
450+ 0 ,
451+ new [ ]
452+ {
453+ new [ ] { 0 , 1 , 2 , 3 } // 0 get assembled and no further processing is done
454+ } ,
455+ null ,
456+ ( i ) => i % 2 == 0 // Cache all even indexes before loading
457+ ) ,
458+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
459+ loadIds ,
460+ 1 ,
461+ new [ ]
462+ {
463+ new [ ] { 1 , 2 , 3 , 4 } , // 2 and 4 get assembled inside LoadFromSecondLevelCache
464+ new [ ] { 3 , 5 , 0 } ,
465+ new [ ] { 1 , 3 , 5 }
466+ } ,
467+ new [ ] { 1 , 3 , 5 } ,
468+ ( i ) => i % 2 == 0
469+ ) ,
470+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
471+ loadIds ,
472+ 5 ,
473+ new [ ]
474+ {
475+ new [ ] { 5 , 4 , 3 , 2 } , // 4 and 2 get assembled inside LoadFromSecondLevelCache
476+ new [ ] { 3 , 1 , 0 } ,
477+ new [ ] { 1 , 3 , 5 }
478+ } ,
479+ new [ ] { 1 , 3 , 5 } ,
480+ ( i ) => i % 2 == 0
481+ ) ,
482+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
483+ loadIds ,
484+ 0 ,
485+ new [ ]
486+ {
487+ new [ ] { 0 , 1 , 2 , 3 } , // 1 and 3 get assembled inside LoadFromSecondLevelCache
488+ new [ ] { 2 , 4 , 5 } ,
489+ new [ ] { 0 , 2 , 4 }
490+ } ,
491+ new [ ] { 0 , 2 , 4 } ,
492+ ( i ) => i % 2 != 0
493+ ) ,
494+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
495+ loadIds ,
496+ 4 ,
497+ new [ ]
498+ {
499+ new [ ] { 4 , 5 , 3 , 2 } , // 5 and 3 get assembled inside LoadFromSecondLevelCache
500+ new [ ] { 2 , 1 , 0 } ,
501+ new [ ] { 0 , 2 , 4 }
502+ } ,
503+ new [ ] { 0 , 2 , 4 } ,
504+ ( i ) => i % 2 != 0
505+ ) ,
506+ // Tests by loading different ids
507+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
508+ loadIds . Where ( ( v , i ) => i != 0 ) . ToArray ( ) ,
509+ 0 ,
510+ new [ ]
511+ {
512+ new [ ] { 0 , 5 , 4 , 3 } , // Triggered by LoadFromSecondLevelCache method of DefaultLoadEventListener type
513+ new [ ] { 5 , 4 , 3 , 2 } , // Triggered by Load method of BatchingEntityLoader type
514+ new [ ] { 0 , 5 , 4 , 3 } , // Triggered by PutMany method of ReadWriteCache type
515+ } ,
516+ new [ ] { 0 , 5 , 4 , 3 } ,
517+ null
518+ ) ,
519+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
520+ loadIds . Where ( ( v , i ) => i != 5 ) . ToArray ( ) ,
521+ 5 ,
522+ new [ ]
523+ {
524+ new [ ] { 5 , 4 , 3 , 2 } ,
525+ new [ ] { 4 , 3 , 2 , 1 } ,
526+ new [ ] { 2 , 3 , 4 , 5 }
527+ } ,
528+ new [ ] { 2 , 3 , 4 , 5 } ,
529+ null
530+ ) ,
531+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
532+ loadIds . Where ( ( v , i ) => i != 0 ) . ToArray ( ) ,
533+ 0 ,
534+ new [ ]
535+ {
536+ new [ ] { 0 , 5 , 4 , 3 } // 0 get assembled and no further processing is done
537+ } ,
538+ null ,
539+ ( i ) => i % 2 == 0 // Cache all even indexes before loading
540+ ) ,
541+ new Tuple < int [ ] , int , int [ ] [ ] , int [ ] , Func < int , bool > > (
542+ loadIds . Where ( ( v , i ) => i != 1 ) . ToArray ( ) ,
543+ 1 ,
544+ new [ ]
545+ {
546+ new [ ] { 1 , 5 , 4 , 3 } , // 4 get assembled inside LoadFromSecondLevelCache
547+ new [ ] { 5 , 3 , 2 , 0 } ,
548+ new [ ] { 1 , 3 , 5 }
549+ } ,
550+ new [ ] { 1 , 3 , 5 } ,
551+ ( i ) => i % 2 == 0
552+ ) ,
553+ } ;
554+
555+ foreach ( var tuple in parentTestCases )
556+ {
557+ await ( AssertMultipleCacheCallsAsync < ReadWriteItem > ( tuple . Item1 , getIds , tuple . Item2 , tuple . Item3 , tuple . Item4 , tuple . Item5 ) ) ;
558+ }
559+ }
560+
216561 [ Test ]
217562 public async Task MultipleGetReadOnlyTestAsync ( )
218563 {
0 commit comments