是否可以使用lambda / linq等待获取集合?

时间:2016-07-31 10:55:49

标签: c# linq lambda async-await

我最近一直在使用很多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);

这有什么好的做法?

2 个答案:

答案 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内查询数据库。