Change Tracker: Working with individual properties (Single Entity)

Description and code samples
Table of Contents
Description

 

 Working with EntityProperties

Class Method / Property Type Description Comments
DbContext Entry DbEntityEntry<TEntity>
DbEntityEntry
Provides access to tracking information for an entity Implies an implicit call to the method DetectChanges
DbEntityEntry<TEntity>
DbEntityEntry
Property(“NAME“)
Property(Func<TEntity, TName>)
DbPropertyEntry Gets an object that represents a scalar property of the entity object
ComplexProperty(“NAME“)
ComplexProperty(Func<TEntity, TName>)
DbComplexPropertyEntry Gets an object that represents a complex property of the entity object
CurrentValue DbComplexPropertyEntry Gets or sets the current value of this property
OriginalValue object object
IsModified bool Gets or sets a value indicating whether the value of this property has been modified since it was loaded from the database.
ParentProperty object DbComplexPropertyEntry The DbPropertyEntry of the property for which this is a nested property This method returns a non-null entry for properties of complex objects
This method returns null for properties of the entity itself

 Working with Navigation Properties

Class Method / Property Type Description Comments
DbContext Entry DbEntityEntry<TEntity>
DbEntityEntry
Provides access to tracking information for an entity Implies an implicit call to the method DetectChanges
DbEntityEntry<TEntity>
DbEntityEntry
Reference(Func<TEntity, TName>) DbReferenceEntry Gets an object that represents the reference (i.e. non-collection) navigation property from this entity to another entity
DbEntityEntry<TEntity>
DbEntityEntry
Collection(Func<TEntity, TName>) DbCollectionEntry Gets an object that represents the collection navigation property from this entity to a collection of related entities
Operations
How to get tracking information of a scalar property of an entity
How to do it
using (var context = new BreakAwayContext())
  {
    var davesDump = (from d in context.Lodgings
                      where d.Name == "Dave's Dump"
                      select d).Single();

    var entry = context.Entry(davesDump);

    entry.Property(d => d.Name).CurrentValue =
      "Dave's Bargain Bungalows";

    Console.WriteLine(
      "Current Value: {0}",
      entry.Property(d => d.Name).CurrentValue);

    Console.WriteLine(
      "Original Value: {0}",
      entry.Property(d => d.Name).OriginalValue);

    Console.WriteLine(
      "Modified?: {0}",
      entry.Property(d => d.Name).IsModified);
  }
How to get modified properties of an entity
How to do it
using (var context = new BreakAwayContext())
  {
    var canyon = (from d in context.Destinations
                  where d.Name == "Grand Canyon"
                  select d).Single();

    canyon.Name = "Super-Size Canyon";
    canyon.TravelWarnings = "Bigger than your brain can handle!!!";

    var entry = context.Entry(canyon);
    var propertyNames = entry.CurrentValues.PropertyNames;

IEnumerable<string> modifiedProperties = from name in propertyNames
                             where entry.Property(name).IsModified
                             select name;

    foreach (var propertyName in modifiedProperties)
    {
      Console.WriteLine(propertyName);
    }
  }
How to get tracking information for a complex property
Remarks

Note 1:
When working with complex properties, Entity Framework tracks that state for the complex type, but not for its individual properties: The state of any property within the complex type will be the same the state of the complex type .

Note 2:
After changing the ComplexPropertyName.State property, every property of ComplexPropertyName will be marked as modified.

Note 3:
When using CurrentValues, OriginalValues, or GetDatabaseValues to get all the current, original, or database values for an entity, the values of any complex properties are returned as nested DbPropertyValues objects

How to do it
using (var context = new BreakAwayContext())
  {
    var julie = (from p in context.People
                  where p.FirstName == "Julie"
                  select p).Single();

    var entry = context.Entry(julie);

    entry.ComplexProperty(p => p.Address)
      .Property(a => a.State)
      .CurrentValue = "VT";

    Console.WriteLine(
      "Address.State Modified?: {0}",
      entry.ComplexProperty(p => p.Address)
        .Property(a => a.State)
        .IsModified);

    Console.WriteLine(
      "Address Modified?: {0}",
      entry.ComplexProperty(p => p.Address).IsModified);

    Console.WriteLine(
      "Info.Height.Units Modified?: {0}",
      entry.ComplexProperty(p => p.Info)
        .ComplexProperty(i => i.Height)
        .Property(h => h.Units)
        .IsModified);
  }
How to get and set the Current or Original values of complex properties
Remarks

Either the Property or the ComplexProperty method can be used to access a complex property. However, the ComplexProperty method must be used to drill down into the complex object with additional Property or ComplexProperty calls.

