How can I use LINQ in CosmosDB SDK v3.0 async query?

后端 未结 2 1191
野的像风
野的像风 2021-02-20 08:26

I\'ve been following the official documentation here: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-get-started#Query

But I can\'t figure out how to correctly

2条回答
  •  佛祖请我去吃肉
    2021-02-20 08:51

    If your application follows a layered architecture and you'd like to give your domain layer full control over the query then it's possible to wrap cosmos IQueryable with a custom IQueryProvider that implements IAsyncEnumerable e.g.

    By doing that you can hide the implementation details of asynchronously iterating over the result from your domain layer.

    Persistence layer

    public class PersonRepository
    {
        public IQueryable Persons => _cosmosContainer.GetItemLinqQueryable().ToCosmosAsyncQueryable();
    }
    

    Domain layer

    var persons = await _personRepository.Persons
        .Where(p => p.Name == "Name")
        .AsAsyncQueryable()
        .ToListAsync(cancellationToken);
    
    • ToListAsync is available from System.Linq.Async that can be referenced from your domain layer

    Domain layer extensions

    public static IAsyncEnumerable AsAsyncQueryable(this IQueryable queryable)
    {
        return (IAsyncEnumerable)queryable;
    }
    

    Persistence layer extensions

    internal static class CosmosAsyncQueryableExtensions
    {
        internal static IQueryable ToCosmosAsyncQueryable(this IOrderedQueryable source)
        {
            return new CosmosAsyncQueryable(source);
        }
    }
    
    internal class CosmosAsyncQueryable : IEnumerable, IQueryable, IAsyncEnumerable
    {
        private readonly IQueryable _queryable;
    
        public CosmosAsyncQueryable(IQueryable queryable)
        {
            _queryable = queryable;
            Provider = new CosmosAsyncQueryableProvider(queryable.Provider);
        }
    
        public Type ElementType => typeof(TResult);
    
        public Expression Expression => _queryable.Expression;
    
        public IQueryProvider Provider { get; }
    
        public IEnumerator GetEnumerator() => _queryable.GetEnumerator();
    
        IEnumerator IEnumerable.GetEnumerator() => _queryable.GetEnumerator();
    
        public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
            var iterator = _queryable.ToFeedIterator();
    
            while (iterator.HasMoreResults)
            {
                foreach (var item in await iterator.ReadNextAsync(cancellationToken))
                {
                    yield return item;
                }
            }
        }
    }
    
    internal class CosmosAsyncQueryableProvider : IQueryProvider
    {
        private readonly IQueryProvider _provider;
    
        public CosmosAsyncQueryableProvider(IQueryProvider provider) => _provider = provider;
    
        public IQueryable CreateQuery(Expression expression) =>
            new CosmosAsyncQueryable(_provider.CreateQuery(expression));
    
        public IQueryable CreateQuery(Expression expression) => CreateQuery(expression);
    
        public object Execute(Expression expression) => _provider.Execute(expression);
    
        public TResult Execute(Expression expression) => _provider.Execute(expression);
    }
    
        

    提交回复
    热议问题