2011-11-15 5 views
3

子エンティティ(セグメント)のコレクションを持つ親エンティティ(治療)があります。私は治療を受け取り、それが新規か既存かを判断し、それをobjectContextに追加するか、それが新規か既存かに基づいてオブジェクトコンテキストに追加するsaveメソッドを持っています。EF "Save"メソッドで問題が発生しました。子エンティティのコレクションが変更されました

メインエンティティ内の子と同じことを行います。子エンティティのコレクションを反復処理し、必要に応じて追加または更新します。

私がやりたいことは、欠落している子オブジェクトを削除することです。問題は、親オブジェクトを更新してオブジェクトコンテキストにアタッチすると、親オブジェクトにDBからの子オブジェクトのコレクションがあることです。私が最初に渡したコレクションではありません。したがって、3つのセグメントを持つ治療法がある場合、コレクションから1つのセグメントを削除してから、治療法を保存メソッドに渡します。治療オブジェクトがobjectcontextにそれのセグメント数が2から3に変更されました。

私は間違っていますか?

public bool Save(Treatment myTreatment, modelEntities myObjectContext) 
     { 
      bool result = false; 

      if (myObjectContext != null) 
      { 
       if (myTreatment.Treatment_ID == 0) 
       { 
        myObjectContext.Treatments.AddObject(myTreatment); 
       } 
       else 
       { 
        if (myTreatment.EntityState == System.Data.EntityState.Detached) 
        { 
         myObjectContext.Treatments.Attach(myTreatment); 
        } 
        myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified); 
        myObjectContext.Treatments.ApplyCurrentValues(myTreatment); 
       } 

       foreach (Segment mySegment in myTreatment.Segments) 
       { 
        if (mySegment.SegmentID == 0) 
        { 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added); 
         myObjectContext.Segments.AddObject(mySegment); 
        } 
        else 
        { 
         if (mySegment.EntityState == System.Data.EntityState.Detached) 
         { 
          myObjectContext.Segments.Attach(mySegment); 
         } 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified); 
         myObjectContext.Segments.ApplyCurrentValues(mySegment); 
        } 
       } 
      } 

      result = (myObjectContext.SaveChanges(SaveOptions.None) != 0); 


      return result; 
     } 

* EDIT *下記のフィードバックの一部に基づいて* ** 、私が編集した "保存" 方法:ここで

は私の保存方法のコードです。新しいメソッドの実装は以下のとおりです。ただし、myTreatments.Segmentsコレクションから削除されたセグメントは削除されません。

public bool Save(Treatment myTreatment, tamcEntities myObjectContext) 
     { 
      bool result = false; 

      if (myObjectContext != null) 
      { 
       if (myTreatment.Treatment_ID == 0) 
       { 
        myObjectContext.Treatments.AddObject(myTreatment); 
       } 
       else 
       { 
        if (myTreatment.EntityState == System.Data.EntityState.Detached) 
        { 
         myObjectContext.Treatments.Attach(myTreatment); 
        } 
        myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified); 
       } 

       foreach (Segment mySegment in myTreatment.Segments) 
       { 
        if (mySegment.SegmentID == 0) 
        { 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added); 
        } 
        else 
        { 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified); 
        } 
       } 
      } 

      result = (myObjectContext.SaveChanges(SaveOptions.None) != 0); 


      return result; 
     } 

FINAL EDIT 私は最終的にそれが動作するようになってきました。ここでは、正常に動作している更新されたSaveメソッドを示します。私はセグメントの初期リストをローカル変数に保存してから、それをDBにアタッチされた後にmyTreatments.Segmentsリストと比較し、削除されるセグメントのリストを決定し、そのリストを反復してマッチングを削除しなければならなかった新しく添付されたmyTreatment.Segmentsリストのセグメント。また、以下のいくつかのレスポンダからのアドバイスごとにobjectcontextの受け渡しを削除しました。

public bool Save(Treatment myTreatment) 
     { 
      bool result = false; 


      List<Segment> myTreatmentSegments = myTreatment.Segments.ToList<Segment>(); 

      using (tamcEntities myObjectContext = new tamcEntities()) 
      { 
       if (myTreatment.Treatment_ID == 0) 
       { 
        myObjectContext.Treatments.AddObject(myTreatment); 
       } 
       else 
       { 
        if (myTreatment.EntityState == System.Data.EntityState.Detached) 
        { 
         myObjectContext.Treatments.Attach(myTreatment); 
        } 
        myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified); 
       } 

       // Iterate over all the segments in myTreatment.Segments and update their EntityState to force 
       // them to update in the DB. 
       foreach (Segment mySegment in myTreatment.Segments) 
       { 
        if (mySegment.SegmentID == 0) 
        { 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added); 
        } 
        else 
        { 
         myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified); 
        } 
       } 

       // Create list of "Deleted" segments 
       List<Segment> myDeletedSegments = new List<Segment>(); 
       foreach (Segment mySegment in myTreatment.Segments) 
       { 
        if (!myTreatmentSegments.Contains(mySegment)) 
        { 
         myDeletedSegments.Add(mySegment); 
        } 
       } 
       // Iterate over list of "Deleted" segments and delete the matching segment from myTreatment.Segments 
       foreach (Segment mySegment in myDeletedSegments) 
       { 
        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Deleted); 
       } 

       result = (myObjectContext.SaveChanges(SaveOptions.None) != 0); 
      } 
      return result; 
     } 

