5

Entity Framework Code First を使用しており、必要のないときに Insert、Update、および Delete のエンティティの変更をロールバックしようとして問題が発生していSaveChanges()ます。

具体的には、いくつかの補助テーブルを変更するために、TableEditor として使用している datagridview があります。datagridview は にバインドされていDbSet<TEntity>ます。

Update のロールバックは正常に機能しているようです。currentValues を OriginalValues に戻すように設定し、状態を に変更しunchangedます。

レコードがグリッドビューに挿入されると (ただし、変更は保存されません)、エンティティ クラスには表示されず、二度と表示されません...だから、dbSet に到達しないと思います。ロールバックはありません。これに必要ですか?

しかし、私の主な問題は Delete にあります:

私が理解していることから、レコードが「削除」されると (例: )、 SaveChanges が呼び出されるまで、tableData.Remove(currentItem);単に削除対象としてマークされます。State をdeletedback からに変更するunchangedと、ロールバックが処理されるはずですよね?

レコードは再び表示されますが、レコードのナビゲーション プロパティは失われています。(つまり、外部キーと他のエンティティとの必要な関係を含む列)。どうしてこれなの??!

これが私がこれまでに持っているものです:

    public void RollbackChanges(DbEntityEntry entry)
    {
        if (entry.State == EntityState.Modified)
        {
            foreach (var propertyName in entry.OriginalValues.PropertyNames)
            {
                entry.CurrentValues[propertyName] = entry.OriginalValues[propertyName];
            }
            entry.State = EntityState.Unchanged;
        }
        else if (entry.State == EntityState.Deleted)
        {
            entry.State = EntityState.Unchanged;
        }
        else if ((entry.State == EntityState.Added) || (entry.State == EntityState.Detached))
        {
            MessageBox.Show("I don't think this ever happens?");
        }
    }

使用例:

    foreach (var entity in db.CertificationDecisions)
                {
                    DbEntityEntry entry = db.Entry(entity );
                    if (entry.State != EntityState.Unchanged)
                    {
                        RollbackChanges(entry);
                    }
                }

ナビゲーション プロパティがレコードから消える理由はありますか? (または、それらを取り戻すために何ができますか?)


編集: 使用に関する@Chris Refresh

私はDbContextを使用しているので、ロールバック メソッドを次の行に置き換えました。

((IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.StoreWins, db.CertificationDecisions);

ただし、レコードがまだ欠落しているため、これはコンテキストをリロードしていないようです...Refresh間違って使用していますか?

これは私の問題の可能な解決策のように思えますが、なぜナビゲーション プロパティが削除されるのか疑問に思っています。

4

2 に答える 2

3

ナビゲーション プロパティがレコードから消える理由はありますか?

ナビゲーション プロパティは、外部キー関係のために削除される可能性が最も高いです。次のクラスを取ります。

public class Dog
{
  public guid ID { get; set; }
  public string Title { get; set; }
}

public class Person
{
  public guid ID { get; set; }

  public ICollection<Dog> FavoriteDogs { get; set; }
}

データベースでは、FavoriteDogs のコレクションは Person と Dog の両方への参照を持つテーブルですが、ナビゲーション プロパティによって自動的に非表示になります。の状態が削除済みに設定されている場合、EF は自動的に参照エンティティを削除済みとしてマークします。エンティティが Unchanged に設定されている場合、Entity Framework はこれらの参照エンティティを Unchanged に設定しません。そのために必要な参照整合性がないためです (削除操作の場合のみ)。

または、それらを取り戻すために何ができますか?

現在、これを行う EF 内の自動化されたプロセスはありません。 参照エンティティを手動で変更する方法さえあるとは思いません。また、新しいEntity Framework 5 は、の状態を表示または変更する方法を公開していませんDbRefrenceEntry

多分DbReferenceEntryを試してください。リロードします。

于 2012-12-19T18:42:28.893 に答える
2

これは実際には私の質問に対する答えではありませんが、これまでのところ私のために働いているように見える代替手段です(誰かがこの質問に対する答えを探している場合):

基本的に、新しいコンテキストを作成し、新しいコンテキストからフォームにエンティティを渡します。フォームをキャンセルすると、コンテキストを破棄するだけなので、変更は保存されません (ロールバックする必要はありません)。フォームを保存すると、新しいコンテキストからの変更が保存されますが、元のコンテキストに変更を認識させる必要があります。

これは.Refresh、新しいエンティティを正常に見つけるように見えますが、削除されたエンティティは削除しません。次に、エンティティをループしてデータベースの値と比較します。

データベースが「null」を返す場合、エンティティがデータベースで削除されており、コンテキストから削除する必要があることがわかります。(ただし、ループ内で削除することはできません。列挙中にコンテキストの内容を変更しようとするとエラーが発生するため、代わりにリストにエントリを追加して、後で別のループでコンテキストから削除します.)

以下はコードです:(
注:これが良い解決策であるという保証はありませんが、私にとってはうまくいっているようです)

            using (FmlaManagementContext auxDb = new FmlaManagementContext())
            {
                AuxiliaryTableEditor<State> statesTableEditor = new AuxiliaryTableEditor<State>(auxDb.States);
                if (statesTableEditor.ShowDialog() != DialogResult.OK)
                {
                    auxDb.Dispose();
                }
                else
                {
                    auxDb.SaveChanges();
                    auxDb.Dispose();

                    //refresh to pick up any new
                    ((IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.StoreWins, db.States);

                    //loop through to remove deleted
                    List<State> nulls = new List<State>();
                    foreach (State state in db.States.Local)
                    {
                        DbEntityEntry entry = db.Entry(state);
                        DbPropertyValues databaseValues = entry.GetDatabaseValues();
                        if (databaseValues == null)
                        {
                            nulls.Add(state); 
                        }
                    }
                    foreach (State state in nulls)
                    {
                        db.States.Remove(state);
                    }
                }
            }

これを変更したり、問題を見つけたりした場合は、戻ってきて更新することを忘れないようにします...

于 2012-12-21T21:31:29.503 に答える