【问题标题】:Resolve IQueryable and Async in Method解决方法中的 IQueryable 和 Async
【发布时间】:2019-12-28 12:11:33
【问题描述】:

我正在尝试结合异步原理并正确实施。 在下面的代码中,departmentRepository.GetAll 返回 IQueryable。之后,GetPage(1,3) 返回 IEnumerable。只是好奇根据 Intellisense,新代码行是否有意义。

原始代码:

应用服务代码:

public async Task<IEnumerable<DepartmentDto>> GetAllDepartments()
{
    var departments = await departmentRepository.GetAll();
    Paged<Department> departmentPaged = new Paged<Department>(departments);
    var departments2 = departmentPaged.GetPage(1, 3);
    var departmentDto = mapper.Map<IEnumerable<Department>, IEnumerable<DepartmentDto>>(departments2);
    return  departmentDto;
}

第一行 await departmentRepository.GetAll() 给了我一个错误。

IQueryable 不包含 GetAwaiter 的定义和不可访问的扩展方法 Getawaiter`

所以 Intellisense 建议更改为

var departments = await departmentRepository.GetAll().ToListAsync();

更改后,在 var department2 = departmentPaged.GetPage(1, 3); 行弹出第二个错误

无法将 System.Collections.Generic.List 转换为 System.Linq.IQueryable。

所以 Intellisense 建议改成

Paged<Department> departmentPaged = new Paged<Department>(departments.AsQueryable());

所以新代码如下所示:

这有意义吗,是回旋处,还是有什么好办法?

public async Task<IEnumerable<DepartmentDto>> GetAllDepartments()
{
    var departments = await departmentRepository.GetAll().ToListAsync();
    Paged<Department> departmentPaged = new Paged<Department>(departments.AsQueryable());
    var departments2 = departmentPaged.GetPage(1, 3);
    var departmentDto = mapper.Map<IEnumerable<Department>, IEnumerable<DepartmentDto>>(departments2);
    return  departmentDto;
    }

也在研究这个:IQueryable does not contain definition for GetAwaiter

其他参考代码:

基础存储库和其他选项(公司的架构师想要通用存储库,而不是我的电话):

    public IQueryable<T> GetAll()
    {
        return All;
    }
    public List<T> GetAllList()
    {
        return All.ToList();
    }

    public List<T> GetAllList(Expression<Func<T, bool>> predicate)
    {
        return All.Where(predicate).ToList();
    }

    public async Task<List<T>> GetAllListAsync()
    {
        return await All.ToListAsync();
    }

分页方式:

    public IEnumerable<T> GetPage(int index, int limit)
    {
        return source.Skip((index - 1) * limit)
            .Take(limit);
    }

【问题讨论】:

  • 您的方法中似乎根本没有任何异步代码,您能澄清一下哪些位实际上是异步的吗?
  • hi @LasseVågsætherKarlsen API,调用此应用服务方法,然后调用基本数据存储库,也不确定,公司建议在 API 调用中使用异步,向下到数据层
  • 而您选择先将其转换为列表,然后再转换回可查询的选项,将消除使用分页的所有性能优势,您将首先获取所有项目,然后分页将仅选择那些与页面相关。如果您始终将其保持为可查询,分页将向可查询添加条件以仅获取它需要的项目。
  • 您发布的实现同样糟糕,如果您正在进行分页,我会将其保留为IQueryableToListAsync 将抓取所有项目,无需分页,然后您在列表中分页。 IQueryable 上的分页将在执行之前修改查询,这可能会更便宜。
  • 理想的方法是在存储库中实现适当的异步处理,然后使用它。现在的方式是你的异步实现很糟糕,所以我会让你的方法保持同步。将您的方法转为与当前实现异步不会有任何好处。

标签: c# linq generics asp.net-core .net-core


【解决方案1】:

虽然我认为在通用存储库接口中公开 IQueryable&lt;T&gt; 是完全失败的,但我认为你不能反对这一点。

看来你可以改写成:

public IEnumerable<DepartmentDto> GetAllDepartments()
{
    var departmentPaged = new Paged<Department>(departmentRepository.GetAll());
    return mapper.Map<IEnumerable<Department>, IEnumerable<DepartmentDto>>(departmentPaged.GetPage(1, 3));
}

其中不涉及异步代码。

如果您仍想强制将返回类型包装在任务中,您可以这样做:

public Task<IEnumerable<DepartmentDto>> GetAllDepartments()
{
    var departmentPaged = new Paged<Department>(departmentRepository.GetAll());
    return Task.FromResult(mapper.Map<IEnumerable<Department>, IEnumerable<DepartmentDto>>(departmentPaged.GetPage(1, 3)));
}

【讨论】:

  • 嗨@JotaToledo,除了异步之外,我还有其他基本存储库选项,如果它改变了答案,请告诉我,谢谢!
  • 对了,我听说result中的task不是最佳实践,不确定是真是假,在这两个选项中,你更喜欢哪一个?
  • Task.FromResult 必须在您实现约定时使用,例如重写方法或接口方法,它指示 Task&lt;T&gt; 返回类型,但您实际上有一个同步实现。否则,这不是一个好主意。
  • 我会放弃第二个选项;原因很简单,因为您没有实现将您“绑定”到该接口的合同,因此您没有理由强制返回任务,因为您的方法不执行任何异步操作。
  • 什么是让它异步的理想方法,如果我废弃一些代码,我应该向基础存储库添加一些东西吗?还是同步好?谢谢
猜你喜欢
  • 1970-01-01
  • 2014-12-02
  • 2018-11-09
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多