pmn
pmn

Reputation: 2247

EntityFramework and Lazy Loading

I have two object Classes

 class Person
{

    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set;}
    public DateTime BirthDate { get; set; }
    public bool IsMale { get; set; }
    public byte[] Image { get; set; }
    public byte[] RowVersion { get; set; }
    public virtual Person Parent { get; set; }
    public virtual ICollection<PhoneNumber> PhoneNumber { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
    public virtual  PersonInfo PersonInfo { get; set; }

}

and :

class PhoneNumber
{

    public enum PhoneType
    { Work, Mobile, Home };

    public int id { get; set; }
    public string phoneNumber { get; set; }
    public PhoneType phoneType { get; set; }
    public virtual Person Person { get; set; }
}

I added "virtual" keyword to my navigation properties to enable LazyLoading, then i added some codes for getting list of persons:

using (var newContext = new MyDbContext())

    {
        var selectedPerson = newContext.Persons.ToList();  
    }

But, when i run my project, i get the PhoneNumber being null! I thought if i add "virtual" keyword to my navigation properties then i get the PhoneNumber as well.. I got it all wrong?

Upvotes: 2

Views: 202

Answers (3)

pmn
pmn

Reputation: 2247

I found the solution, i should added public modifier to my object classes so :

 Public class Person
  {

     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set;}
     public DateTime BirthDate { get; set; }
     public bool IsMale { get; set; }
     public byte[] Image { get; set; }
     public byte[] RowVersion { get; set; }
     public virtual Person Parent { get; set; }
     public virtual ICollection<PhoneNumber> PhoneNumber { get; set; }
     public virtual ICollection<Address> Addresses { get; set; }
     public virtual  PersonInfo PersonInfo { get; set; }

  }

and :

 Public class PhoneNumber
  {

    public enum PhoneType
    { Work, Mobile, Home };

     public int id { get; set; }
     public string phoneNumber { get; set; }
     public PhoneType phoneType { get; set; }
     public virtual Person Person { get; set; }
  }

Upvotes: 2

Gert Arnold
Gert Arnold

Reputation: 109080

Your code

using (var newContext = new MyDbContext())
{
    var selectedPerson = newContext.Persons.ToList();  
}

will never load PhoneNumbers (or any navigation property) because you don't Include them. And after the statement has run the context is disposed, so any lazy loading attempt will throw an exception.

So (assuming that you didn't disable lazy loading in the context by setting either LazyLoadingEnabled or ProxyCreationEnabled = false.) you should either include the PhoneNumbers

var selectedPerson = newContext.Persons.Include(p => p.PhoneNumbers).ToList();

or address a person's PhoneNumbers collection within the lifespan of the context. (Which will execute additional SQL queries).

Upvotes: 0

J&#252;rgen Steinblock
J&#252;rgen Steinblock

Reputation: 31738

First: I don't know if that makes any difference but I have configured my navigation properties as List<T> and lazy loading works.

Maybe with ICollection<T> EF does not initialize these collections because it does not know which concrete list type to use (just a guess)

 public virtual List<PhoneNumber> PhoneNumbers { get; set; }

Second: By default you don't have to explicitly configure something, it should work out of the box. Anyway, make sure you don't disable LazyLoadingEnabled and ProxyCreationEnabled

Third: Enum Data types are supported since EF5 with Framework 4.5 (if you still run Framework 4.0 you should set it phoneType to int

Upvotes: 0

Related Questions