In Entity Framework, why isn't lazy loading working for a one-to-zero-or-one navigation property?

ef-code-first entity-framework entity-framework-5 entity-framework-6 lazy-loading

Question

Consider Person and Address classes defined as

class Person
{
  public int PersonId { get; set; }
  public virtual Address Address { get; set; }
}

class Address
{
  public int PersonId { get; set; }
  public virtual Person Person { get; set; }
}

where only some Persons have an Address, but all Addresses have a Person. This is a one-to-zero-or-one relationship, so I configure it as

modelBuilder.Entity<Address>()
  .HasKey(a => a.PersonId)
  .HasRequired(a => a.Person)
  .WithOptional(a => a.Address);

Now, in my code the following approach (eager loading) works perfectly fine.

var person = context.Person
  .Include(a => a.Address)
  .Single(a => a.PersonId == 123);
var address = person.Address; // address != null (correct)

However, the following approach (lazy loading) does not.

var person = context.Person
  .Single(a => a.PersonId == 123);
var address = person.Address; // address == null (incorrect)

Moreover, I hooked up SQL Profiler and I can see that EF isn't even attempting to lazy load the Address in the second case--it just returns null.

I've been unable to locate any documentation that says EF does not lazy load one-to-zero-or-one navigation properties. Is this by design, is it a bug, or am I doing something wrong?

I tested this with both Entity Framework 5 and Entity Framework 6 Alpha 3 and obtained the same results.

Accepted Answer

I figured this one out. The entity classes must be declared as public and the properties public virtual for lazy loading to work. I.e.

public class Person
{
  public int PersonId { get; set; }
  public virtual Address Address { get; set; }
}

public class Address
{
  public int PersonId { get; set; }
  public virtual Person Person { get; set; }
}

Popular Answer

There are some some Rules to enable or have lazy loading:

context.Configuration.ProxyCreationEnabled should be true.
context.Configuration.LazyLoadingEnabled should be true.

Navigation property should be defined as public, virtual.

Context will not do lazy loading if the property is not defined as virtual.

Example

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext() : base("ProjectConnection")
    {
        Configuration.LazyLoadingEnabled = true;
        Configuration.ProxyCreationEnabled = true;
    }

}

read more



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why