12

私はこの問題で1週間以上立ち往生しています。うまくいけば、誰かが私を正しい方向に向けることができます。

まず、スキーマの簡単な説明から始めます。

資産1--->1住所*->1地域*->1地域*->1国

パッケージ1->*アセット

自己追跡エンティティ(STE)+WCFを使用します。

手順:

  1. アセットのリストについては、データストアに電話してください。
  2. パッケージのリストについては、データストアに電話してください。
  3. ユーザーがパッケージを選択し、それにいくつかのアセットを割り当てます。
  4. パッケージを保存します。

ステップ2では、呼び出しはアドレスの積極的な読み込みを使用します。

from p in context.Assets.Include("Address.Area.Region.Country")

これは、電話をかけようとしたときのエラーです

context.Packages.ApplyChanges(package)

オブジェクトのキー値がObjectStateManager内の別のオブジェクトと競合しているため、AcceptChangesを続行できません。AcceptChangesを呼び出す前に、キー値が一意であることを確認してください。

編集

詮索した後、これはSTEの問題であることがわかりました。ここで概説したように、同じエンティティの複数のインスタンスを含むグラフを永続化できないという問題があります。これが私の質問です。

エンティティコレクションにエンティティを追加するにはどうすればよいですか。新しいエンティティには、すでにコレクションにあるものと同じキーを含む関連エンティティが含まれている場合があります。つまり、同じ住所、地域、地域、または国のエンティティを含む可能性のある新しいアセットを追加します。

これが私の制約です:

  1. UIに影響するため、ナビゲーションコレクションを使用する必要があります。
  2. データセットが大きすぎるため、関係するすべてのエンティティをプリフェッチできません。
  3. 履歴を保持し、それを使用して変更を「元に戻す」には、いつでもエンティティのスナップショットを撮ることができなければなりません。

私はDiegoBVegaによって提案された可能な解決策を知っいますが、それらは私の解決策に使用できるオプションではありません。他に何かアイデアはありますか?

4

5 に答える 5

8

参考までに、私は EF フォーラムで既に回答した内容に対する追加の提案を含むブログ投稿を書きました。ブログ記事はこちら。

于 2010-10-06T16:52:43.440 に答える
8

私の言いたいことがわかっているなら、ORM-sをあきらめて通常のアクセスに戻ることを考えましたか:-)

冗談ではありません - そのような単一の問題 (何よりも ORM バグの匂いがします) に取り組むまでに、通常の sproc 呼び出しとより簡単なデータ型変換を行うために独自の 5 ~ 10 個の関数をロールアウトできたはずです。完全にコントロールできる状態に戻っており、安定するのにさらに 5 年かかる図書館に悩まされることはありません。

特に、非常にクリーンなスキーマを持っているように見えるため、非常に単純なクエリと簡単な更新を意味します。

于 2010-08-05T12:18:45.697 に答える
3

私は同じ問題に遭遇し、最終的に解決策を思いつきました。基本的な考え方は、特定のナビゲーション クラス タイプが ObjectContext にアタッチされないようにすることです。これが私がしたことです:

  1. Context.tt テンプレートを変更して、SelfTrackingEntitiesContextExtensions クラスを部分的にしました。
  2. 2 つの ApplyChanges 関数を新しく作成した Custom.Context.Extension.cs にコピーし、名前を CustomApplyChanges に変更します。それぞれに Type の配列として 1 つの追加パラメータがあります

public static void CustomApplyChanges(この ObjectContext コンテキスト、文字列 entitySetName、TEntity エンティティ、Type[] excludeTypes ) TEntity : IObjectWithChangeTracker

  1. 条件を for ループに追加して、excludeTypes 配列に含まれるクラス タイプを除外します。

region ハンドルの初期エンティティ状態

foreach (IObjectWithChangeTracker changedEntity in entityIndex.AllEntities.Where(x => x.ChangeTracker.State == ObjectState.Deleted && !excludeTypes.Contains(x.GetType()))) { HandleDeletedEntity(context, entityIndex, allRelationships, changedEntity); }

foreach (IObjectWithChangeTracker changedEntity in entityIndex.AllEntities.Where(x => x.ChangeTracker.State != ObjectState.Deleted && !excludeTypes.Contains(x.GetType()))) { HandleEntity(context, entityIndex, allRelationships, changedEntity); }

エンドリージョン

  1. 使い方

Type[] excludeTypes = { typeof(Asset), typeof(Address), typeof(Region)};

rep.Entities.CustomApplyChanges(エンティティ、excludeTypes); var changedEntry = rep.Context.ObjectStateManager.GetObjectStateEntries>(System.Data.EntityState.Added | System.Data.EntityState.Modified | System.Data.EntityState.Deleted); foreach (var e in changedEntry) { if (excludeTypes.Any(c => c == e.Entity.GetType())) { rep.Context.Detach(e.Entity); //変更されていないオブジェクトを切り離します } }

于 2010-08-13T18:46:11.100 に答える