简体   繁体   中英

Eager load navigation properties on Entity Framework

I have been scouring the internet for a solution to my problem, but have found nothing yet that works.

I have a query that selects a new DTO like so:

List<myDTO> query = (from c in db.Customers                 
           .Include(x => x.Orders)
            where customerId = 5
            select new myDTO
{
 Customer = c,
...
}).ToListAsync();

foreach (var custDto in query)
{
   //this is lazy loaded
   var customerOrder = custDto.Customers.Orders;
}

My problem is when I try to navigate to query.Customers.Orders it is lazy loaded. I would like to eager load the Orders property so it doesn't hit the database many times when looping through customers. I thought having the include would eager load the navigation property.

I am aware I can possibly put an order property in myDTO and load it that way, but I am curious if it's possible the above way.

Thanks!

I'm not sure if you can eager load properties with lazy loading still enabled. If you are willing to disable lazy loading for either just the Orders property of Customers or for your whole context, then it should work the way you presented.

You can do that by removing the virtual keyword from the Orders property or shut it off for the whole dbContext by adding:

     this.Configuration.LazyLoadingEnabled = false;

to your dbContext constructor. Then eager loading the way you presented it should work fine.

However, keep in mind you will always have to eager load that property (or all navigation properties depending on the approach you take) in the future.

As you found out, eager loading ( Include ) doesn't work when the query result is a projection . It's a nuisance sometimes and in cases like yours, when the result contains full entities, I don't really understand why these entities were not enabled to have navigation properties Include ed.

Anyway, it's a restriction you have to find a work-around for. As you say, including a property like Orders = c.Orders would be possible. Another thing you can do is

db.Configuration.LazyLoadingEnabled = false;
var intermed = (from c in db.Customers                 
                where customerId = 5
                select new
                {
                    Customer = c,
                    ...
                    Orders = c.Orders
                }).ToListAsync();
var dtos = intermed.Select(x => new myDTO
                                {
                                    Customer = x.Customer,
                                    ...
                                }).ToList();

You'll notice that myDTO.Customer.Orders is populated, because EF auto-populates navigation properties when a context contains related entities (also called relationship fixup ). Lazy loading must be disabled, because myDTO.Customer.Orders is not marked as loaded internally, so addressing it would still trigger lazy loading.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM