Skip to content

Commit 5de81ca

Browse files
committed
Add spectial wrapper for querues that are not IAsyncEnumerable natively
Such as EntitySets. The wrapper allows to apply .ToArrayAsync/ToListAsync/ToHashSetAsync extension methods to EntitySets. Correct implementation of IAsyncEnumerable would take a lot of resources because many apis should support async operation, this approach less painfull, though has a caviar - in ClientProfile mode results does not contain local changes.
1 parent 808a617 commit 5de81ca

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

Orm/Xtensive.Orm/Orm/QueryableExtensions.Async.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ namespace Xtensive.Orm
2121
/// </summary>
2222
public static partial class QueryableExtensions
2323
{
24+
/// <summary>
25+
/// A wrapper to transform non-<see cref="IAsyncEnumerable{T}"/>, yet based on <see cref="QueryProvider"/>,
26+
/// <see cref="IQueryable{T}"/> implementation, such as <see cref="EntitySet{TItem}"/>, into <see cref="IAsyncEnumerable{T}"/>.
27+
/// </summary>
28+
private sealed class QueryAsAsyncEnumerable<T> : IAsyncEnumerable<T>
29+
{
30+
private readonly QueryProvider queryProvider;
31+
private readonly Expression expression;
32+
33+
/// <inheritdoc/>
34+
public async IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
35+
{
36+
var result = await queryProvider.ExecuteSequenceAsync<T>(expression, cancellationToken).ConfigureAwait(false);
37+
var asyncSource = result.AsAsyncEnumerable().WithCancellation(cancellationToken).ConfigureAwait(false);
38+
await foreach (var element in asyncSource) {
39+
yield return element;
40+
}
41+
}
42+
43+
public QueryAsAsyncEnumerable(QueryProvider queryProvider, Expression expression)
44+
{
45+
this.queryProvider = queryProvider;
46+
this.expression = expression;
47+
}
48+
}
49+
2450
/// <summary>
2551
/// Asynchronously determines whether all the elements of a sequence satisfy a condition.
2652
/// </summary>
@@ -1654,8 +1680,12 @@ public static IAsyncEnumerable<TSource> AsAsyncEnumerable<TSource>(this IQueryab
16541680
{
16551681
ArgumentValidator.EnsureArgumentNotNull(source, nameof(source));
16561682

1657-
if (source is IAsyncEnumerable<TSource> asyncEnumerable) {
1658-
return asyncEnumerable;
1683+
if (source is IAsyncEnumerable<TSource> nativeAsyncEnumerable) {
1684+
return nativeAsyncEnumerable;
1685+
}
1686+
1687+
if (source.Provider is QueryProvider doProvider) {
1688+
return new QueryAsAsyncEnumerable<TSource>(doProvider, source.Expression);
16591689
}
16601690

16611691
throw new InvalidOperationException("Query can't be executed asynchronously.");

0 commit comments

Comments
 (0)