foreachasync和带有实体记录的for循环之间的区别?

时间:2019-05-14 16:26:18

标签: c# entity-framework

我很想知道以下两个语句之间的区别是什么,为什么.ForEacHAsync不能用于创建新行,而for循环却可以呢?

这有效并添加了新的唱片产品

var recordProducts = context.RecordsProducts
            .Where(i => i.RecordId == model.OldRecordId);

        foreach (var rp in recordProducts)
        {
            var newRecordProduct = new RecordProduct
            {
                IsActive = true,
                RecordId = model.RecordId,
                ProductId = rp.ProductId,
                DefendantId = rp.DefendantId,
                Annotation = rp.Annotation
            };
            context.RecordsProducts.Add(newRecordProduct);
        }

这不是

var recordProducts = 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);
            }
        );

1 个答案:

答案 0 :(得分:5)

在第一个示例中,您的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编辑。如果您想使用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();