Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with Eager Loading Nested Navigation Based on Abstract Entity (EF CTP5)

I a portion of my EF model that looks like this:

enter image description here

Summary:

  • Location has many Posts
  • Post is an abstract class
  • Discussion derives from Post
  • Discussions have many Comments

Now, the query i'm trying to achieve:

Get information about Location Id 1234, including any Discussions and Comments associated with those Discussions.

I can get discussions and the comments like this:

var discussions = ctx.Posts
                     .OfType<Discussion>()
                     .Include(x => x.Comments)
                     .ToList();

But i can't seem to get it based on the Posts navigation on the Location entity.

I've tried this:

var locationWithDiscussionsAndComments = ctx
                    .Locations
                    .Include(x => x.Posts
                                   .OfType<Discussion>()
                                   .Select(y => y.Comments))
                    .SingleOrDefault();

Which compiles, but i get the error:

System.ArgumentException: The include path expression must refer to a property defined by the entity, optionally also with nested properties or calls to Select. Parameter name: path

Any ideas? I could probably go "backwards" from the Posts:

var locationWithDiscussionsAndComments = ctx
                   .Posts
                   .Include(x => x.Location)
                   .OfType<Discussion>()
                   .Include(x => x.Comments)
                   .Where(x => x.LocationId == 1234)
                   .Select(x => x.Location)
                   .ToList();

But that is both hairy and semantically wrong in terms of my repositories (i shouldn't have to go through a post repository to get information about a location).

Any ideas?

EDIT

So after having a bigger think about it, i realized that OfType<T> is a filter operation. As as we know, EF does not support filtering with eager loading. The only options are retrieving everything, or using anonymous type projection.

No way i can retrieve everything, as there is far too much meta data involved. So i'm attempting the anonymous type projection.

like image 777
RPM1984 Avatar asked Mar 04 '11 03:03

RPM1984


People also ask

How do I enable eager loading in Entity Framework?

Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load blogs and all the posts related to each blog. Include is an extension method in the System.

What is eager loading in EF core?

Eager loading means that the related data is loaded from the database as part of the initial query. Explicit loading means that the related data is explicitly loaded from the database at a later time.

Which variable declaration would apply eager loading when querying data?

Eager loading is achieved using the Include() method. In the following example, it gets all the students from the database along with its standards using the Include () method.

How do you include in Efcore?

The Entity Framework Core (EF) extension method Include provides us the ability to load additional data besides the entities we are querying for. For example: loading products along with their translations. In some use cases we want to load all translations for the requested products and in some cases we don't.


1 Answers

The new Query method might help you:

var location = context.Locations.SingleOrDefault();

context.Entry(location)
       .Collection(l => l.Posts)
       .Query()
       .OfType<Discussion>()
       .Load();


Repository Implementation:

We can add a new LoadProperty generic method to the Repository<T> class that leverages this new QUery method:

public void LoadProperty<TElement>(T entity, 
        Expression<Func<T, ICollection<TElement>>> navigationProperty,
        Expression<Func<TElement, bool>> predicate) where TElement : class
{
    _context.Set<T>().Attach(entity);

    _context.Entry(entity)         
            .Collection(navigationProperty)
            .Query()
            .Where(predicate)
            .Load();
}

Using the LoadProperty method:

Location location = _locationRepository.Find(1);
_locationRepository.LoadProperty(location, l => l.Posts, p => p is Discussion);
like image 144
Morteza Manavi Avatar answered Sep 25 '22 03:09

Morteza Manavi