Laravel provides a huge amount of cool features that help improve our development experience (DX). But with the regular releases, stresses of day-to-day work, and the vast amount of features available, it’s easy to miss some of the lesser-known features that can help improve our code.
In this article, I’m going to cover some of my favourite tips for working with Laravel models. Hopefully, these tips will help you write cleaner, more efficient code and help you avoid common pitfalls.
Spotting and Preventing N+1 Issues
The first tip we’ll look at is how to spot and prevent N+1 queries.
N+1 queries are a common issue that can occur when lazy loading relationships, where N is the number of queries that are run to fetch the related models.
But what does this mean? Let’s take a look at an example. Imagine we want to fetch every post from the database, loop through them, and access the user that created the post. Our code might look something like this:
Although the code above looks fine, it’s actually going to cause an N+1 issue. Say there are 100 posts in the database. On the first line, we’ll run a single query to fetch all the posts. Then inside the foreach
loop when we’re accessing $post->user
, this will trigger a new query to fetch the user for that post; resulting in an additional 100 queries. This means we’d run 101 queries in total. As you can imagine, this isn’t great! It can slow down your application and put unnecessary strain on your database.
As your code becomes more complex and features grow, it can be hard to spot these issues unless you’re actively looking out for them.
Thankfully, Laravel provides a handy Model::preventLazyLoading()
method that you can use to help spot and prevent these N+1 issues. This method will instruct Laravel to throw an exception whenever a relationship is lazy-loaded, so you can be sure that you’re always eager loading your relationships.
To use this method, you can add the Model::preventLazyLoading()
method call to your App\Providers\AppServiceProvider
class:
Now, if we were to run our code from above to fetch every post and access the user that created the post, we’d see an Illuminate\Database\LazyLoadingViolationException
exception thrown with the following message:
To fix this issue, we can update our code to eager load the user relationship when fetching the posts. We can do this by using the with
method: