How does the Tracking / Chache of EntityFramework objects work?

3

Whenever I used EntityFramework in a project, to add a record in the database through it, of a class that contains class type memberships (usually on behalf of ForeignKeys ), I did the following:

  • After the entity instance, it filled in the properties of primitive types;
  • I used the properties of class types as null .
  • And so for me it always worked, until in a specific case like the one I presented in this question: EntityFramework complaining of duplicate identifier even with property being null .

    There are some issues here that address this issue, always isolated cases and a way to get around.

  • When working with ASP.NET MVC (web projects) it works so as not to keep information in memory. That is, the EntityFramework context and all other things are instantiated when a request is made and destroyed when it finishes returning its result. So, whenever I do a POST for a Action , which will bind of a class as Action , I know I have an instance not monitored by EntityFramework in> right? Why a simple one:

  •     if (ModelState.IsValid)
        {
            _context.Add(model);
            _context.SaveChanges();
        }
    

    Does it work?

  • As in the case of the question I referred to, why were there monitoring issues?

  • What would be the most "complete" way to deal with Inserts and Updates and not have problems with Tracking of objects?

  • Enable or Disable LazyLoading and creation of proxies and change tracking ( AutoDetectChangesEnabled ) affects how Tracking ?

  • asked by anonymous 09.05.2015 / 04:05

    2 answers

    3

    How, after all, does Tracking of EntityFramework objects?

    First it is important to explain that a context exists during the life of a Controller , in the specific case that you are working using MVC. The values loaded by the Controller are only expired when the Controller in question suffers a Dispose ", making the context also suffer a Dispose .

    When loading an object, and I'll call it a record, the record is loaded with the original values of the database, and they stay there even if you change it the register. This causes that, when modifying a record, the Entity Framework knows that this record has been previously loaded and knows what to change.

    The registry is usually located by its key. To understand this better, you need to understand the DbSet<T> implementation. It is an observable collection ( ObservableCollection ). When calling , what is being done is:

  • Check if any collection is marked as changed;
  • For each record that has been marked as changed, the Entity Framework performs some logical operation to insert, update, or delete a record in the database. The executed statement is bound to SaveChanges , a EntityState used to identify the state of the record within the Entity Framework.
  • So, whenever I do a POST for an Action, which will bind a class to the Action parameter, I know I have an instance not monitored by EntityFramework, right?

    Wrong. If the record has been previously loaded (in Enum , for example), it is already being "watched". When you apply a Edit to save the edit, the object coming from View is synchronized as follows:

    context.Entry(obj).State = EntityState.Modified;
    

    Notice that the context here is a new context, without the information of the previous request. When I say "the record has already been loaded previously", I say that it was loaded on screen, not on Controller . When you perform POST , you are sending information and the context works optimally, ie the record is reloaded in POST if it has not already been loaded.

    In this line two things are done:

  • Locate a record based on another;
  • Update recorded registry values based on records on screen.
  • The Entry() case is simpler. You are telling the context that the object does not exist, so the context considers the object as new.

    As in the case of the question I referred to, why were there monitoring problems?

    I'll answer the question.

    What would be the most "complete" way to deal with Add and Inserts and not have problems with Tracking of objects?
    • No implementing repositories (the Entity Framework already implements repositories);
    • No Implementing Service Layer ( Controller is already a service layer, different, but it is);
    • No instantiating two contexts unnecessarily;
    • No selecting objects in one context and trying to save in the other;
    • Using the simplest code possible, conforming to (almost) all examples illustrated here and on other specialized websites.

    Enable or Disable Updates and creation of proxies and change tracking ( LazyLoading ) affects how Tracking?

    Lazy load and monitoring are independent things. One does not affect the other, and vice versa.

    AutoDetectChangesEnabled does tracking does not work. Any and all changes have to be invoked by manual methods.

        
    09.05.2015 / 05:24
    3

    Many questions to answer, and a bit complicated, but I'll try

    1 - EntityFramework's ChangeTracking monitors an instance of an entity after it has been "attached" (attached) to an instance of a DbContext.

    2 - When you call a method from a DbSet, for example, Add (T model), EntityFramework will attach the object to DbContext and mark its state as Added.

    Remembering that you can not attach the same object to two different instances of DbContext

    You can check the current state of an object using the Entry (object instance) method.

    3 - EntityFramework uses the Identity Map Pattern . With this, an instance of DbContext can only have a single instance of an object with the same Primary Key attached to ChangeTracker. For example, if you loaded the record with the Id = 1 of a Person entity, you can not attach another object with the same Id = 1, otherwise you will have problems.

    4 - The best way to handle inserts and updates is to isolate transactions with entities similar to a transaction. An instance of a DbContext should have a short life, that is, you instantiate the DbContext, do what you need and then discard the instance. I need to improve the answer to this question 4, but I will add that there is a very good NuGet package for more complex updates called GraphDiff .

    5 - I do not use LazyLoading, nor do I recommend, I prefer to have total control over what I want to load from my database and when necessary I load prematurely the data that I will need, using Include (). So, by default I disable it. Lazy Loading requires the creation of proxy classes, and requires Entity properties to be virtual. Regarding the AutoDetectChanges, if it is disabled, you will have to call the DetectChanges () method manually so that the EntityFramework finds out which properties have been modified at the time of generating SQL that update entities.

        
    09.05.2015 / 04:56