0

Edit Controller アクションで、オブジェクトを投稿して更新します。

 [HttpPost]
 public virtual ActionResult Edit(Case myCase){
      var currentDocuments = db.CaseDocuments.Where(p => p.idCase == myCase.idCase);

            foreach (CaseDocument docInDB in currentDocuments )
            {
                var deleteDoc = true;

                foreach (CaseDocument docNew in myCase.CaseDocuments )
                {
                    if (docNew.idDocument == docInDB.idDocument)
                        deleteDoc = false;
                }
                if (deleteDoc )
                    db.CaseDocuments.Remove(docInDB);
            }

            foreach (CaseDocument pc in myCase.CaseDocuments)
            {
                if (pc.idDocument == 0)
                    db.CaseDocuments.Add(pc);
                else
                    db.Entry(pc).State = EntityState.Modified;    
            }

           *** **db.Entry(myCase).State = EntityState.Modified;**  //THIS LINE
            db.SaveChanges();
 }

モデルにはのCaseコレクションがありDocuments、ケース モデルと一緒に掲載されています。

アクションに入るとすぐに、コレクション内のドキュメントの数を数えることができ、3 つあるとしましょう。

次に、データベースからドキュメントを削除する必要があるかどうかを確認するために (ユーザーが UI からドキュメントを削除したため)、その場合のドキュメントをデータベースから次のように取得する必要があります。

var currentDocuments = db.CaseDocuments.Where(p => p.idCase == myCase.idCase);

そして、ここで奇妙なことが始まります。そのステートメントを実行するとすぐにmyCase.Documents、データベースにあるものがロードされます(4つあるとしましょう)!! そのため、2 つのコレクションを比較することはできません (ドキュメントが削除されたかどうかを検出し、データベースから削除するため)。

私が必要としているのは、ケース モデルの編集アクション中に、そのドキュメントを作成/更新/変更する必要があることです。これを別の角度から見る必要がありますか?私がしていることは間違っていますか?

編集: コメントの後、myCase を Modified としてマークした行が先頭にあることに気付きました。これがその動作の理由であると思います。

今、その行を db.SaveChanges() の直前に移動すると、その問題は修正されましたが、db.Entry(myCase).State = EntityState.Modified;ObjectStateManager に同じキーを持つオブジェクトが既に存在します。

ここで何が間違っていますか?このコードは見栄えが悪いです。

4

1 に答える 1

1

このようにしてみてください:

 [HttpPost]
 public virtual ActionResult Edit(Case myCase){
     var currentDocumentIds = db.CaseDocuments
                                .Where(p => p.idCase == myCase.idCase)
                                .Select(p => p.idDocument);

     foreach (int idInDb in currentDocumentsIds.Where(i => !myCase.CaseDocuments
                                                                  .Any(ci => ci.idDocumnet == i))
     {
         var docToDelete = new CaseDocument { idDocument = idInDb };
         db.CaseDocuments.Remove(docToDelete);
     }

     foreach (CaseDocument pc in myCase.CaseDocuments)
     {
         if (pc.idDocument == 0)
            db.CaseDocuments.Add(pc);
         else
            db.Entry(pc).State = EntityState.Modified;    
     }

     db.Entry(myCase).State = EntityState.Modified;
     db.SaveChanges();
}

編集: このコードとあなたのコードの違いは、既存のドキュメントでの動作方法です。それらをロードするのではなく、ID のみをロードします。このようにして、データベースからのデータ転送を節約できますが、その例外を回避するのにも役立ちます。データベースからドキュメントをロードすると、すでにコンテキストにアタッチされていますが、これを呼び出そうとすると、次のようになります。

db.Entry(pc).State = EntityState.Modified; 

同じキーを持つドキュメントの別のインスタンスをコンテキストに添付しようとします。これは許可されていません。コンテキストは、一意のキーを持つ単一のインスタンスのみをアタッチできます。

于 2012-04-23T10:44:05.473 に答える