为什么自动生成的控制器的Get()方法是同步的?

时间:2019-01-03 13:58:14

标签: c# .net asp.net-mvc asp.net-core .net-core

使用实体创建基本的ASP.NET Core 2.1 MVC API Web应用程序时,可以在选择模型和dbContext之后自动生成控制器(RMB->添加->控制器...->具有动作的API控制器,使用实体框架)

我想知道为什么除了返回所有表的基本Get()方法之外,所有生成的方法都是异步的?这是错误吗?这是一个数据库调用,因此我希望它是异步的。在这种情况下使用异步调用没有真正的好处吗?如果是,为什么?

    // GET: api/User
    [HttpGet]
    public IEnumerable<User> GetUsers()
    {
        return _context.Users;
    }

2 个答案:

答案 0 :(得分:2)

return _context.Users仅返回类型DbSet<Users>的对象。它不会对其进行迭代或进行任何工作,而只是传递一个允许您访问数据库数据的对象。

DbSet<T>也是IQueryable<T>,这意味着直到调用诸如.ToList().Single(x=>x.Id == idToLookFor)

之类的某种执行函数才调用数据库。

如果要异步迭代它,那么将有一个异步Get()方法,例如;

return await _context.Users.ToListAsync()


更新

我意识到实际上没有回答您的问题,

您极不可能希望返回整个表。 (SELECT * FROM [Users])所以这里的Get()方法是一种反模式(在我看来**),称为“公开IQueryable”

因此,您可以在控制器中执行类似的操作

_context.Get().Where(user=>user.FirstName == 'Steve').ToList()

或者您可以使它与数据库调用异步,

await _context.Get().Where(user=>user.FirstName == 'Steve').ToListAsync()

那么,生成的模板Get()是否错误?不,但是我认为您不应该将IQueryable作为公共方法公开,因此我不同意。


IQueryable<T>

var query = _context.Users;  //SQL:  * FROM [Users]

query = query.Where(x=>x.Name == "Steve"); 
//SQL: * FROM [Users] WHERE Name = 'Steve'

query = query.Where(x=>x.wearsHats == true);
//SQL: * FROM [Users] WHERE Name = 'Steve' AND WearsHats = true

query = query.Select(x=>x.Name);
//SQL: Name FROM [Users] WHERE Name = 'Steve' AND WearsHats = true

var result = query.ToList()
//SQL: SELECT Name FROM [Users] WHERE Name = 'Steve' AND WearsHats = true

答案 1 :(得分:0)

是的,这与所有其他异步操作非常不一致。我认为没有任何具体原因。我认为Microsoft只是忘记更新模板的这一部分。我希望会生成以下内容:

// GET: api/User
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
    return await _context.Users.ToListAsync();
}

即使是一个线性操作也可以从异步中受益-IIS线程在数据库查询期间不会被阻止。您可以在SO的其他问题中了解更多有关此内容的信息,例如:When should I use Async Controllers in ASP.NET MVC?

编辑:您可以在github上找到模板源。您可以在第38-42行中看到,在最新版本中,此操作已更新,并且将以异步方式生成,与我上面所写的完全相同。