How to do it
using (var context = new BreakAwayContext())
{
    var castle = context.Castles.Find("The EF Castle");

    // Get the Location complex object
    var location = context.Entry(castle)
                       .Property(c => c.Location)
                       .CurrentValue;
    // Get the nested ImaginaryWorld complex object using chained calls
    var world1 = context.Entry(castle)
                     .ComplexProperty(c => c.Location)
                     .Property(l => l.ImaginaryWorld)
                     .CurrentValue;

    // Get the nested ImaginaryWorld complex object using a single lambda expression
    var world2 = context.Entry(castle)
                     .Property(c => c.Location.ImaginaryWorld)
                     .CurrentValue;

    // Get the nested ImaginaryWorld complex object using a dotted string
    var world3 = context.Entry(castle)
                     .Property("Location.ImaginaryWorld")
                     .CurrentValue;

    // Get the value of the Creator property on the nested complex object using
    // chained calls
    var creator1 = context.Entry(castle)
                       .ComplexProperty(c => c.Location)
                       .ComplexProperty(l => l.ImaginaryWorld)
                       .Property(w => w.Creator)
                       .CurrentValue;

    // Get the value of the Creator property on the nested complex object using a
    // single lambda expression
    var creator2 = context.Entry(castle)
                       .Property(c => c.Location.ImaginaryWorld.Creator)
                       .CurrentValue;

    // Get the value of the Creator property on the nested complex object using a
    // dotted string
    var creator3 = context.Entry(castle)
                       .Property("Location.ImaginaryWorld.Creator")
                       .CurrentValue;
}
How to get tracking information for a navigation reference property of an entity
How to do it
 using (var context = new BreakAwayContext())
  {
    var davesDump = (from d in context.Lodgings
                      where d.Name == "Dave's Dump"
                      select d).Single();

    var entry = context.Entry(davesDump);

    entry.Reference(l => l.Destination)
      .Load();

    var canyon = davesDump.Destination;

    Console.WriteLine(
      "Current Value After Load: {0}",
      entry.Reference(d => d.Destination)
        .CurrentValue
        .Name);
  }
How to change value of a navigation reference property of an entity
Remarks

When doing changes using the Change Tracker API, there is no need for DetectChanges to be called, because the Change Tracker is aware of the changes being made.

How to do it
 using (var context = new BreakAwayContext())
  {
    var davesDump = (from d in context.Lodgings
                      where d.Name == "Dave's Dump"
                      select d).Single();

    var entry = context.Entry(davesDump);

    entry.Reference(l => l.Destination)
      .Load();

    var canyon = davesDump.Destination;

    Console.WriteLine(
      "Current Value After Load: {0}",
      entry.Reference(d => d.Destination)
        .CurrentValue
        .Name);

    var reef = (from d in context.Destinations
                where d.Name == "Great Barrier Reef"
                select d).Single();

    entry.Reference(d => d.Destination)
      .CurrentValue = reef;

    Console.WriteLine(
      "Current Value After Change: {0}",
      davesDump.Destination.Name);
  }
How to get tracking information for a navigation collection property of an entity
How to do it
using (var context = new BreakAwayContext())
  {
    var res = (from r in context.Reservations
               where r.Trip.Description == "Trip from the database"
               select r).Single();

    var entry = context.Entry(res);

    entry.Collection(r => r.Payments)
      .Load();

    Console.WriteLine(
      "Payments Before Add: {0}",
      entry.Collection(r => r.Payments).CurrentValue.Count);
  }
How to change value of a navigation collection property of an entity
Remarks

With a collection navigation property, the CurrentValue property can be used to read and write from the relevant collection navigation property: The CurrentValue on collection navigation properties returns the instance of the collection assigned to the navigation property (e.g. a List<Entity> that should be created in the constructor of the entity class).

Adding or removing from the CurrentValue behaves the same as adding or removing from the navigation property itself: Unless the entity is a change tracking proxy, the method DetectChanges to get change detection and relationship fix-up to occur.

How to do it
using (var context = new BreakAwayContext())
  {
    var res = (from r in context.Reservations
               where r.Trip.Description == "Trip from the database"
               select r).Single();

    var entry = context.Entry(res);

    entry.Collection(r => r.Payments)
      .Load();

    Console.WriteLine(
      "Payments Before Add: {0}",
      entry.Collection(r => r.Payments).CurrentValue.Count);

    var payment = new Payment { Amount = 245 };
    context.Payments.Add(payment);

    entry.Collection(r => r.Payments)
      .CurrentValue
      .Add(payment);

    Console.WriteLine(
      "Payments After Add: {0}",
      entry.Collection(r => r.Payments).CurrentValue.Count);
  }