Foreach循环异步等待

时间:2018-11-21 10:08:51

标签: c# foreach async-await

我有一个关于foreach循环中async-await的良好实践的问题。

我的方法看起来像这样

 public async Task<List<Category>> GetCategoriesAsync(string partOfName,
        CancellationToken ct = default(CancellationToken))
    {
        string lowerCasePartOfName = partOfName.ToLower();

        var categories = await _context.ECATEGORIES
            .Where(a => a.NAME.ToLower().Contains(lowerCasePartOfName))
            .ProjectTo<Category>()
            .ToListAsync(ct);

        //version1 #Beginning 
        var i = 0;
        foreach (var parentId in categories)
        {
            var categoryParent = await _context.ECATEGORIES
                .Where(a => a.ID == parentId.ParentId)
                .Select(s => s.NAME)
                .FirstOrDefaultAsync(ct);

            categories[i].CategoryParent = categoryParent;
            i++;
        }
        //version1 #End

        //version2 #Beginning 
        categories.ForEach(async x => x.CategoryParent = await _context.ECATEGORIES
            .Where(a => a.ID == x.ParentId)
            .Select(s => s.NAME).FirstOrDefaultAsync(ct));
        //version2 #End

        return categories;
    }

版本1和版本2给出相同的结果,但是我想问一下异步任务哪个更好,或者可能都不是。

谢谢。

1 个答案:

答案 0 :(得分:1)

两者都是不好的,因为可以重写代码以利用适当的联接。这将使1个数据库调用,而不是每个类别+ 1个(对于初始调用)。但是严格回答您的问题并不重要:选择您最习惯的一个

  

我遇到的问题是,parentId通常是重复的,我不能使用。包含

您可以使用左联接来执行相同的操作,但是所有操作都在1个DB调用中,比每个结果1个调用便宜。

string lowerCasePartOfName = partOfName.ToLower();

var categories = await (from category in _context.ECATEGORIES.Where(a => a.NAME.ToLower().Contains(lowerCasePartOfName))
    from parent in _context.ECATEGORIES.Where(parent => parent.ID == category.ParentId).DefaultIfEmpty()
    select new Category
    {
        Id = category.ID,
        CategoryParent = parent.NAME,
    }).ToListAsync();

如果将模式设置为不区分大小写,则也可以省略ToLower调用。您可以通过查看COLLATION进行检查。

.Where(a => a.NAME.Contains(lowerCasePartOfName))