How to update an entity's navigation properties in Entity Framework
Asked Answered
R

1

9

In ASP .NET MVC 3 with Entity Framework, I have a domain object which has a navigation property referencing another objects, as follows:

public class Person
{
    public String Name {get;set;}

    public Guid CompanyID{get;set;}

    [ForeignKey(CompanyID)]
    public virtual CompanyType Company{ get; set; }
}

When I create an instance of Person and try to add it to the database, the DBContext keeps a cache of this entity 'Person' and sends it to the database. So later on in the lifetime of the same context instance, when I try to access this entity, the Company field is always null since the navigation property never got updated.

Is there a way to update the navigation property with what exists in the database?

Lazy loading is turned on.

Racemic answered 10/5, 2012 at 21:12 Comment(0)
C
11

If lazy loading is turned on and you want to load the navigation property with lazy loading you must create a proxy of a new Person, not instantiate it with new, like so:

using (var context = new MyDbContext())
{
    var person = context.People.Create(); // creates a lazy loading proxy
    person.CompanyID = 123;
    context.People.Add(person);
    context.SaveChanges();

    var company = person.Company; // lazy loading query happens here
}

Without lazy loading you can use explicit loading:

using (var context = new MyDbContext())
{
    var person = new Person();
    person.CompanyID = 123;
    context.People.Add(person);
    context.SaveChanges();

    context.Entry(person).Reference(p => p.Company).Load(); // explicit loading

    var company = person.Company; // no query anymore, Company is already loaded
}
Compassionate answered 10/5, 2012 at 23:5 Comment(5)
This requires the program to explicitly reload every navigation property that exists. Is there a way to implement something more basic, to reload all navigatio properties for any entity entry? I tried the Reload function for DbEntityEntry but that doesn't seem to work.Racemic
@daniely: No, that's not possible. Only way with a single DB rountrip would be to use eager loading with multiple Includes to load all navigation properties. But this would load the parent entity as well and you have to write the Includes for all navigation properties manually.Compassionate
@Compassionate When using context.People.Include(p => p.NavProp1).Include(p=> p.NavProp2) I can chain-load several navigaton properties creating a single hit to the DB. Is there a similar way to load several navigation properties with context.Entry(person).Reference(...) ? I can't figure out a way to specify all nav properties so I can only call Load() once.Bernie
@CristiDiaconescu: I think it's not possible to load all children with a single explicit loading. However, you can load grandchildren and grandgrandchildren and so on together with the one child navigation property, see the answer to this question: https://mcmap.net/q/551786/-explicit-loading-of-grandchild-collections-in-ef-4-1/270591Compassionate
Is there a way to do context.Entry(person).Reference(p => p.Company).Load(); for all navigation properties in a generic fashion?Karena

© 2022 - 2024 — McMap. All rights reserved.