Nelrum
Nelrum

Reputation: 113

How to properly trigger lazy load of collection in Entity Framework 5?

I'm using EF5 (code first) in my application. I have a table which contains a few lazy loading fields.

public class TestEntity
{
    public int Id { get; set; }

    public virtual TestEntity2 SubEntity2 { get; set; }
    public virtual TestEntity3 SubEntity3 { get; set; }

    private ICollection<SubEntity4> _subEntities;
    public ICollection<SubEntity4> SubEntities
    {
        get { return _subEntities ?? (_subEntities = new Collection<SubEntity4>()); }
        protected set { _subEntities = value; }
    }
}

When I'm reading this from database SubEntity2 and SubEntity3 are loading fine but SubEntities collection just won't load and it's always stay Count=0. So I'm forcing load like this:

db.Entry(queryResult).Collection(rr => rr.SubEntities).Load();

But as I understand this collection should be loaded automatically by EF during the first invocation just like SubEntity2 and SubEntity3. Why isn't it working with collection?

Example of the code I'm using to read database:

using (var db = new TestContext(_connection, false))
        {
            var query = from r in db.SubEntities
                        where r.Id == 10
                        select r;

            var queryRes = query.FirstOrDefault();
            if (queryRes != null)
            {
                if (queryRes.FederalRegion != null)
                {
                    // Do something
                }

                foreach (var dbEnt in queryRes.SubEntities)
                {
                    // Do something
                }
            }
        }

Upvotes: 3

Views: 8203

Answers (3)

Maris
Maris

Reputation: 4776

To enable lazy loading you have to make your field virtual, it's true. But you have also another problem. You have your ICollection<SubEntity4> as private. That make your field unaccessible for the mapper. I had the similiar problem, and asked about how to set private field of entity to be visible for a mapper. The answer is - "it's imposible"! Here is a link:

How to enable mapping the private property of the entity

So just do like this:

   public virtual ICollection<SubEntity4> SubEntities {get;set};

and remove your property.

Upvotes: 0

LiverpoolsNumber9
LiverpoolsNumber9

Reputation: 2394

"Sub-entities" as you describe them (collections) ARE lazy-loaded by their very nature. If you DON'T want them to be lazy-loaded, you should use the .Include(x=> x.SubEntitiesCollectionName) extension method.

EDIT

Your class should be like so:

public class TestEntity
{
    public int Id { get; set; }    
    public virtual TestEntity2 SubEntity2 { get; set; }
    public virtual TestEntity3 SubEntity3 { get; set; }    
    public virtual ICollection<SubEntity4> SubEntities { get; set; }
}

Upvotes: 0

In order for lazy-loading to work, EF5 has to do some tricky work. At runtime they create proxy-classes, which are derived from your model classse. Within these proxy classes they override the navigation properties to implement the lazy-loading mechanism.

Your SubEntity2 and SubEntity3 properties are virtual, so they can be overridden. Your SubEntities property is not virtual - EF5 can't override this property to implement lazy loading for it.

When you make your SubEntities property virtual it should work.

Upvotes: 8

Related Questions