1

現在、非常に長い Linq トランザクションでアプリを実行しています。すべてがこの 1 つのトランザクションで発生する必要があり、オブジェクトが互いに干渉しているかどうか、またはどこで干渉しているかはわかりません。

変更を保存しようとすると、次の警告が表示されます。

System.InvalidOperationException: データベースへの変更は正常にコミットされましたが、オブジェクト コンテキストの更新中にエラーが発生しました。ObjectContext が矛盾した状態にある可能性があります。内部例外メッセージ: オブジェクトのキー値が ObjectStateManager 内の別のオブジェクトと競合するため、AcceptChanges を続行できません。AcceptChanges を呼び出す前に、キー値が一意であることを確認してください。

私がグーグルで読んだことから、人々は多くの1回限りの解決策を見つけました(競合するキーと関係があることはめったにありません)、そして彼らは通常、ヒントが何であるかを投稿しません(もちろん、何もないよりはましです) )。

私がはっきりしていないのは、この問題の原因を突き止める方法です。

さまざまな場所で多くのレコードを更新し、それらを範囲外にします。.NET コンパイラは、GC を通過させずにこれらのオブジェクトを追跡する方法を知っているので、最後にすべてをコミットできると思います。そして、すべての変更はデータベースのあとがきで終わるようです。

例:

            // create new A, SA for new incoming tasks
            SF_SUB_AREA sa = null;
            SF_AREA a = null;
            if (isNewSA)   // new SA
            {
                areaID = MakeSalesForceGUID();
                a = new SF_AREA
                {
                    ID = areaID,
                    DESCRIPTION = t.DESCRIPTION,
                    CU_NUMBER = Convert.ToString(t.CU_NUMBER),
                    FC = t.FC,
                    PROJECT = cp.ID,
                    DELETE_FLAG = "I"
                };
                ctx.SF_AREA.AddObject(a);


                SAID = MakeSalesForceGUID();
                sa= new SF_SUB_AREA
                {
                    ID = SAID,
                    PROJECT_REGION = t.CR,
                    AREA = areaID,
                    DELETE_FLAG = "I"
                };
                ctx.SF_SUB_AREA.AddObject(sa);
            }
            else       // old SA
            {
                List<SF_AREA> lia = (from a2 in ctx.SF_AREA
                                             join a2 in ctx.SF_SUB_AREA on a2.ID equals sa2.AREA
                                             where sa2.ID == t.SUB_AREA
                                             select ct2).ToList();
                if ((lia != null) && (lia.Count > 0))
                {
                    a = lia[0];
                    a.DELETE_FLAG = "U";
                    a.CLIENT_UNIT_NUMBER = Convert.ToString(t.CU_NUMBER);
                    a.DESCRIPTION = t.DESCRIPTION;
                    a.FC = t.FC;
                    a.PROJECT = cp.ID;
                } // TODO: throw an error here for else block

                List<SF_SUB_AREA> lisa = (from sa2 in ctx.SF_SUB_AREA
                                                              where sa2.ID == t.SUB_AREA
                                                              select sa2).ToList();
                if ((lisa != null) && (lisa.Count > 0))
                {
                    sa = lisa[0];
                    sa.PROJECT_REGION = t.AREA;
                    sa.AREA = lisa[0].AREA;
                    sa.DELETE_FLAG = "U";
                }
            }
            ...
            ctx.SaveChanges(); // left out the try/catch

現在、何かをコミットするたびに新しいコンテキストを作成していますが、これが賢明かどうかはわかりません。

            foreach (SF_MOVE_ORDER mo in liMO ) {
                using (SFEntitiesRM ctx2 = new SFEntitiesRM())  // new context for every MO since it goes into an unknown state after every commit
                {
                    List<SF_CLIENT_PROJECT> liCP = (from cp in ctx2.SF_CLIENT_PROJECT
                                                    where cp.ID == mo.CLIENT_PROJECT
                                                    select cp).ToList();
                    if ((liCP != null) && (liCP.Count > 0))
                    {
                        PerformMoveOrder(mo, liCP[0], ctx2);
                    }
                }
            }
4

1 に答える 1

1

通常、このようなエラーが発生する場合は、1 つのオブジェクトを保存し、一度に 1 つずつ複雑さを構築することから始めるのが最善です。そうすれば、問題がどこにあるのかを把握し始めることができます。予期していなかったオブジェクト グラフのどこかに配置される可能性があります。しかし、LINQ の更新全体をコンテキストでスローし続けるだけではありません。それを小さな保存に分割し、最大のグラフに再構築すると、エラーが見つかります。

于 2012-07-27T15:44:05.873 に答える