答えて

1

多分私は何かを見逃しているかもしれませんが、このコードはあまりにも面倒です。 ここで間違ったトラックにいて、あなたを誤解している場合は、私に同行してください。

削除する必要があるオブジェクトについては、削除したアイテムのみを保持する別のコレクションに保存することをお勧めします。あなたはObjectContextから削除することができます。

ApplyCurrentValuesを呼び出す代わりに、私は単にmyObjectContext.SaveChanges()を呼び出します。ApplyCurrentValuesは、この場合、保存しているものとの関係を持つ他のエンティティを処理していないという欠点があります。 内のオブジェクトと同じキーを持つのObjectContextに供給される物体から

MSDN documentation:

コピースカラー値。他のSegmentsとして

はすでに()のSaveChangesを使用することによって、あなたの Treatmentに添付されている、彼らは自動的にコンテキストに追加したり、彼らがすでに追加された場合に更新されます。

これにより、EntityStateの手動処理が不要になります。

EDIT:あなたの中にこれが起こっている場所 は、今私が見る ...

どこかのコード - この保存()メソッドの外で - あなたはセグメントのインスタンスを削除しています。この問題は、ObjectContextがであり、これが完全に認識されていないという問題にあります。それはどうすれば...?

あなたは、特定のセグメントエンティティのインスタンスを破壊しているかもしれませんが、実体はを外れているとして、これは彼らがのObjectContextへの接続なしを有することを意味します。したがって、文脈はあなたが何をしたのか全く分かりません。

結果として、あなたはそれにトリマントを添付するとき、削除について知りませんし、何も起こらなかったように治療にそれらを再び追加するので、すべてのセグメントが生きていると文脈は依然として信じています。

ソリューション: 私はすでに上で述べたように、あなたはあなたの削除したエンティティのトラックを維持する必要があります。治療のインスタンスからそれを

  1. Remove():あなたはセグメントを削除し、それらのスポットでは、

    は、実際にそれらを削除しますが、しないでください。

  2. 「削除済み」セグメントをコレクションに移動します(例: List<Segment>。それをdeletedSegmentsと呼ぶことにしよう。
  3. Save()メソッド
  4. にこのコレクションをループし、ObjectContect.Delete()を渡してください。
  5. 残りの保存ロジックは必要に応じて行います。トーマス・ボレーセックは上述のよう

また、ローカル複数のコンテキストを使用することが好ましいです。それを引数として渡すのではなく、saveメソッド内でのみ作成してください。

+0

オリジナルの投稿を変更して、あなたのコメントと@Shirazのコメントを考慮して、新しい「保存」方法を表示しました。しかし、私はまだセグメントの1つを削除できません。問題は、治療が最初にメソッドに入るときに、2つのセグメントを含み、それが接続されると、3つのセグメント(2つが渡されただけでなく、3番目のセグメントがDBから "失われた/削除された ")。だからそれは最終的に "SaveChanges()"を呼び出すとき、それはそのコレクションの3つすべてを持っていて、もともと含まれていなかったものを削除しません。 –

+0

最新の編集をご覧ください。 –

1

もう一度お試しください。

「削除」と言うときは、削除済みとしてマークすることを意味します。

ChangeObjectStateを呼び出して状態を変更済みに変更しています。

送信すると3つ、削除されたもの、変更されたもの、変更されないものの1つです。変更を保存する前に、すべてが変更済みとしてマークされます。

+0

foreachセクションを削除しても、セグメントの削除には影響しません。さらに、セグメントが削除されると、セグメントのEntityStateが「変更されていない」ため、個々のセグメントに加えられた更新はすべてdbに伝播されません。私はそれぞれをループして、EntityStateを "Modified"に設定して、実際にDBに変更を加える必要があります。私は彼らがつけられているという議論を見ることができ、再び付く必要はありません。しかし、私はまだエンティティ状態をModifiedに設定する部分を行う必要があります。 –

+0

問題は、 "myTreatment"を添付すると、DBからのセグメントのコレクションで更新されるということです。だから、2つのセグメントしかない場合(私が1つを削除したため)、治療を添付すると、突然 "3"になります。面白いのは、セグメントを追加すると、追加されたセグメントが削除されないということです。それは「不足している」セグメントをもたらすだけである。私はセグメントを格納するためのtemp配列を作成してからmyTreatment.Segmentsを後で再び比較することができますが、EFがあなたのためにこれらの種類のものを処理すると思われたようです。だから私は間違っていることが明らかなものがあると思った。 –

関連する問題