DEV Community

Discussion on: ORMs, Lazy Loading and Web Applications

Collapse
 
danieljsummers profile image
Daniel J. Summers

I think that, given what you've illustrated (and my experience), EF got it right. Back when we'd write our own SQL, if I wanted the customer information and the orders, I'd have written two queries - the first would be a PK hit, and the second would be a FK hit. Pretty efficient, especially if I'm just selecting the columns I want to display.

In the EF realm, if I want customer info, I don't have to load the orders; this is the "avoiding extra database calls" scenario. However, I can still have my object model with an Orders collection (and the Orders have a property for the owning Customer), and if I need to edit a specific order, I can do var order = ctx.Orders.Include(o => o.Customer).Single(o => o.Id == myId).

EF also has the concept of tracked vs. non-tracked entities, and with non-tracked entities, it's either eager-loaded or it's null. I'd wager that most web app calls could get away with sticking an .AsNoTracking() right after the DbSet.

I believe, at least in the EF realm, if you were to loop foreach (var order in cust.Orders), you're going to end up with a fetch per iteration; if you want to constrain it to two fetches, you'd need to loop foreach (var order in cust.Orders.ToList()). If there are 5 orders, it would be negligible, but you could end up with N+1 without needing to go 2 levels deep. (source: SQL debug on an app whose slowness I was diagnosing; they could have changed that since then.)

All that being said - you have to really dig into EF to learn these things, but you don't have to dig in that deep to get something that works. It would be nice if there were some way to include these concepts in beginner tutorials. I don't know that I'd judge the potential issues as offsetting the benefits, though; in many cases, the efficiency using the defaults is acceptable, and keeps down the allocations for the instantiated classes. And, with the simplified syntax, ORMs (with their associated downsides) can be an accessible way for people to learn data persistence.

Collapse
 
ruidfigueiredo profile image
Rui Figueiredo • Edited

Hi Daniel,

.AsNoTracking() isn't related to lazy-loading, it's a way of saying to EF that you don't want it to keep track of those entities. This means that if you make changes to them, those changes won't be persisted when you call .SaveChanges().

Also, if you do something like foreach (var order in cust.Orders) you are not going to end up with a fetch per iteration. There's only going to be 1 db call (adding .ToList() makes no difference in this case). The way you end up with N+1 is if Orders is lazy loaded and you do something like this:

   foreach (var cust in customers)
   {
      foreach (var order in cust.Orders) //one db call per customer for the orders
      {
      }
   }
Enter fullscreen mode Exit fullscreen mode

You are absolutely right about having to really dig deep into the ORM that you are using. Lazy loading and N+1 problems are just one of the ways you can shoot yourself in the foot. Another that comes to mind is validation introducing performance issues when doing bulk inserts.