EF6 - Using the await keyword with the Where() cla

2019-04-07 15:24发布

问题:

I am coding a MVC 5 internet application with entity framework 6 and have a question in regards to using the await keyword when using the .Where() clause.

Here is my code that works:

public async Task<Account> GetAccount(string userName)
{
    if (Session[userName] == null)
    {
        Account account = db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();
        if (account == null)
        {
            //log out
            return null;
        }
        Session[userName] = account;
    }
    return Session[userName] as Account;
}

I am wanting to use the await keyword when retrieving the Account object as follows:

Account account = await db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();

Can the await keyword be used when using the .Where() clause?

Thanks in advance.

回答1:

The await keyword can only be used on methods that return "Task...", neither .Where nor .FirstOrDefault (Which is the last method in the chain, and thus would be the one the await keyword would apply to) return Task<IEnumerable<Account>>

In theory you could write you own extension method which simply wraps around the .Where and .FirstOrDefault methods.

Also, this question isn't exactly EF specific, but rather a 'pure' C# question.

public static class ExtensionMethods
{
    public static async Task<IEnumerable<T>> WhereAsync<T>(this IEnumerable<T> source, Func<T, bool> selector)
    {
        return await Task.Run(() => source.Where(selector));
    }
}

Although that would be kind of overkill imho.

You could just wrap your entire method in a Task, so your final code would be something like:

public async Task<Account> GetAccount(string userName)
{
    return await Task.Run(() =>
    {
        if (Session[userName] == null)
        {
            Account account = db.accounts.Where(a => a.userName.Equals(userName)).FirstOrDefault();
            if (account == null)
            {
                //log out
                return null;
            }
            Session[userName] = account;
        }
        return Session[userName] as Account;
    });
}


回答2:

There is no WhereAsync() method provided by EF (obviously because it can't potentially block, since LINQ uses deferred-execution), but since you're performing a FirstOrDefault() you could simply use the FirstOrDefaultAsync() method:

Account account = await db.accounts.FirstOrDefaultAsync(a => a.userName.Equals(userName));

See MSDN