В первом примере ваш IQueryable<RecordProduct> recordProducts
будет оцениваться синхронно, а не асинхронно, поэтому он блокирует поток внутри (скрытого) вызова на IQueryable.GetEnumerator() ...MoveNext()
.
В то время как во втором примере метод расширения .ForEachAsync
будет запускать анонимную функцию асинхронно и эквивалентен этому:
IQueryable<RecordProduct> list = await context.RecordsProducts
.Where(i => i.RecordId == model.OldRecordId);
using( DataReader rdr = await ExecuteQueryAsDataReader( list ) )
{
while( await rdr.ReadAsync() )
{
await ForEachAsyncBodyHere();
}
}
Ваш второй пример не работает, потому что результатом вашего выражения является Task
, которое никогда не будет await
ed. Если вы хотите использовать ForEachAsync
, вам нужно изменить код на этот:
Task loadTask = context.RecordsProducts
.Where(i => i.RecordId == model.OldRecordId)
.ForEachAsync(a =>
{
var newRecordProduct = new RecordProduct
{
IsActive = true,
RecordId = model.RecordId,
ProductId = a.ProductId,
DefendantId = a.DefendantId,
Annotation = a.Annotation
};
context.RecordsProducts.Add(newRecordProduct);
}
);
await loadTask; // This will wait (actually, _yield_) until all of the `ForEachAsync` iterations are complete.
await context.SaveChangesAsync(); // This will actually save the new rows added to `context.RecordsProducts`
Я не думаю, что какой-либо фрагмент кода обязательно является хорошим - я думаю, что наилучшим подходом было бы загружать все данные асинхронно одновременно, используя ToListAsync
, а затем использовать обычный синхронный foreach
- Add
каждый запись тогда await SaveChangesAsync
:
List<RecordProduct> list = await context.RecordsProducts
.Where(i => i.RecordId == model.OldRecordId)
.ToListAsync();
foreach( RecordProduct rp in list )
{
context.RecordsProduct.Add( ... );
}
await context.SaveChangesAsync();