You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C# Cust类转换为支持异步查询的IQueryable对象?

解决IQueryable不支持IAsyncQueryProvider的问题

报错的核心原因是:通过List<T>.AsQueryable()得到的是Linq to Objects的查询提供者,它没有实现EF异步操作所需的IAsyncQueryProvider接口,因此无法直接用于CountAsync这类EF异步方法。以下是几种可行的解决办法:

方法一:使用EF Core内存数据库(推荐用于测试/模拟场景)

如果需要模拟EF的查询环境,用EF Core的InMemory数据库可以直接获取支持异步的IQueryable<Cust>:

  1. 定义包含Cust实体的DbContext:
public class AppDbContext : DbContext
{
    public DbSet<Cust> Custs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseInMemoryDatabase(databaseName: "TestDb");
    }
}
  1. 初始化数据并获取支持异步的IQueryable:
using var context = new AppDbContext();
// 添加测试数据
context.Custs.AddRange(new List<Cust> { new Cust(), new Cust() });
context.SaveChanges();

// 此处的context.Custs是支持IAsyncQueryProvider的IQueryable<Cust>
var queryable = context.Custs.AsQueryable();
// 可直接传入CountCust方法
await CountCust(queryable, CancellationToken.None);

方法二:自定义异步查询提供者包装类

如果不想依赖EF的InMemory数据库,可以自行实现IAsyncQueryProvider,将普通IQueryable包装为支持异步的版本。以下是简化实现:

public class AsyncQueryProvider<T> : IAsyncQueryProvider
{
    private readonly IQueryProvider _innerProvider;

    public AsyncQueryProvider(IQueryProvider innerProvider)
    {
        _innerProvider = innerProvider;
    }

    public IQueryable CreateQuery(Expression expression)
    {
        return new AsyncEnumerable<T>(expression, this);
    }

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
    {
        return new AsyncEnumerable<TElement>(expression, this);
    }

    public object Execute(Expression expression)
    {
        return _innerProvider.Execute(expression);
    }

    public TResult Execute<TResult>(Expression expression)
    {
        return _innerProvider.Execute<TResult>(expression);
    }

    public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute(expression));
    }

    public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute<TResult>(expression));
    }
}

public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
    public AsyncEnumerable(Expression expression) : base(expression) { }

    public AsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }

    public AsyncEnumerable(Expression expression, IAsyncQueryProvider provider) : base(expression)
    {
        Provider = provider;
    }

    public new IAsyncQueryProvider Provider { get; }

    public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
    {
        return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
    }
}

public class AsyncEnumerator<T> : IAsyncEnumerator<T>
{
    private readonly IEnumerator<T> _innerEnumerator;

    public AsyncEnumerator(IEnumerator<T> innerEnumerator)
    {
        _innerEnumerator = innerEnumerator;
    }

    public T Current => _innerEnumerator.Current;

    public ValueTask DisposeAsync()
    {
        _innerEnumerator.Dispose();
        return ValueTask.CompletedTask;
    }

    public ValueTask<bool> MoveNextAsync()
    {
        return ValueTask.FromResult(_innerEnumerator.MoveNext());
    }
}

使用时直接包装普通IQueryable:

var list = new List<Cust> { new Cust(), new Cust() };
var asyncQueryable = new AsyncEnumerable<Cust>(list.AsQueryable().Expression, new AsyncQueryProvider<Cust>(list.AsQueryable().Provider));

await CountCust(asyncQueryable, CancellationToken.None);

方法三:在CountCust方法中兼容普通IQueryable(妥协方案)

如果只是希望方法兼容两种IQueryable,可以在CountCust内部做判断,遇到不支持异步的提供者时,改用同步计数再包装为Task:

public async Task<int> CountCust(IQueryable<Cust> query, CancellationToken cancellationToken)
{
    if (query.Provider is IAsyncQueryProvider)
    {
        return await query.CountAsync(cancellationToken);
    }
    else
    {
        // 同步计数后返回已完成的Task
        return query.Count();
    }
}

内容的提问来源于stack exchange,提问作者EBDS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:04:01