2

ASP.NETアプリケーションで切断されたPOCOモデルを更新する際に問題が発生しました。

次のモデルがあるとしましょう。

  1. ユーザー
  2. 地区
  3. 注文

ユーザーは0以上の地区を担当でき、注文は地区に属し、ユーザーは注文の所有者になることができます。

ユーザーがログインすると、ユーザーと関連する地区が読み込まれます。その後、ユーザーは注文を読み込み、注文の所有者として自分自身を設定します。ユーザー(および関連する地区)と注文(および関連する地区)は、2つの異なるdbcontextを使用した2つの異なる呼び出しでロードされます。ユーザーが注文を割り当てた後で注文を保存したとき。オブジェクトのキー値が別のオブジェクトと競合しているため、acceptchangesを続行できないという例外が発生します。

同じ地区がユーザーが責任を負う地区のリストと注文の両方に表示される可能性があるため、これは奇妙なことではありません。

私はこの問題の解決策を高低で検索しましたが、私が見つけた答えは次のいずれかであるようです:

  1. 私の場合、ユーザーの地区となるオブジェクトの1つの関連エンティティをロードしないでください。
  2. オブジェクトを使用してユーザーを注文に割り当てるのではなく、注文オブジェクトに外部キーIDを設定するだけです。
  3. 明らかにそれを処理するので、nHibernateを使用してください。

1を試しましたが、うまくいきましたが、注文に関連付ける前に地区なしでユーザーをロードするか、浅いクローンを作成する必要があるため、これは間違っていると感じています。これは、この単純なケースでは問題ありませんが、問題は、私の場合、地区がグラフにさらに数回表示される可能性があることです。また、オブジェクトがあるので意味がないようですので、それらを接続してグラフを更新してみませんか。注文のグラフ全体が必要な理由は、すべての情報をユーザーに表示する必要があるためです。それで、すべてのオブジェクトを取得したので、これを機能させるために、なぜそれをリロードまたはシャロークローンする必要があるのですか?

STEを使用してみましたが、別のコンテキストによってロードされたグラフにオブジェクトをアタッチできないため、同じ問題が発生しました。だから私は正方形1に戻っています。

これはチュートリアルコード以外の一般的な問題だと思います。それでも、私はこれに対する良い解決策を見つけることができないようです。これは、私がどのような状況でもPOCO / EFの使用を理解していないか、この問題の答えを見つけるためにgoogleを使用するのが苦手だと思います。

JuliaLermanのO'Reillyから両方の「ProgrammingEntityFramework」の本を購入しましたが、これらの本でも私の問題を解決するものが見つからないようです。

一部のオブジェクトが繰り返され、必ずしも同じコンテキストからロードされるとは限らないグラフの処理方法に光を当てることができる人はいますか?

4

1 に答える 1

0

EFが同じキーを持つ2つのエンティティをコンテキストにアタッチすることを許可しない理由は、EFがどちらが「有効」であるかを知ることができないためです。例:Districtオブジェクトグラフに2つのオブジェクトがあり、両方ともキーが付いている場合がありますが、2つのオブジェクトのプロパティ値Id = 1は異なります。Nameデータベースに保存する必要のあるデータを表すのはどれですか?

これで、両方のオブジェクトが変更されていないかどうかは問題ではなく、状態のコンテキストにそれらをアタッチしたいだけで、Unchanged別のエンティティとの関係を確立したいと言うことができます。この特殊なケースでは、重複が問題にならない場合があります。しかし、重複するオブジェクトがあいまいさを引き起こしているかどうかをオブジェクトが判断しなければならない可能性のあるすべての状況やさまざまな状態に対処するには、単純に複雑すぎると思います。

とにかく、EFは、オブジェクト参照IDとキープロパティ値の間に厳密なIDマッピングを実装し、特定のキーがコンテキストにアタッチされた複数のエンティティを持つことを許可しません。

この種の問題に対する一般的な解決策はないと思います。私はあなたの質問の解決策に加えて、さらにいくつかのアイデアを追加することができます:

  • User注文をロードするコンテキストにを添付します。

    context.Users.Attach(user); // attaches user AND user.Districts
    var order = context.Orders.Include("Districts")
        .Single(o => o.Id == someOrderId);
    // because the user's Districts are attached, no District with the same key
    // will be loaded again, EF will use the already attached Districts to
    // populate the order.Districts collection, thus avoiding duplicate Districts
    order.Owner = user;
    context.SaveChanges();
    // it should work without exception
    
  • 特別な更新を実行するために必要なコンテキストにエンティティのみをアタッチします。

    using (var context = new MyContext())
    {
        var order = new Order { Id = order.Id };
        context.Orders.Attach(order);
        var user = new User { Id = user.Id };
        context.Users.Attach(user);
    
        order.Owner = user;
    
        context.SaveChanges();
    }
    

    Ownerこれは、関係を更新するのに十分です。この手順では、オブジェクトグラフ全体は必要ありません。必要なのは、リレーションシップを作成する必要のあるエンティティの正しい主キー値だけです。もちろん、保存する変更がさらにある場合や、正確に何を変更できたのかわからない場合は、それほど簡単には機能しません。

  • オブジェクトグラフをコンテキストに添付しないでください。代わりに、データベースに現在保存されているオブジェクトグラフを表す新しいエンティティをデータベースからロードします。次に、ロードされたグラフをデタッチされたオブジェクトグラフで更新し、ロードされた(=アタッチされた)グラフに適用された変更を保存します。この手順の例をここに示します。これは安全で非常に一般的なパターンですが(一般的ではありません)、複雑なオブジェクトグラフの場合は非常に複雑になる可能性があります。

  • オブジェクトグラフをトラバースし、重複するオブジェクトを一意のオブジェクトに置き換えます。たとえば、最初のオブジェクトだけを、見つけたタイプとキーで置き換えます。重複を置き換えるために検索する一意のオブジェクトの辞書を作成できます。例はここにあります。

于 2012-11-07T22:00:09.103 に答える