Entity Framework 6 Code First unreported breaking change/bug when migrating from version 5
Came a cross a nice bug in my golf score app on my season premiere round yesterday. I suddenly had a couple more strokes than I should with my HCP, although it seemed fair since it was the first round and all it didn’t make sense. I hadn’t made any (programmatic) changes to the code since the last time I played.
It took me a while to figure it out but my strokes were based on the female slope. All the custom male and female slopes were suddenly flipped, how come? I had moved the site from surftown to windows azure and with that also upgraded EF from 5 to 6 and compiled the back-end for .NET 4.5 instead of 4.0.
Without diving into golf details a golf club has one to many courses and a course has one to many tees. How many strokes a player gets from a given tee is based his HCP and is usually calculated with a formula. Unless the course has a custom slope table, then you’ll need to specify explicitly how many strokes you’ll get for a given HCP. The latter is the case on my home course, which also is the reason for me creating the app, since there is no other app that handles this well.
So my entities looked something like this (yup, I’m serializing my EF POCOs directly in my WebApi service, get over it :D)
public class Tee { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } ... [InverseProperty("TeeAsMale")] public virtual ICollection CustomHcpAsMale { get; set; } [InverseProperty("TeeAsFemale")] public virtual ICollection CustomHcpAsFemale { get; set; } }
public class TeeHcp { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [JsonIgnore, IgnoreDataMember] public int Id { get; set; } public double From { get; set; } public double To { get; set; } public int Strokes { get; set; } }
And since I haven’t mapped up the inverse property EF won’t be able to give the foreign keys good names, so the table will look like this:
which isn’t neat but it’s fine imho, it works, or at least it did work! Now all of the sudden CustomHcpAsMale and CustomHcpAsFemale switched places when getting the data. Since EF seemed to be confused I went ahead and explictly mapped the inverse properties, changing the code to something like this:
public class Tee { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } ... [InverseProperty("TeeAsMale")] public virtual ICollection CustomHcpAsMale { get; set; } [InverseProperty("TeeAsFemale")] public virtual ICollection CustomHcpAsFemale { get; set; } }
public class TeeHcp { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [JsonIgnore, IgnoreDataMember] public int Id { get; set; } public double From { get; set; } public double To { get; set; } public int Strokes { get; set; } [JsonIgnore, IgnoreDataMember] public Tee TeeAsMale { get; set; } [JsonIgnore, IgnoreDataMember] public Tee TeeAsFemale { get; set; } }
which after applying the migration changed the tables to look like this:
and voilá, problem solved! Once again upgrading libraries to run the latest and greatest versions for no reason bites me in the ass. I’ll try to report this to Microsoft as a breaking change, at least it was an easy fix and I figured it out quickly!
Lessons learned – don’t be lazy like me when mapping navigation properties!
Hope it helps somebody out. Peace!