@@ -197,7 +197,8 @@ string resourceType
197197 IQueryable < T > filteredQuery = ApplyFiltersAndIncludes (
198198 queryable ,
199199 parameters ,
200- mappedIncludes
200+ mappedIncludes ,
201+ paginating : parameters . Pagination != null
201202 ) ;
202203
203204 if ( parameters . Sort ? . Count > 0 )
@@ -280,53 +281,15 @@ protected async Task<JsonApiQueryResult<T>> BuildJsonApiQueryAsync<T>(
280281 parameters . Include
281282 ) ;
282283
283- if ( parameters . Include ? . Count > 0 && mappedIncludes . Count == 0 )
284- {
285- Logger . LogWarning (
286- "No valid includes for {EntityType}. Requested: {Includes}" ,
287- typeof ( T ) . Name ,
288- string . Join ( ", " , parameters . Include )
289- ) ;
290- }
284+ LogInvalidIncludes < T > ( parameters , mappedIncludes ) ;
291285
292- var ( mainFilters , includeFilters ) = IncludeFilterParser . SeparateIncludeFilters (
293- parameters . Filter ,
294- parameters . Include
286+ IQueryable < T > processedQuery = ApplyFiltersAndIncludes (
287+ queryable ,
288+ parameters ,
289+ mappedIncludes ,
290+ paginating : false
295291 ) ;
296292
297- IQueryable < T > processedQuery = queryable ;
298-
299- // Apply main entity filters
300- if ( mainFilters != null )
301- processedQuery = processedQuery . ApplyFilters ( mainFilters , Logger ) ;
302-
303- // Apply includes (with or without filters)
304- if ( includeFilters . Count > 0 )
305- {
306- Logger . LogDebug (
307- "Applying {FilterCount} filtered includes for {EntityType}" ,
308- includeFilters . Count ,
309- typeof ( T ) . Name
310- ) ;
311- processedQuery = processedQuery . ApplyFilteredIncludes (
312- mappedIncludes ,
313- includeFilters ,
314- Logger
315- ) ;
316- }
317- else if ( mappedIncludes . Count > 0 )
318- {
319- // Use standard includes (no pagination optimization needed since we're not paginating)
320- processedQuery = processedQuery . ApplyIncludes ( mappedIncludes ) ;
321-
322- Logger . LogDebug (
323- "Applied {IncludeCount} includes for {EntityType}" ,
324- mappedIncludes . Count ,
325- typeof ( T ) . Name
326- ) ;
327- }
328-
329- // Apply sorting
330293 if ( parameters . Sort ? . Count > 0 )
331294 processedQuery = processedQuery . ApplySorting ( parameters . Sort , Logger ) ;
332295
@@ -435,20 +398,17 @@ private void LogQueryParameters<T>(QueryParameters parameters, List<string> mapp
435398 ) ;
436399 }
437400
438- if ( parameters . Include ? . Count > 0 && mappedIncludes . Count == 0 )
439- {
440- Logger . LogWarning (
441- "No valid includes for {EntityType}. Requested: {Includes}" ,
442- typeof ( T ) . Name ,
443- string . Join ( ", " , parameters . Include )
444- ) ;
445- }
401+ LogInvalidIncludes < T > ( parameters , mappedIncludes ) ;
446402 }
447403
404+ // When `paginating` is true, includes use single-query mode to avoid the
405+ // EF Core warning/exception triggered by split-query + Skip/Take. Otherwise
406+ // split-query is preferred to avoid cartesian explosion on collection includes.
448407 private IQueryable < T > ApplyFiltersAndIncludes < T > (
449408 IQueryable < T > queryable ,
450409 QueryParameters parameters ,
451- List < string > mappedIncludes
410+ List < string > mappedIncludes ,
411+ bool paginating
452412 )
453413 where T : class
454414 {
@@ -477,22 +437,33 @@ List<string> mappedIncludes
477437 }
478438 else if ( mappedIncludes . Count > 0 )
479439 {
480- filteredQuery =
481- parameters . Pagination != null
482- ? filteredQuery . ApplyIncludesSingleQuery ( mappedIncludes )
483- : filteredQuery . ApplyIncludes ( mappedIncludes ) ;
440+ filteredQuery = paginating
441+ ? filteredQuery . ApplyIncludesSingleQuery ( mappedIncludes )
442+ : filteredQuery . ApplyIncludes ( mappedIncludes ) ;
484443
485444 Logger . LogDebug (
486445 "Applied {IncludeCount} includes for {EntityType} using {QueryType}" ,
487446 mappedIncludes . Count ,
488447 typeof ( T ) . Name ,
489- parameters . Pagination != null ? "SingleQuery" : "SplitQuery"
448+ paginating ? "SingleQuery" : "SplitQuery"
490449 ) ;
491450 }
492451
493452 return filteredQuery ;
494453 }
495454
455+ private void LogInvalidIncludes < T > ( QueryParameters parameters , List < string > mappedIncludes )
456+ {
457+ if ( parameters . Include ? . Count > 0 && mappedIncludes . Count == 0 )
458+ {
459+ Logger . LogWarning (
460+ "No valid includes for {EntityType}. Requested: {Includes}" ,
461+ typeof ( T ) . Name ,
462+ string . Join ( ", " , parameters . Include )
463+ ) ;
464+ }
465+ }
466+
496467 private static void EnforceStrictPagination (
497468 JsonApiOptions options ,
498469 QueryParameters parameters ,
0 commit comments