实体框架异步记录计数与记录

时间:2015-12-28 22:19:16

标签: c# entity-framework asynchronous count async-await

我正在尝试从数据库中获取记录,但在同一次调用DB中获取记录计数。我的方法是异步的,所以我不确定这是否是正确的方法:

    public async Task<IEnumerable<ProductItemViewModel>> GetAsync(int pageIndex, int pageSize)
    {
        var products = this.Repository.GetAll<Product>().OrderBy(p => p.Price).AsQueryable();

        var count = await products.CountAsync();
        if (count == 0)
            return new List<ProductItemViewModel>();

        products = products.ToPaginatedList(pageIndex, pageSize);
        var result = await products.ToListAsync();

        var viewModels = new List<ProductItemViewModel>();
        Mapper.Map(result, viewModels);

        return viewModels.AsEnumerable();
    }

我认为等待CountAsync()不太好,但我不确定如何实现它。

问候。

编辑:

我为没有在任何地方返回计数而道歉,因为它现在看起来我只计算因为== 0检查,但我最终会返回带有记录的计数,因为我需要它用于我的角度分页指令。还没弄清楚我将如何返回(新类vs元组)所以我把它错过了,并专注于单个数据库调用中的实体框架Count()和实体提取。

2 个答案:

答案 0 :(得分:2)

我认为您的代码可以针对此进行优化:

using AutoMapper.QueryableExtensions;
//...
public async Task<IEnumerable<ProductItemViewModel>> GetAsync(int pageIndex, int pageSize)
{
    var products = this.Repository.GetAll<Product>().OrderBy(p => p.Price);// I think you don't need to call AsQueryable(), you already are working with IQueryable
    var result=await products.Skip(pageIndex*pageSize).Take(pageSize).ProjectTo<ProductItemViewModel>().ToListAsync();
    return result;
}

最后,只需一行即可完成:

public async Task<IEnumerable<ProductItemViewModel>> GetAsync(int pageIndex, int pageSize)
{

    return await this.Repository.GetAll<Product>()
                                .OrderBy(p => p.Price)
                                .Skip(pageIndex*pageSize)
                                .Take(pageSize)
                                .ProjectTo<ProductItemViewModel>()
                                .ToListAsync();
}

.ProjectTo<ProductItemViewModel>()将告诉AutoMapper的映射引擎向IQueryable发出一个select子句,该子句将通知Entity Framework它只需要查询您映射的属性,就像是您使用IQueryable条款将ProductItemViewModel手动投影到Select

答案 1 :(得分:1)

哎呀,我完全错过了你的回归类型。我以为您使用计数来显示TotalResultCount以及您的分页集合。既然你不是,那就完全消除了。

只需删除CountAsync()调用,然后检查results.Count属性是否为零。这不是你拥有的结果总数,但它会告诉你它是否为空。

public async Task<IEnumerable<ProductItemViewModel>> GetAsync(int pageIndex, int pageSize)
{
    var result = await this.Repository.GetAll<Product>()
        .OrderBy(p => p.Price)
        .ToPaginatedList(pageIndex, pageSize)
        .ToListAsync();

    if (result.Count == 0)
    {
        // This "if" really isn't necessary, as your mapper should map an
        // empty collection to an empty collection. But it is a minor
        // efficiency improvement, and it speaks to your original code.

        return Enumerable.Empty<ProductItemViewModel>();
    }

    var viewModels = new List<ProductItemViewModel>();
    Mapper.Map(result, viewModels);

    return viewModels; // AsEnumerable() has no effect here, as the cast will happen by
                       // default anyway
}

这可以避免额外调用服务器,但代价是该变量的含义。如果您的分页支持告诉用户代理有多少页面,请在此行下面阅读,但除此之外,此代码应该处理您在此处所做的事情。

这个答案有一个错误的假设,你需要知道总结果数;我最初错误地阅读了代码。

听起来你所拥有的将是你最好的选择。

我不知道实体框架中有什么方法可以使用T-SQL的COUNT(*) OVER ()子句,这听起来就像你正在寻找的那样。

您的方法唯一的麻烦就是您将针对您的服务器运行两个查询:

  • 有多少条记录?
  • 给我记录x..y

效率低于将它们组合在一起的效果,但它可能不会对大多数应用程序产生巨大影响。如果您担心性能成本,我会重新评估您可能拥有的索引,或者甚至考虑实体框架的替代方案。

事实上,这都是async没有任何区别。针对await致电CountAsync()正是它的用法。