none
SaveChanges called frequently RRS feed

  • Question

  • Hi all,

    Hopefully this is an easy call for someone so I can stop digging... I'm not sure if this is normal behavior or if I have something "wired incorrectly" however I've been debugging a particular problem with an DbContext and I noticed that on many occasions there are calls to SaveChanges() on things like ".AsNoTracking()" and "Single/SingleOrDefault()" when nothing has changed and the context is only just opened... is this "normal" - what if there are changes you don't want saved yet... it doesn't feel right to me?

    I've tried with .Configuration.ProxyCreationEnabled = true/false,  lazyloading on/off and so on... doesn't seem to change things...

    Thanks in advance for any advice


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -

    Tuesday, March 31, 2015 12:03 AM

All replies

  • Hi noJedi,

    -->what if there are changes you don't want saved yet...

    I'm afraid you have some questions about the usage of ".AsNoTracking".

    What AsNoTracking Does
    Entity Framework exposes a number of  performance tuning options to help you optimise the performance of your applications. One of these tuning options is .AsNoTracking(). This optimisation allows you to tell Entity Framework not to track the results of a query. This means that Entity Framework performs no additional processing or storage of the entities which are returned by the query. However it also means that you cant update these entities without reattaching them to the tracking graph.

    When to use AsNoTracking
    As you have seen there are significant performance gains to be had by using AsNoTracking, especially when using the Entity Framework Snapshot tracker. If you are using the proxy tracker the performance gains are smaller.
    This means you should use this tuning option on all queries for entities you don't want to save back to the database. In a CQRS sense you should probably apply this option globally across your read path to reduce your memory and processing footprint.
    It is important however not to use this tuning option when you intend to update the entity as this will mean that Entity Framework has no way of knowing that it needs to save your changes back to the database.

    How to use AsNoTracking

    AsNoTracking is very easy to use in your application, simply do the following:

    • Make sure you are using System.Data.Entity
      using System.Data.Entity;
    using (var context = new BloggingContext()) 
    { 
        // Query for all blogs without tracking them 
        var blogs1 = context.Blogs.AsNoTracking(); 
     
        // Query for some blogs without tracking them 
        var blogs2 = context.Blogs 
                            .Where(b => b.Name.Contains(".NET")) 
                            .AsNoTracking() 
                            .ToList(); 
    }

    And if you really has no intent to persist your object changes to database. Try detaching the object.

    var customer= db.customers.where(c=>c.id==1);
    db.Entry(customer).State = System.Data.EntityState.Detached; // add this
    customer.name=santhosh;
    customer.city=hyd;    
    db.SaveChanges();

    That won't save your changes on name and city to database.

    If you have any other concern regarding this issue, please feel free to let me know.

    Best regards,
    Youjun Tang


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by Fred BaoModerator Monday, April 6, 2015 9:53 AM
    • Unmarked as answer by noJedi Tuesday, April 7, 2015 2:28 PM
    Wednesday, April 1, 2015 6:37 AM
  • Hi there,

    I disagree that this is related to the problem.

    The behaviour I'm seeing is this:

    var db = new MyContext();

    then something like this:

    var settings = db.Settings.AsNoTracking() 
        .Where(p=> p.DateSettingsActive <= DateTime.Today)
        .OrderByDescending(p => p.DateSettingsActive)
        .First();
    

    Appears to trigger "SaveChanges"... have a breakpoint in the following override in the DBContext...

    public override int SaveChanges() {     logger.DebugFormat("SaveChanges...");     .....

    I have looked at your info, and this just increases my confusion, because it lends itself to my original theory that "AsNoTracking()" should REMOVE COMPLETELY the odds of this triggering SaveChanges!?

    The only thing I can think of is that somewhere else in my code has made a change, that EF thinks needs to be persisted and this is triggered when the "detatch" happens that is from the "AsNoTracking" ...

    If this IS what is happening... then is there any way to put a watch on something (or similar) that will break when something that EF considers a "requires a save" change happens so I can figure this one out?


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -

    Tuesday, April 7, 2015 2:37 PM
  • Hmm...

    I'm stepping through and thorugh this code to figure this out, and what it looks like is that when the code is hit there is an "external code" and then it appears to be jumping into a new instance... or separate thread perhaps... where its hittin gthe SaveChanges...

    I've expanded the External code and it looks like its running thorugh another startup process...

    including Migrations and various other things...

    Any ideas on (a) how to troubleshoot this and (b) why and/or what might cause this to happen and (c) if this is intended behaviour or if I've got somthing wired incorrectly that might be causing it to create another instance of the context, for some unknown reason...

    UPDATE: SEE THE IMAGE BELOW:

    The stack trace shows "External Code" (lighter) that appears to be EF code...

    The first (lowest) item is the "db.Settings.querystuff..." where by all accounts the instance in "db" exists and is happy (I can see an item "logger" that is populated as it should be), at the TOP of the stack is the problem where it LOOKS like "db" is now actually a different instance (the logger is NOT populated as it should be)...

    PLEASE HELP this is really throwing me for six...


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -



    • Edited by noJedi Friday, April 10, 2015 1:32 PM
    Wednesday, April 8, 2015 4:02 AM
  • O_o

    Buggrit... this has something to do with this, doesn't it...

    static PortalContext()
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<PortalContext, Portal.Migrations.Configuration>());
    

    okay... what's the solution...

    how do you separate the migrations bit from taking over with the object creation when you don't WANT MyDbContext() being created but you want MyDbContext(extrastuffhere...)?

    UPDATE:

    Yes indeed this is the issue.

    Basically the problem is that for some reason (that I haven't figured out yet) the EF thinks that the DB is either not at the "current" migration and is trying to apply the migrations because I have the Databadse INitalizer of MigrateDatabaseToLatestVersion

    so whenever it hits its first query of "anything" its running through the migrations... from what I can tell its not actually changing anything, but it does end up hitting SaveChanges() and this is what was causting my confusion... with the break point of SaveChanges...Can anyone tell me if this is normal operation or not? and if not, is there something I can look at to help me figure out what in my config or system is not seutp properly?

    UPDATE: What I'm seeing is this stepping through (if this helps):
    "Auto-generated" code from the EF.Migrations is getting hit for each of the migrations in my project, it looks like "string IMigrationMetadata.Id - get" is called twice for each migration (which just returns the migration ID)

    It doesn't seem to be running the up/down on any of the migrations but the SEED method IS being run and that's probably what is causing the "SaveChanges()" to be hit... but I'm only using AddOrUpdate... which THEORETICALLY shouldn't be changing anything EVERYTIME... but this could be normal operation and I could be chasing a RED HERRING!?

    Thanks in advance for any advice/assistance.


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -



    • Edited by noJedi Tuesday, April 14, 2015 12:09 AM Update with more info and possible solve?
    Friday, April 10, 2015 1:41 PM