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.

David Spence
  • 7,999
  • 3
  • 39
  • 63
daniely
  • 7,313
  • 5
  • 29
  • 46

1 Answers1

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
}
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • 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. – daniely May 11 '12 at 14:24
  • @daniely: No, that's not possible. Only way with a single DB rountrip would be to use eager loading with multiple `Include`s to load all navigation properties. But this would load the parent entity as well and you have to write the `Include`s for all navigation properties manually. – Slauma May 11 '12 at 14:39
  • @Slauma 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. – Cristian Diaconescu Aug 10 '12 at 22:22
  • @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: http://stackoverflow.com/q/5966994/270591 – Slauma Aug 11 '12 at 11:10
  • Is there a way to do `context.Entry(person).Reference(p => p.Company).Load();` for all navigation properties in a generic fashion? – Pluc Mar 11 '15 at 16:58