我有一个简单的场景,但我想知道我的方法是否正确,是否更好地建议选择单个任务来保存我的失败订单,或者我可以启动并启动多个任务并等待它们全部到完成。在连接到Db和保存实体时,这种情况的正确方法是什么。
我已经有一个基于任务的单一版本,可以将一个实体保存到数据库中。
public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress)
{
var toSave = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList();
var tasks = new Task[toSave.Count()];
for (var i = 0; i < tasks.Length; i++)
{
var i1 = i;
tasks[i] = new Task(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow), TaskCreationOptions.PreferFairness);
var message = string.Format("- Order: {0} has been resaved.\n", toSave.ElementAt(i1).Order.FriendlyId);
if (progress != null)
progress.Report(message);
}
await Task.WhenAll(tasks);
}
目前,我已对上述内容进行了测试,并认为任务尚未开始,因为进度条不断循环。我的假设是Task.WhenAll应该为我开始我的任务 - 这就是我的想法?
或者应该在循环中使用它:
tasks[i] = Task.Run(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow));
我认为我很亲近,只是想让别人告诉我我是否正确地做了这件事。
反馈合并版本:
public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress)
{
var saveList = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList();
var saveTask = Task.Run(() =>
{
foreach (var ot in saveList)
{
SaveToDbBatch(oService, oiService, ot);
var message = string.Format("- Order: {0} has been resaved.\n", ot.Order.FriendlyId);
if (progress != null)
progress.Report(message);
}
});
await saveTask;
await Cache.UoW.SaveAsync();
}
答案 0 :(得分:6)
在连接到Db和保存实体时,此方案的正确方法是什么。
一般来说,你应该:
SaveChangesAsync
。Task.Run
(或者更糟糕的是 - 任务构造函数)。例如,EF有SaveChangesAsync
。答案 1 :(得分:2)
是的,您确定创建任务并不启动它。调用Task.Run(...)是更好的选择。
但是,更好的选择是使用从对ExecuteAsync(...)的调用返回的任务并等待它。这是因为ExecuteAsync任务是IO任务&amp;不是一个线程,所以它以不同的方式执行,并且没有用完线程池线程。
作为旁注:根据&#34; Save&#34;的复杂性;做每一个可能更可靠&#34; Save&#34;连续。这是因为如果存在由并行任务引起的任何数据库错误(例如约束违规),则如果它们并行执行(即,在随机时间)则将极难再现。
答案 2 :(得分:1)
new Task(...)
无法启动任务。启动它们不是Task.WhenAll
的责任。几乎不应该使用Task ctor。
使用Task.Run
。
答案 3 :(得分:0)
似乎把这个问题简化为我的更新中发布的一项任务,它也解决了我认为我会在这里提出的一个侧面问题,因为其他一些人热衷于追求我原来的方法。但我同意@jaytre,根据保存的复杂性和保存的对象,最好连续进行每次保存以进行错误处理 - 但这取决于你。
因此,如果你采用我原来的方法,你可能会遇到这个错误:
无法多次将EdmType映射到CLR类。 EdmType'FrootPipe.Data.Order'被映射多次。
这基本上归结为锁定/同步问题 - 因此不同的任务在更多或更少的时间内访问模型,所有这些都试图将失败的订单重新添加回数据模型。所以我的场景的错误有点难以辨别,但有些谷歌搜索引导我到下面。
如需进一步阅读,请参阅此处:Entity framework MappingException: The type 'XXX has been mapped more than once