我有一个关于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给出相同的结果,但是我想问一下异步任务哪个更好,或者可能都不是。
谢谢。
答案 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))