Thursday, July 16, 2015

Entity State Management by Entity Framework's DbContext

DbContext is used to query from a database and group together changes that will then be written back to the store as a unit.

The general pattern of usage is:

using (ctx = new MyDbContext())
{
    // manipulate domain/model objects
    // issue queries
    ctx.SaveChanges();   // if making changes to db (i.e. not just querying)
}

DbContext tracks state of entities and applies appropriate changes when SaveChanges() is called.

Let's say we have Customer class (POCO, domain/model object) that maps to a Customer table.

In the MyDbContext, we make the context aware of Customer.

public IDbSet<Customer> Customers {get; set; }

To add a new Customer

var customer = new Customer();
ctx.Entry(customer).State = EntityState.Added;
ctx.SaveChanges();

Lookup and update a Customer

var existingCustomer = ctx.Customers.Find(customerId);
existingCustomer.Zip = 22222;
ctx.SaveChanges();

Lookup and update a Customer using an untracked object

var existingCustomer = ctx.Customers.Find(customerId);
passedInUntrackedCustomer.Id = existingCustomer.Id;
ctx.Entry(existingCustomer ).State = EntityState.Detached;
ctx.Entry(passedInUntrackedCustomer).State = EntityState.Modified;
ctx.SaveChanges();

Start tracking an untracked Customer object

ctx.Entry(passedInUntrackedCustomer).State = EntityState.Unchanged;
// any changes to passedInUntrackedCustomer from this point
// will be saved
ctx.SaveChanges();

Update a Customer without looking up first

var existingCustomer = new Customer() { Id = customerId };
ctx.Entry(existingCustomer).State = EntityState.Modified;
ctx.SaveChanges();

Lookup, update a Customer attribute but then cancel changes

var existingCustomer = ctx.Customers.Find(customerId);
existingCustomer.Zip = 22222;
ctx.Entry(existingCustomer).State = EntityState.Unchanged;
ctx.SaveChanges();  // does not save changes to Zip

Delete a Customer

var existingCustomer = new Customer() { Id = customerId };
ctx.Entry(existingCustomer).State = EntityState.Deleted;
ctx.SaveChanges();

Manipulate Navigation Property or Navigation Collection property

Just like we did above, through the Customer object we can manipulate states of the entities referenced from Customer. For example, we can add a new Category to the Category lookup table while at the same time reference that Category (reference navigation property) from Customer. Similarly, if the Customer has one to many relationship with Addresses, we can add a new Address to the Addresses attribute (collection navigation property) of Customer and have EF store that into the Addresses table.