Nate
Nate

Reputation: 5407

Why are my navigational properties null when retrieved from the database in EF 4.2 POCO?

I have a exceedingly simplistic data model (below). I am having trouble figuring out how I am to get my navigational properties to load from the database. I have no trouble getting them in, but the navigational property does not get set by EF it appears. I have seen several related questions, but they are slightly different or rather involved. I am looking for information on how navigational properties are treated by EF 4.2 (POCO). In the reading I've done, I got the impression that I would be able to access objects with foreign keys using navigational properties. Instead, my properties are coming back as either null or empty depending on if I instantiate my collection in the constructor.

public class AnimalDb : DbContext
{
    public static AnimalDb Create(string fileName)
    {
        Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
        return new AnimalDb(fileName);
    }

    private AnimalDb(string fileName) : base(fileName) { }

    public DbSet<Animal> Animals { get; set; }
}

public class Animal
{
    public Animal()
    {
        Id = Guid.NewGuid();
        Traits = new ObservableCollection<Trait>();
    }

    public Guid Id { get; set; }
    public string Species { get; set; }
    public string Name { get; set; }
    public ObservableCollection<Trait> Traits { get; set; }
}

public class Trait
{
    public Trait()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
}

And here is some (simple) code that uses it:

foreach (var animal in db.Animals)
{
    foreach (var trait in animal.Traits)
    {
        //animal.Traits count is 0, so this does not run.
        //However there are traits in the database, as my populate
        //function is working fine.
        Console.WriteLine("{0} is {1}", animal.Name, trait.Name);
    }
}

----Edit Answer Summary----

Using the article and information provided in the answers below, I was able to discover I could either eagerly load using db.Animals.Include() or enable lazy loading. There is a trick to enabling lazy loading and being able to use it though. First to enable lazy loading I added:

db.Configuration.LazyLoadingEnabled = true;

Next I changed my Traits collection in the following manner:

public virtual ObservableCollection<Trait> Traits { get; set; }

Making it virtual allows the automatically generated proxy to lazily load Traits. That's it! IMHO I think the MSDN docs should shout this load and clear in the POCO EF 4.2 coding conventions. Again thanks for the help.

Upvotes: 0

Views: 1178

Answers (2)

nemesv
nemesv

Reputation: 139778

If you don't use lazy loading you have to explicitly tell EF to load the relation with the Include method:

foreach (var animal in db.Animals.Include(a => a.Traits))
{
    foreach (var trait in animal.Traits)
    {
        //...
    }
}

You can read more about eager loading in this article.

Upvotes: 2

EBarr
EBarr

Reputation: 12026

There are a few reasons that your wire-up methods may appear to have no data. To load related data you need to :

  • explicity load the data
  • meet the lazy loading requirements, or
  • use eager loading using Include()

My guess is that you turned off the virtual proxies. There is more on the requirements here:

http://msdn.microsoft.com/en-us/library/dd456855.aspx

Upvotes: 3

Related Questions