带有实体框架更新的TPL

时间:2011-10-19 10:32:06

标签: entity-framework parallel-processing

我有一个业务案例,对于给定源表中的每个记录,需要对不同表中的每个记录进行一些更改,并且每个sourceTable记录都需要单独处理。

所以我有以下pseodocode:

MyEntityFrameworkContext ctx;
foreach (sourceRecord sr in ctx.sourceTable)
{
    try
    {
        using (MyEntityFrameworkContext tctx = new MyEntityFramworkContext)
        {
            string result1 = MakeUpdatesToSomeOtherTable1(tctx);
            sr.Result1 = result1;
            string result2 = MakeUpdatesToSomeOtherTable2(tctx);
            sr.Result2 = result2;
            // will be more tables here.
            using (TransactionScope ts = new TransactionScope)
            {
                tctx.SaveChanges; // to save changes made to OtherTable1 and    OtherTable2
                tctx.ExecuteStoreCommand("SQL that makes a few other changes related to    sourceRecord to tables that are NOT in the EF context");
                ts.Complete();
            }
        }
    }
    catch (Exception ex)
    {
     sr.ExceptionResult = ex.Message();
    }
});
ctx.SaveChanges(); // to save all changes made to sourceTable.

循环中tctx和TransactionScope的原因是我需要对一个事务中保存对OtherTables1& 2的更改,并为每个正在处理的sourceRecord调用tctx.ExecuteStoreCommand()。

另请注意,我需要保存写入sourceTable的结果,而不是对TransactionScope中更新的表所做的更改。因此,我不能在同一个TransactionScope中包含sourceTable的更新,因为如果txn回滚,我将不会有异常记录。这样,在整个过程结束时,我可以看到哪些sourceRecords失败,哪些成功。

上述伪代码效果很好。

但是,我想在这里利用并行性,并将foreach转换为Parallel.ForEach()。但后来我遇到了非常意外的错误(比如在调用ts.Complete()之后的TransactionAbortedException,调用ctx.SaveChanges()时的NullReferenceException,或者在设置sourceRecord的Result属性之一时,我有时会得到InvalidOperationException:EntityMemberChanged或EntityComplexMemberChanged被调用而没有首先使用相同的属性名称在同一个更改跟踪器上调用EntityMemberChanging或EntityComplexMemberChanging。

所以我认为并行性虽然对于QUERIES来说是完美的,但它并不适合EntityFramwork中的数据更新?我错过了什么,或者不了解并行性?我不明白为什么我的上述方法在转换为使用并行性时会中断。任何建议将不胜感激。

2 个答案:

答案 0 :(得分:1)

EF对象上下文不是线程安全的,因此当多个线程在同一个上下文中嗡嗡作响时,很有可能发生灾难性错误。

看起来你在foreach循环之外至少有一个上下文对象,并在线程之间共享。

根据您的描述,我猜测来自多个线程的sourceRecord实体的更新属性正在破坏上下文中的某些内部状态 - 可能是它为变更跟踪维护的数据集合。

答案 1 :(得分:0)

并行性只会为那些受CPU限制的操作带来好处,在你的情况下,你所做的一切似乎都是IO操作(数据库更新等),所以我认为你不能从中获得任何好处平行。但是如果此代码中的操作受CPU限制,则可以使它们与每次更新并行,但更新将是顺序的。