我最近一直在使用很多Async,因为客户端应用程序是一个移动应用程序,使用非ui阻止api非常重要。
我一直在做这样的询问:
var answer = _baseCommands.GetAll<Answer>().FirstOrDefault(x => x.QuestionId == question1.QuestionId && x.IsCorrect);
这是哪种方法,但我也使用它:
IQueryable<T> GetAll<T>() where T : class;
Task<IQueryable<T>> GetAllAsync<T>() where T : class;
这是BaseCommands中的两者的实现:
public IQueryable<T> GetAll<T>()
where T : class
{
return _askDatabase.Set<T>();
}
public async Task<IQueryable<T>> GetAllAsync<T>()
where T : class
{
return await Task.FromResult(_askDatabase.Set<T>());
}
无论如何都要写这样的代码所以我可以得到所有的aysnc但是有一个lambda:
var answer = await _baseCommands.GetAllAsync<Answer>().Result.FirstOrDefault(x => x.QuestionId == question1.QuestionId && x.IsCorrect);
这有什么好的做法?
答案 0 :(得分:1)
诚实地,异步创建IQueryable<T>
没有多大意义。创建的对象只是代表问题,它不是自己执行查询,所以它可能非常便宜;记得LINQ很懒;查询将在您枚举时执行,而不是之前执行。
如果返回枚举查询,调用例如ToList()
,则异步方法会更有意义。如果连接具有非常高的延迟并且从数据库带回的数据量不是太大,这可能是有意义的。
答案 1 :(得分:0)
是的,可以通过()
包装它:
(await _baseCommands.GetAllAsync<Answer>())
.FirstOrDefault(x => x.QuestionId == question1.QuestionId && x.IsCorrect);
await _baseCommands.GetAllAsync<Answer>().FirstOrDefault
没有编译,因为Task没有该方法的定义。但是如果你在()
中包装那个等待调用,那么你可以对该任务的结果执行.FirstOrDefault
。请注意,这会执行过滤synchronously
。
在您的API中使用Task.FromResult
是无用的,您不会在此处异步执行操作。这主要用于模型。您需要使用Task.Run()
来代替异步执行查询。此外,您最好执行查询并使用.ToList()
返回集合,以便在后台线程中执行查询。
如果您可以更改提取数据的API,我建议您添加一些重载:
Task<List<T>> GetAllAsync<T>(Expression<Func<T, bool>> predicate) where T : class;
然后,您可以使用该谓词直接在API内查询数据库。