DynamicWhere.ex
DynamicWhere.exv3.4.0·docs

.ToListAsyncDynamic<T>(Filter)

Async version of .ToListDynamic<T>(Filter). Counts with EF Core's CountAsync() and reads with EF Core's own ToListAsync(). Since 3.2.0 two more overloads take a CancellationToken, which reaches both.

Signature

public static Task<FilterResult<dynamic>> ToListAsyncDynamic<T>(
    this IQueryable<T> query,
    Filter filter,
    bool getQueryString = false)
    where T : class

// 3.2.0
public static Task<FilterResult<dynamic>> ToListAsyncDynamic<T>(
    this IQueryable<T> query,
    Filter filter,
    CancellationToken cancellationToken)
    where T : class

public static Task<FilterResult<dynamic>> ToListAsyncDynamic<T>(
    this IQueryable<T> query,
    Filter filter,
    bool getQueryString,
    CancellationToken cancellationToken)
    where T : class
ParameterTypeDefaultDescription
filterFilter–Composition object
getQueryStringboolfalseWhen true, captures the generated SQL on QueryString
cancellationTokenCancellationToken–Cancels the count and the read. The overload without it passes CancellationToken.None

Pipeline

  • Where applied on the typed query.
  • CountAsync(cancellationToken) on the typed query → TotalCount.
  • Order applied on the typed query.
  • Page applied on the typed query.
  • SelectDynamic projection applied last.
  • EF Core's ToListAsync(cancellationToken) materializes the result, called for the query's element type: the class the projection generates, or T when Selects is null.
Changed in 3.2.0: the read goes through EF Core
The read used to run Dynamic LINQ's ToDynamicListAsync(), asynchronous as well but with no token to pass on. On an EF Core query it now runs through EF Core's ToListAsync(), so a canceled token reaches the database. The rows are the same. Only the count needs an EF Core async provider; on any other provider the read falls back to Dynamic LINQ's.
Warning
Ordering and pagination are applied on the strongly-typed IQueryable<T> before the dynamic projection so that field names referenced in orders always resolve against the original entity type T.
Note
Property names in the dynamic result follow SelectDynamic rules — see that page for the full set of access patterns through nested dynamic objects and collections.

Cancellation

The two overloads that take a CancellationToken are new in 3.2.0. The token reaches the count and the read, so a canceled token stops whichever of the two is running, and the call throws OperationCanceledException. EF Core's TaskCanceledException derives from it. The overload without a token passes CancellationToken.None.

They are overloads, not an optional parameter added to the old signature. The 3.1 signature is unchanged, so code compiled against 3.1 still binds. The guarded handle that ApplyPolicy returns has the same overloads.

ToListAsyncDynamic(filter, default) does not compile
default fits both bool getQueryString and CancellationToken, so the compiler reports the call as ambiguous (CS0121). Write false, a token, or a named argument.
await db.Products.ToListAsyncDynamic(filter, default);                   // CS0121: ambiguous
await db.Products.ToListAsyncDynamic(filter, cancellationToken);         // the token overload
await db.Products.ToListAsyncDynamic(filter, true, cancellationToken);   // the SQL and a token

Returns

Task<FilterResult<dynamic>>.

Example

FilterResult<dynamic> result = await dbContext.Products.ToListAsyncDynamic(filter);

foreach (var p in result.Data)
{
    Console.WriteLine($"{p.Name} — {p.Category.Name}");
}
var result = await dbContext.Products.ToListAsyncDynamic(filter, getQueryString: true);
Console.WriteLine(result.QueryString);
{
  "pageNumber": 1,
  "pageSize": 10,
  "pageCount": 5,
  "totalCount": 42,
  "data": [
    { "Id": 7, "Name": "Laptop Pro", "Price": 1299.99, "Category": { "Name": "Electronics" } }
  ],
  "queryString": null
}

See also