Entity Framework - Lifecycle


Advertisements

Lifetime

The lifetime of a context begins when the instance is created and ends when the instance is either disposed or garbage-collected.

  • Context lifetime is a very crucial decision to make when we use ORMs.

  • The context is performing like an entity cache, so it means it holds references to all the loaded entities which may grow very fast in memory consumption and it can also cause memory leaks.

  • In the below diagram, you can see the upper level of data workflow from application to database via Context and vice versa.

Data Workflow

Entity Lifecycle

The Entity Lifecycle describes the process in which an Entity is created, added, modified, deleted, etc. Entities have many states during its lifetime. Before looking at how to retrieve entity state, let’s take a look at what is entity state. The state is an enum of type System.Data.EntityState that declares the following values −

  • Added: The entity is marked as added.

  • Deleted: The entity is marked as deleted.

  • Modified: The entity has been modified.

  • Unchanged: The entity hasn’t been modified.

  • Detached: The entity isn’t tracked.

State Changes in the Entity Lifecycle

Sometimes state of entities are set automatically by the context, but it can also be modified manually by the developer. Even though all the combinations of switches from one state to another are possible, but some of them are meaningless. For example, Added entity to the Deleted state, or vice versa.

Let’s discuss about different states.

Unchanged State

  • When an entity is Unchanged, it’s bound to the context but it hasn’t been modified.

  • By default, an entity retrieved from the database is in this state.

  • When an entity is attached to the context (with the Attach method), it similarly is in the Unchanged state.

  • The context can’t track changes to objects that it doesn’t reference, so when they’re attached it assumes they’re Unchanged.

Detached State

  • Detached is the default state of a newly created entity because the context can’t track the creation of any object in your code.

  • This is true even if you instantiate the entity inside a using block of the context.

  • Detached is even the state of entities retrieved from the database when tracking is disabled.

  • When an entity is detached, it isn’t bound to the context, so its state isn’t tracked.

  • It can be disposed of, modified, used in combination with other classes, or used in any other way you might need.

  • Because there is no context tracking it, it has no meaning to Entity Framework.

Added State

  • When an entity is in the Added state, you have few options. In fact, you can only detach it from the context.

  • Naturally, even if you modify some property, the state remains Added, because moving it to Modified, Unchanged, or Deleted makes no sense.

  • It’s a new entity and has no correspondence with a row in the database.

  • This is a fundamental prerequisite for being in one of those states (but this rule isn’t enforced by the context).

Added State

Modified State

  • When an entity is modified, that means it was in Unchanged state and then some property was changed.

  • After an entity enters the Modified state, it can move to the Detached or Deleted state, but it can’t roll back to the Unchanged state even if you manually restore the original values.

  • It can’t even be changed to Added, unless you detach and add the entity to the context, because a row with this ID already exists in the database, and you would get a runtime exception when persisting it.

Deleted State

  • An entity enters the Deleted state because it was Unchanged or Modified and then the DeleteObject method was used.

  • This is the most restrictive state, because it’s pointless changing from this state to any other value but Detached.

The using statement if you want all the resources that the context controls to be disposed at the end of the block. When you use the using statement, then compiler automatically creates a try/finally block and calls dispose in the finally block.

using (var context = new UniContext()) {

   var student = new Student {
      LastName = "Khan", 
      FirstMidName = "Ali", 
      EnrollmentDate = DateTime.Parse("2005-09-01")
   };

   context.Students.Add(student);
   context.SaveChanges();
}

When working with long-running context consider the following −

  • As you load more objects and their references into memory, the memory consumption of the context may increase rapidly. This may cause performance issues.

  • Remember to dispose of the context when it is no longer required.

  • If an exception causes the context to be in an unrecoverable state, the whole application may terminate.

  • The chances of running into concurrency-related issues increases as the gap between the time when the data is queried and updated grows.

  • When working with Web applications, use a context instance per request.

  • When working with Windows Presentation Foundation (WPF) or Windows Forms, use a context instance per form. This lets you use change-tracking functionality that context provides.

Rules of Thumb

Web Applications

  • It is now a common and best practice that for web applications, context is used per request.

  • In web applications, we deal with requests that are very short but holds all the server transaction they are therefore the proper duration for the context to live in.

Desktop Applications

  • For desktop application, like Win Forms/WPF, etc. the context is used per form/dialog/page.

  • Since we don’t want to have the context as a singleton for our application we will dispose it when we move from one form to another.

  • In this way, we will gain a lot of the context’s abilities and won’t suffer from the implications of long running contexts.

Advertisements