Linq
Linq has two ways to execute a query:
- Through enumerating the query (if it's a query which returns an IEnumerable)
- Through calling a single-value returning method.
The enumeration of a query is always synchronous in .NET, as it uses
foreach which will call GetEnumerator() on the IQueryable
and this will
execute the query and enumerate the results. As there's no await
possible in foreach(), executing a linq query asynchronously this way is
not possible through foreach.
We have solved this by implementing
ToListAsync, ToArrayAsync and ExecuteAsync extension methods
for IQueryable
which execute the query asynchronously and then return
the values obtained by the query as the result of the method.
To get details about the various methods, please consult the LLBLGen Pro Runtime Library Reference Manual, which is an additional download from the LLBLGen Pro website.
All nested queries inside Linq queries as well as prefetch path definitions are executed asynchronously if the main query is executed asynchronously as well.
The Async methods available.
The following methods have been added to fetch linq queries
asynchronously. They're all IQueryable
extension methods. They follow
the same pattern as with the QuerySpec methods added for Async
programming: there are two overloads per method signature: one which
accepts a CancellationToken and one which calls that overload and passes
CancellationToken.None.
The naming scheme is equal to what's been used in QuerySpec as well: All methods below have the format SynchronousMethodEquivalentAsync. So ToArrayAsync is the asynchronous variant of ToArray, with the same behavior, input and output.
All async methods have to be the last method called on a query. You can't wrap them inside another call in a linq query, as the async methods have to be awaited. Example: (not the same query, but they illustrate the place of the method call)
// Wrong
var q = from c in metaData.Customer
select new { CustomerId=c.CustomerId, Order = c.Orders.FirstAsync()};
// Right
var q = (from c in metaData.Customer
select c).FirstAsync(c=>c.Country=="USA");
IEnumerable returning methods
The following methods have been added to execute an IEnumerable returning Linq query asynchronously. All methods have overloads which accept a CancellationToken.
- ToArrayAsync<TSource>()
- ToListAsync<TSource>()
- ExecuteAsync(). Equal to IQueryable.Execute, the synchronous method to execute a query. Calls ILLBLGenProQuery.Execute.
- ExecuteAsync<TResult>(). Returns the query result casted to TResult. Equal to IQueryable.Execute, the synchronous method to execute a Linq query. Calls ILLBLGenProQuery.Execute.
Scalar value returning methods
The following methods have been added to execute a scalar returning linq query asynchronously. The difference with the IEnumerable returning methods is that the method which defines what value to return is also the async method. This means that the async method is part of the linq query.
Async variants of methods unique to LLBLGen Pro:
- CountColumnAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>)
- CountColumnAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>, bool)
- StandardDeviationAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>)
- StandardDeviationAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>, bool)
- VarianceAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>)
- VarianceAsync<TSource, TColumnType>(Expression<Func<TSource, TColumnType>>, bool)
Async variants of methods provided by Queryable / System.Linq
- AllAsync<TSource>(Expression<Func<TSource, bool>>)
- AnyAsync<TSource>()
- AnyAsync<TSource>(Expression<Func<TSource, bool>>)
- AverageAsync(). Various overloads for different numeric types.
- AverageAsync<TSource>(Expression<Func<TSource, returntype>>). Various overloads for different numeric types.
- ContainsAsync<TSource>(TSource)
- CountAsync<TSource>()
- CountAsync<TSource>(Expression<Func<TSource, bool>>)
- ElementAtAsync<TSource>(int)
- ElementAtOrDefaultAsync<TSource>(int)
- FirstAsync<TSource>()
- FirstAsync<TSource>(Expression<Func<TSource, bool>>)
- FirstOrDefaultAsync<TSource>()
- FirstOrDefaultAsync<TSource>(Expression<Func<TSource, bool>>)
- LongCountAsync<TSource>()
- LongCountAsync<TSource>(Expression<Func<TSource, bool>>)
- MaxAsync<TSource>()
- MaxAsync<TSource, TResult>(Expression<Func<TSource, TResult>>)
- MinAsync<TSource>()
- MinAsync<TSource, TResult>(Expression<Func<TSource, TResult>>)
- SingleAsync<TSource>()
- SingleAsync<TSource>(Expression<Func<TSource, bool>>)
- SingleOrDefaultAsync<TSource>()
- SingleOrDefaultAsync<TSource>(Expression<Func<TSource, bool>>)
- SumAsync(). Various overloads for different numeric types.
- SumAsync<TSource>(Expression<Func<TSource, returntype>>). Various overloads for different numeric types.