为什么DbSet <TEntity>不实现EnumerableAsync

MHO*_*OOS 10 ienumerable entity-framework async-await c#-5.0 entity-framework-6

在实体框架6.1.1中,IDbSet表示可以从数据库查询的实体集合,其具体实现是DbSet,如

DbSet

为什么这个接口或其具体实现不包含ToEnumerableAsync或AsEnumerableAsync的任何定义,而是ToListAsync,ToArrayAsync,ToDictionaryAsync?

为了让您了解我遇到此问题的原因,我有以下一段代码,我希望将其设为异步:

public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
    string entityName = GetEntityName<TEntity>();
    return ((IObjectContextAdapter)DbContext).ObjectContext.CreateQuery<TEntity>(entityName);
}


public IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class
{
    if (sortOrder == SortOrder.Ascending)
    {
        return GetQuery<TEntity>().OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsEnumerable();
    }
    return
        GetQuery<TEntity>()
            .OrderByDescending(orderBy)
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .AsEnumerable();
}
Run Code Online (Sandbox Code Playgroud)

我想到的唯一实现如下:

public async Task<IEnumerable<TEntity>> GetAsync<TEntity, TOrderBy>(Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class
{
    if (sortOrder == SortOrder.Ascending)
    {
        return await GetQuery<TEntity>().OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
    }
    return
        await GetQuery<TEntity>()
            .OrderByDescending(orderBy)
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)

这是使方法异步的正确方法吗?

上述方法属于以下链接中实现的通用存储库: 实体框架POCO,存储库和规范模式 为了深入挖掘,您可以查看原始博客: 实体框架POCO,存储库和规范模式

小智 9

设计IEnumerable不允许与async/ 一起使用await.IEnumerator<T>.MoveNext()不能返回Task调用者可以的任何对象await,因为它有一个固定的返回类型bool.

async中知晓的版本IEnumerableIDbAsyncEnumerable,而这已经被实现DbQuery<T>,从中DbSet<T>派生,所以没有AsDbAsyncEnumerable()扩展方法是必要的,为了工作.

您的Get版本IMO不需要Async版本.它已经不会阻止,因为它没有做任何事情.只有当调用者开始使用返回的枚举时,才会查询数据库.我只是将返回类型更改为DbQuery<TEntity>.(这需要强制转换,但应该已经是返回的具体类型.)然后调用者可以决定是使用同步方法还是异步方法.

(实际上,经过仔细检查,我发现虽然你的问题是关于DbSet<T>,你实际上是使用支持ObjectContext而不是DbContext.这可能会给你ObjectQuery<T>可查询而不是DbQuery<T>可查询,答案会有所不同.你会做的事情如果你真的需要停止使用ObjectContext除外,你会更容易.)


Sco*_*ain 6

因为你不能有 a Enumerable所以该类是 static。您可以拥有一个IEnumerable,但列表、数组和字典都实现了它,那么您的 中的基础类型是什么ToEnumerableAsync()

你可以轻松做到

IEnumerable<TEntity> result = await yourDbSet.ToListAsync();
Run Code Online (Sandbox Code Playgroud)

  • 这可能会违背 IEnumerable 的目的,即成为最小化峰值内存使用的管道。 (5认同)