0

概要: .attachto を使用した複数の多対多の関係の追加は正常に機能しますが、.add ではなく .remove であることを除いて、同じコードを使用すると、次のような恐ろしい事態が発生します。

同じキーを持つオブジェクトが ObjectStateManager に既に存在します。ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません。

これがコードです。フォーム フィールドに基づいて、1 つは非表示 (以前のトレーナーの値を使用)、もう 1 つは非表示、トレーナーのリストを循環して選択または選択解除されたトレーナーを確認し、クライアントとの間の多対多の関係を追加または削除します。トレーナー:

Protected Sub dsClient_Updated(sender As Object, e As System.Web.UI.WebControls.EntityDataSourceChangedEventArgs) Handles dsClient.Updated
    Dim Client As Client = e.Entity
    Dim Trainers As IEnumerable(Of aspnet_Users), CurrentTrainer As String, PrevTrainer As String

    ' Select list of Trainers
    Trainers = From S In FitnessDB.aspnet_Users

    For Each Trainer As aspnet_Users In Trainers
        CurrentTrainer = Request.Form(Trainer.UserName)
        PrevTrainer = Request.Form("Prev_" & Trainer.UserName)
        ' Check if Trainer has been deleted
        If CurrentTrainer = "" And PrevTrainer <> "" Then
            ' Trainer previously existed, delete
            FitnessDB.Detach(Trainer)
            e.Context.AttachTo ("aspnet_Users", Trainer)
            Client.aspnet_Users.Remove (Trainer)
        ElseIf CurrentTrainer <> "" And PrevTrainer = "" Then
            ' Doesn't exist, add
            FitnessDB.Detach(Trainer)
            e.Context.AttachTo ("aspnet_Users", Trainer)
            Client.aspnet_Users.Add (Trainer)
        End If
    Next
    e.Context.SaveChanges()
End Sub

複数のトレーナーを選択して追加できます。それは循環します:

FitnessDB.Detach(Trainer)
e.Context.AttachTo ("aspnet_Users", Trainer)
Client.aspnet_Users.Add (Trainer)

問題なく、新しい関係がうまく追加されました。トレーナーを 1 つだけ削除すると、問題なく動作します。しかし、以下のコードを使用して複数のトレーナーを削除しようとすると

FitnessDB.Detach(Trainer)
e.Context.AttachTo ("aspnet_Users", Trainer) <-- Error: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Client.aspnet_Users.Remove (Trainer)

次に、2回目の削除試行でエラーが発生します。

だから私を困惑させているのは、.add'ingのときに複数の「トレーナー」に正常に.attachtoできるのに、.remove'ingのときにできないのはなぜですか?

どんな提案でも大歓迎です。

4

1 に答える 1

1

この時点で、これは Entity Framework 内のバグであるという暫定的な結論に達しました。さまざまな理由から、ここで詳しく説明するには疲れています。

ただし、回避策を見つけました。トレーナーが削除することを確認していた上記のコード セクションを削除し、次のように置き換えました。

For Each Trainer As aspnet_Users In Client.aspnet_Users
    If Request.Form(Trainer.UserName) = "" Then DeleteTrainers.Add (Trainer)
Next
For Each Trainer As aspnet_Users In DeleteTrainers
    Client.aspnet_Users.Remove (Trainer)
Next

書き直されたサブ全体は次のようになります。

Protected Sub dsClient_Updated(sender As Object, e As System.Web.UI.WebControls.EntityDataSourceChangedEventArgs) Handles dsClient.Updated
    Dim Client As Client = e.Entity
    Dim DeleteTrainers As New List(Of aspnet_Users), CurrentTrainer As String, PrevTrainer As String

    ' Check for trainers that have been removed
    For Each Trainer As aspnet_Users In Client.aspnet_Users
        If Request.Form(Trainer.UserName) = "" Then DeleteTrainers.Add (Trainer)
    Next
    For Each Trainer As aspnet_Users In DeleteTrainers
        Client.aspnet_Users.Remove (Trainer)
    Next

    ' Check for trainers to add
    For Each Trainer As aspnet_Users In FitnessDB.aspnet_Users
        CurrentTrainer = Request.Form(Trainer.UserName)
        PrevTrainer = Request.Form("Prev_" & Trainer.UserName)
        If CurrentTrainer <> "" And PrevTrainer = "" Then
            ' Doesn't exist, add
            FitnessDB.Detach(Trainer)
            e.Context.AttachTo ("aspnet_Users", Trainer)
            Client.aspnet_Users.Add (Trainer)
        End If
    Next
    e.Context.SaveChanges()
End

Client.aspnet_Users を使用するように移行することで、同じコンテキスト (e.context) 内にとどまることができるため、FitnessDB コンテキストから e.context にデタッチして再アタッチしなければならないという問題が解消されます。エンティティ トレーナーを削除します。

最初に関連付けられたトレーナーのテーブルをループしてリストに追加することで、リストをループしてそれらを正常に削除できます (ループでエラーが発生するため、テーブル ループ内で直接削除することはできません)。 「コレクションが変更されました。列挙操作が実行されない可能性があります。」.

これがいつか誰かに役立つことを願っています。

于 2013-08-23T03:11:17.173 に答える