Patrick Desjardins Blog
Patrick Desjardins picture from a conference

Entity Framework Complex Type and its Tracking

Posted on: 2015-07-22

Entity Framework has something called complex type. They are classes that does not have unique identifier. They are used has a subset of an entity. For example, you can have an Address class that you want to have inside another class but do not want to have to have a table for the Address. This is useful for concepts that can be shared across entities without having to refer them as entity themselves. Another example could be Audit. An Audit table can be a solution, but you may want to have a ModifiedDate and ModifiedUser for some of your entities. The solution would be to copy paste those two properties on all your entities or to have a class that has those two properties and to use this class inside entities that want to have audit.

Let's see a coding example.

 public class House { public int Id { get; set; } public double Price { get; set; } public Address Address { get; set; } }

public class Address { public string Street { get; set; } public int Number { get; set; } public string City { get; set; } } 

An house has an Address. Later on, if we add Business entity, this one could also refer to the Address entity without having to copy and paste all Address properties.

The main point of that article is that every properties inside a complex type is considered as one by Entity Framework's tracking system. It means that if you mark any of the property to IsModified true that the whole complex type will be tracked as changed. Same thing if you mark that complex type has IsModified to true, than every property, even if not changed, will be marked to be changed. The principle behind that is that complex type is treated as an immutable type. That mean that complex type is a whole. Changing one value of this one would mean to create a new instance of that object. I am not sure that this is very convenient in many "real life scenario" but in theory it makes sense.

To illustrate more the point, here is a second example with Entity Framework calls.

 public class MyEntity { public MyComplexClass Property1 { get; set; } }

var entityLocal = this.Set<MyEntity>().Local.SingleOrDefault(d => d.Id == entity.Id); if (entityLocal == null) { entityLocal = this.Set<MyEntity>().Attach(entity); } this.ChangeTracker.Entries<MyEntity>().Single(d => d.Entity == entityLocal).State = EntityState.Modified; this.Entry(entity).Property(s => s.Property1.SubProperty1).IsModified = true; this.Entry(entity).Property(s => s.Property1.SubProperty2).IsModified = false;//This remove all modification of the object!!! this.SaveChanges(); 

As you can see, the entity is marked as modified and I set one of the complex type property to false. The result is that none of the complex type properties will be saved. Here is the SQL generated:

 update [dbo].[MyEntity] set @p = 0 where (([Id] = @0)) 

The Sql update just the property of the entity, not the one of the complex type. However, if we do not mark the SubProperty2 with IsModified to False, we have a SQL that save the whole entity, with the complex type.

 update [dbo].[MyEntity] set [Property1_SubProperty1] = @0 , [Property1_SubProperty2] = null where (([Id] = @1)) 

I took the shortcut to profile the Sql Database to see the output but you could just check from the database context the properties changed and realize the same behavior.

 var entry = DatabaseContext.Entry(entity); var namesOfChangedProperties = entry.CurrentValues.PropertyNames .Where(p => entry.Property(p).IsModified) .ToArray(); 

At the end, you have to think the Complex Type as a whole. That mean that everything is related for Entity Framework. It also mean that if you are concerned about performance that you may not want to have huge complex type because, during load or save, the transportation of the information become into a single package. You may have end result that is not what desired, have too much information loaded or half a complex type saved (in the case you have just fill up half of the object). Take in consideration that Entity Framework limitation/feature when you create your classes design.