2012-05-10 13 views
8

私はObjectContextにRejectChanges()メソッドがあるRIAサービスを使っていました。しかし、私は現在デスクトップアプリケーションでEF 4.4で作業していますが、その方法を見つけることはできません。だから、私の質問は:コレクションの一括CrUD操作を行うことができるシナリオでは、どのようにすべての変更を元に戻すのだろうか?私はContextを再作成してデータを再度取得することができますが、変更を1-2エンティティに戻す必要がある場合は、その必要はありません。DbContextとRejectChanges

変更を拒否する最も良い方法は何ですか?また、コンテキストが何か(IsBusy)を行っているかどうかをどうやって知ることができますか?

答えて

11

EFには直接「拒否変更」操作はありません。エンティティエントリをChangeTracker/ObjectStateManagerに移動し、現在の値を変更されたエンティティの元の値で上書きすることができます。また、追加されたエンティティを切り離して、削除されたエンティティを変更しない状態に戻すこともできますが、すべての機能は主に独立した関連(リレーション)の状態を変更しなかった場合にのみ機能します。リレーションを扱う場合は、リレーションシップを元に戻す必要があるため、すべてが複雑になります。そのような場合は、データをリロードする方が簡単です。あなたは、ライブデータの変更を許可し、EFは、そのロジックをする - 私は主な問題は、あなたが実体とどのように動作するかの方法であると思います。この場合、

foreach (var entry in context.ChangeTracker 
          .Entries<YourEntityType>() 
          .Where(e => e.State == EntityState.Modified)) 
{ 
    entry.CurrentValues.SetValues(entry.OriginalValues); 
} 

:あなたはこれを試すことができDbContext APIの変更を元に戻すために

変更が実行されたときにデータを一貫性を保ちますが、後でそれらの変更が保存されないようにすることができます。この場合、次のいずれかを実行する必要があります

  • 破棄は、このロジックは、ライブデータ上で動作し、唯一のEFコンテキストにデータ変更をプッシュしないように(コンテキストを再作成することによって)セパレート
  • をデータを変更し、データセット全体をリロード修正が実際に確認されたとき

何かをすると文脈が何かしています。決してそれ自体は忙しくはありません。

+0

コンテキストを再作成することは良い解決策になります。しかし、私は関連するデータの同期に問題がありました。たとえば、私はViewAでCollectionAにCRUDを、ViewBにCOLlectionBにCRUDを持っていたとします。 CollectionBはCollectionAも参照しています。したがって、CollectionAとCollectionBの2つのContextオブジェクトがある場合、ViewAでCollectionAを変更すると、どのようにViewBを同期するのですか? 1つのコンテキストを持つ場合、すべてが同期しているため、実際には2つではなく、1つのインスタンスcollectionAのみで作業しているためです。 「グローバル」コンテキストを再作成すると、混乱が生じます。私は "グローバル"なコンテキストを使って間違いを犯しましたか? – Goran

+0

"Busy"に関しては、非同期マナーでLoadを発行した後に、別のLoadを発行しようとするとどうなりますか?この方法で私はそれが "Busy"かどうかを調べることができたので、新しいLoadをキューに入れることができました。 – Goran

+0

+1ほとんどの人が見逃しているように気付く。関係:状態のエントリコレクションを調べるだけでは取り上げられない変更を追跡することは可能です!=変更されていません。 (EF v6。) – mwardm

1

これが私の作品:

public void RejectChanges() { 
    var context = ((IObjectContextAdapter)this).ObjectContext; 
    foreach (var change in this.ChangeTracker.Entries()) { 
     if (change.State == EntityState.Modified) { 
      context.Refresh(RefreshMode.StoreWins, change.Entity); 
     } 
     if (change.State == EntityState.Added) { 
      context.Detach(change.Entity); 
     } 
    } 
} 

これはこのケースでDbContextを=

+1

削除されたエンティティはどうですか?また、他のユーザーによって変更されたエンティティに対しては、新しいデータをどのように取得しますか? – Goran

2

を、私はこれが古い質問です知っています。しかし、私の状況に合った答えはありません。コレクションの1つのエンティティだけで変更を拒否する必要がありました。これは私のために働いていたものです:これは昔の答えが、新しい訪問者に有用である可能性が

var objectContext = (myDbContext as IObjectContextAdapter).ObjectContext; 
    objectContext.Refresh(RefreshMode.StoreWins, partMaster); 
+0

質問はコレクションの変更に関するものであり、単一のエンティティではありませんでしたが、どの回答がどのように役立ったのか分かりません。あなたの上の答え(TheSoul75)は、あなたが示唆しているのとまったく同じですが、コレクション内のすべてのアイテムについてのみ行います。 – Goran

+0

Goran、コレクションのすべての変更が拒否された場合、私のデータは無効になります。コレクション内の項目の1つのみが元の値に戻す必要があります。私はもっ​​ときめ細かなアプローチが必要です。他の人が細かい制御を必要とすることがあることも知っています。私は、同様の要件を持つ他の人を助けるための答えを投稿しました。 – Tarzan

+1

まあ、foreachは使用しませんが、基本的に同じTechicque(StoreWinsでリフレッシュ)を使用しているので、ループを削除しただけで、答えに追加された値は表示されません。 – Goran

11
public void RejectChanges() 
     { 
      foreach (var entry in ChangeTracker.Entries()) 
      { 
       switch (entry.State) 
       { 
        case EntityState.Modified: 
         { 
          entry.CurrentValues.SetValues(entry.OriginalValues); 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Deleted: 
         { 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Added: 
         { 
          entry.State = EntityState.Detached; 
          break; 
         } 
       } 
      } 
     } 
+0

これは、データベースにぶつかることなくすべての州を処理する唯一の答えと思われます。 +1 – Dan

+0

参照のみを変更した場合はどうすればよいですか?特に純粋なm:nの場合、外部キーのプロパティが影響を受けていない場合 – springy76

0

.... リロード機能は、データソースからオブジェクトをリロードすると、既存の変更が上書きされます新たにロードされたエンティティは状態が変化しません。

public static void UndoEntityChanges(object Entity) 
{ 
    <EFModelContainer>.Entry(Entity).Reload(); 
}