web-dev-qa-db-ja.com

DbContext AutoDetectChangesEnabledが変更の検出をfalseに設定

私は少し困惑しています。私が読んだものからDbContext.AutoDetectChangesEnabledfalseに設定すると、データベースに送信される変更を識別するためにDbContext.DetectChangesを呼び出す必要がある変更追跡が無効になります。

ただし、以下のログから、設定がfalseに設定されていても、dbContexts変更トラッカーによって変更が登録されていることがわかります。

何か不足していますか?

Entity Frameworkバージョン:5.0.0.0

DbContextクラス

public class ProjectContext : DbContext {
    public DbSet<Project> Projects {get;set;}
}

コントローラークラス

private ProjectContext db = new ProjectContext();

public method(){
    Project p = new Project("uniqueName");
    db.Configuration.AutoDetectChangesEnabled = false;
    db.Projects.Add(p);
    DebugChangeTracker();
    db.SaveChanges();

    db.Projects.First().ProjectName = "a differentName!";
    DebugChangeTracker();
    db.SaveChanges();
}

ロギング方法

    private void DebugChangeTracker()
    {
        var path = "C:\\mypath\\";
        path = path + Util.GetMsSinceEpoch().ToString() + "changeTracker.log";

        using (StreamWriter sw = new StreamWriter(path))
        {
            var changeTracker = db.ChangeTracker;
            var entries = changeTracker.Entries();
            foreach (var x in entries)
            {

                var name = x.Entity.ToString();
                var state = x.State;

                sw.WriteLine("");
                sw.WriteLine("***Entity Name: " + name +
                             "is in a state of " + state);
                var currentValues = x.CurrentValues;
                sw.WriteLine("***CurrentValues***");
                PrintPropertyValues(currentValues,sw);
                if (state != EntityState.Added)
                {
                    sw.WriteLine("***Original Values***");
                    PrintPropertyValues(x.OriginalValues,sw);
                }
            }
        }
    }

最初のログ

***Entity Name: Models.Projectis in a state of Added
***CurrentValues***
ProjectId:0
ProjectName:uniqueName

2番目のログ

***Entity Name: Models.Projectis in a state of Modified
***CurrentValues***
ProjectId:1
ProjectName:uniqueName
***Original Values***
ProjectId:1
ProjectName:a differentName!
41
Jesse

AutoDetectChangesEnabledfalseに設定しても、変更追跡は無効になりません。 (これがAsNoTracking()拡張メソッドが行うことです。)それは、そうでなければ多くのDetectChanges AP​​Iメソッドで発生するDbContextの自動呼び出しを無効にします。

ただし、DetectChangesは変更追跡に参加する唯一の方法ではありません。ただし、必要な適切な場所で手動で呼び出さないと、追跡されたエンティティの状態が不完全または間違っているため、データが誤って保存されます。

あなたの場合、Addedmethodに設定されている場合でも、db.Projects.Add(p)のみを呼び出すため、AutoDetectChangesEnabledの最初の部分の状態falseが期待されます。 (コードに行がありませんが、コピーアンドペーストのエラーだと思います。)DbContext AP​​Iからメソッドを呼び出すと、変更が正しく追跡され、状態が正しい場合はトラッカーの状態が正しくなります。 Addの呼び出し前。

または言い換えると、APIメソッドを呼び出しても、正しい状態が間違った状態に変わることはありません。しかし:AutoDetectChangesEnabledfalseである場合、AutoDetectChangesEnabledtrueである場合に、間違った状態を正しい状態に変えることもありません。

ただし、methodの2番目の部分では、POCOプロパティ値を変更しているだけです。この時点の後、変更トラッカーの状態は間違っています(Unchanged)、DetectChangesへの呼び出しなし(手動または-AutoDetectChangesEnabledtrueの場合-ChangeTracker.Entriesで自動的にまたはSaveChanges)調整されることはありません。その結果、変更されたプロパティ値はデータベースに保存されません。

最後のセクションでUnchanged状態について言及しているので、私は自分のテスト(および予想されるもの)について言及しています。 Modified状態になっている理由がわかりません。再現できません。

申し訳ありませんが、これが少しわかりにくい場合は。 アーサー・ビッカーズはそれをより良く説明できます。

無効にするときの自動変更検出と動作を理解し、習得するのはかなり難しく、通常、追跡された変更よりも複雑な変更のデフォルト(AutoDetectChangesEnabled = true)には触れません。最も単純なもの(ループ内でのエンティティの一括追加など)。

54
Slauma

Entity Framework CoreでAutoDetectChangesEnabledを探している人は、ChangeTracker insted of Configurationの下で見つけることができます

次のような使用法:

context.ChangeTracker.AutoDetectChangesEnabled = false;

//Do something here
context.PriceRecords.Add(newPriceRecord);

context.ChangeTracker.AutoDetectChangesEnabled = true;
9
Jiri Houzvicka

エンティティによる フレームワークの自動変更の記事の検出

彼らは言った:

大幅に改善される可能性がありますパフォーマンスの改善有効にするとoffsome cases

その記事からこの例を見てください

using (var context = new BloggingContext()) 
{ 
    try 
    { 
        context.Configuration.AutoDetectChangesEnabled = false; 

        // Make many calls in a loop 
        foreach (var blog in aLotOfBlogs) 
        { 
            context.Blogs.Add(blog); 
        } 
    } 
    finally 
    { 
        context.Configuration.AutoDetectChangesEnabled = true; 
    }
}

このコードは、DbSet.AddおよびDetectChangesメソッドの呼び出し中に発生するSaveChangesへの不要な呼び出しを回避します。

5