Reputation: 3752
Imagine you have a variable databaseContext
and want to select all users from the users table. From the docs
https://learn.microsoft.com/en-us/ef/core/querying/
you might create this method:
public IEnumerable<User> GetUsers() => _databaseContext.Users;
but isn't that synchronous code? And I think this is completely wrong:
public Task<User[]> GetUsers() => _databaseContext.Users.ToArrayAsync();
I would expect a method like this:
public Task<IEnumerable<User>> GetUsers() => _databaseContext.Users /* but select them asynchronously */;
Since EF Core provides synchronous and asynchronous methods e.g. Find
and FindAsync
I don't know how to query all data asynchronously. Maybe EF Core does this under the hood somehow but then I should have to await it, right?
Upvotes: 1
Views: 3391
Reputation: 8338
public async Task<IEnumerable<User>> GetUsers() => await _databaseContext.Users.ToListAsync();
Here the async
keyword identifies the method as an asynchronous method (so that you can call it accordingly) and the await
keyword makes sure - i) the calling thread isn't blocked and, ii) the result is awaited. Which thread (the calling one itself or a separate one) receives the awaited result later depends on how the Task Library handles async/await
operations under-the-hood. And that exactly is what the Task Library is intended to do - taking away the concept of thread from the developers' hand forcing them to think in terms of Task
, a higher level abstraction it provides instead.
For more -
Dissecting the async methods in C#
https://stackoverflow.com/a/42291461/446519
public IEnumerable<User> GetUsers() => _databaseContext.Users;
is a synchronous method, but more importantly it doesn't query the database. To query the database and then return the list of all users (synchronously) call ToList()
-
public IEnumerable<User> GetUsers() => _databaseContext.Users.Tolist();
public Task<User[]> GetUsers() => _databaseContext.Users.ToArrayAsync();
is also a synchronous method and it will return a Task<User[]>
instance immediately. But you can use the returned task object later, to get the result asynchronously, like -
Task<User[]> task = this.GetUsers();
User[] users = task.GetAwaiter().GetResult();
EDIT :
In point No.3 above, the code used after returning the Task<User[]>
is purely to demonstrate the fact - "its your Task
object now and you can use it later to get the result from it asynchronously". Showing what approach you should or shouldn't use for doing that was not the intention.
As @pinkfloydx33 suggested in the comment, .GetAwaiter().GetResult()
might not always be the best approach to get the result. You can do the same without being explicit about getting the awaiter
as -
Task<User[]> myTask = this.GetUsers();
User[] users = await myTask;
Upvotes: 2