9

I'm migrating from Linq-to-SQL to Entity Framework (4.4), using Database First with a DbContext. I'm wondering whether the following behavior is normal:

using (var e = new AgendaEntities()) {
    var store = e.Stores.First();
    var office = e.Offices.Create();
    office.Store = store; // Set association
    Console.WriteLine(office.StoreID); // shows Guid.Empty, expected store.ID!
}

In L2S, setting the Store association to an entity would also update the StoreID key. In EF, this doesn't seem to be happening. This is regardless of whether the entities are new or loaded from the context.

When I SaveChanges, it saves correctly and the StoreID is updated to match office.ID, but why does this only happen after the save?

Is there something I'm missing, or am I now supposed to keep foreign keys in sync manually?


Solution Edit: This is called property fixup, and used to be done automatically by the generated proxies. However, with DbContext this is no longer the case. According to this Connect issue, this is by design.

Hello, The DbContext template actually doesn't generate classes that will be used as change tracking proxies - just lazy loading proxies (which don't do fix-up). We made this decision because change tracking proxies are complex and have a lot of nuances that can be very confusing to developers. If you want fix-up to occur before SaveChanges you can call myContext.ChangeTracker.DetectChanges. ~EF Team

An alternative is to call DbContext.Entry(entity), which will sync up the entity. This is described in this article: Relationships and Navigation Properties under "Synchronizing the changes between the FKs and Navigation properties"

Alex J
  • 9,905
  • 6
  • 36
  • 46
  • It is hard to understand no more people appreciate this solution. Nobody is working with dbcontext in this way? – dani herrera Jul 10 '13 at 08:38
  • Personally, I now just set the keys manually whenever I change associations. The fixup was a nice-to-have, but after some thought, it doesn't make much sense to expect POCOs to do that anyway. Any operations that change associations should be abstracted in some domain layer method anyway, so in the end it's not as jarring as I thought it would be. – Alex J Jul 10 '13 at 09:26
  • I'm 'blindant' entities through dbEntityValidations with all my business rules to be able to expose entities to UI layer, at least for 'simple' entities. I deal with lazyloading related entities with 'entry.related' but detectChanges approach. Thanks about your post and solution. – dani herrera Jul 10 '13 at 09:52
  • The fixup works for changing relationship between existing entities through changing the foreign key. However, for new entity, which is not proxy, the fixup is not working well awlays. – ZZZ Feb 12 '14 at 06:53

1 Answers1

6

No. Entity framework does this for you. Read Relationships and Navigation Properties for more information.

By assigning a new object to a navigation property. The following code creates a relationship between a course and a department. If the objects are attached to the context, the course is also added to the department.Courses collection, and the corresponding foreign key property on the course object is set to the key property value of the department.

  • course.Department = department;

But as you observed, this only happens after you call SaveChanges or one of the other actions mentioned in the "Synchronizing the changes between the FKs and Navigation properties" portion of the document linked above.

If you are using POCO entities without proxies, you must make sure that the DetectChanges method is called to synchronize the related objects in the context. Note, that the following APIs automatically trigger a DetectChanges call.

  • DbSet.Add
  • DbSet.Find
  • DbSet.Remove
  • DbSet.Local
  • DbContext.SaveChanges
  • DbSet.Attach
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries
  • Executing a LINQ query against a DbSet

If this is not happening at all, my guess is that you haven't properly defined StoreID as the foreign key of the navigation property Store.

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • 1
    I think what's going on is described in "Synchronizing the changes between the FKs and Navigation properties", at the bottom of the article you linked. Calling `e.Entry(office)` synchronizes the IDs. However, I can see in the debugger that proxies are being created, so it *should* work... – Alex J Mar 21 '13 at 17:16
  • @IliaJerebtsov ahh correct. I misread your question initially. I thought you were saying it wasn't happening at all. – p.s.w.g Mar 21 '13 at 17:20
  • Thanks, I've figured it out, apparently the lack of fixup is by design in the DbContext API. – Alex J Mar 21 '13 at 18:09