Adding Author Badge0:00
In this lesson, we're going to look at optimizing circular relationships. Here we can see that Neil has posted a feature request and other customers have responded. It would be really great if under Neil's name here, we show an author's badge anytime he responds to his own feature request. I've already stubbed this out in our feature.blade.php view, so let's just scroll down and just uncomment that. And now if we refresh the page, we can see this nice new author's badge has been added. However, it's been added to all users, not just Neil. Let's add a conditional here to check to make sure that this was actually made by the author. Of course, this isAuthor method doesn't exist yet.
Implementing isAuthor Check0:30
Let's add a conditional here to check to make sure that this was actually made by the author. Of course, this isAuthor method doesn't exist yet. Let's add that next. We're going to say public function isAuthor. And then we're going to check to see if the first Comment for this feature has a user_id that equals this comment's user_id. And now if we refresh this page, we can see that it's working. We're only getting the author badge for Neil and no other users. That's exactly what we want. However, if we look at our Laravel debug bar now, we've got some serious issues.
Diagnosing N+1 Queries1:03
That's exactly what we want. However, if we look at our Laravel debug bar now, we've got some serious issues. First of all, we're up to 85 database queries. That's a ton of queries, so we've obviously introduced an n plus one issue. Maybe worse than that is our models tab. You can see that we're now loading 1722 Comments. Let's just back this change up and see where things were at before. OK, so this is what we actually want. We want to only load 41 Comments, one Feature and 19 Users, and we only want to make three database queries.
Eager Loading Relationships1:29
We want to only load 41 comments, one Feature and 19 users, and we only want to make three database queries. So let's see how we can improve this. We'll just re-enable that. Hit refresh to get it back to where it was. And I think what we need here is to simply add an eager load to the show method. So let's think about what we need here. We're already loading all the comments and the users for this Feature. However, in order for this method to work, we need the Feature for every comment and then we need the comments for that Feature.
However, in order for this method to work, we need the feature for every comment and then we need the comments for that feature. So let's add that comments dot feature and then the comments for that feature. Let's see if that's helped. And it definitely has. We're back down to only five database queries. Much better. However, if we look at our models tab here, you can see that we're still loading 82 comments and two features. And if you remember from before, we actually only have 41 comments.
and then we're loading the users for those comments. But then we're kind of doing this again. We're loading the feature a second time and then we're loading the comments for that feature a second time. Plus, if we look at our eager loading code here, it kind of does seem a little bit silly. We have the feature already loaded in memory and then we're loading the comments just to load the feature again, just to load the comments again. It's starting to feel like a bit of a Russian doll situation here.
Using setRelation Optimization3:04
just to load the comments again. It's starting to feel like a bit of a Russian doll situation here. Let me show you a different approach that I like to use in situations like this. Let's get rid of this second eager load. And instead of doing that, let's iterate through each comment and manually set the relationship. We're going to use the setRelation method to do this and we're going to pass it the feature that we already have in memory. Let's see what impact this has had on our page. We're at five database queries and we're at 103 models.
Let's see what impact this has had on our page. We're at five database queries and we're at 103 models. Let's hit refresh here and you can see now we're back down to three database queries. One to get the feature, one to get the comments and one to get the users. Plus, in our models tab, you can see that we're only getting 19 users, 41 comments and one feature. So we've essentially found a way to run this in the most efficient way with no extra database queries and not loading any duplicate data. And the reason it works is because of the setRelation eloquent method. Eloquent uses this method anytime it loads a relationship.
And the reason it works is because of the setRelation Eloquent method. Eloquent uses this method anytime it loads a relationship and then has to assign it to a specific model. What we've essentially done here is manually eager load the feature for all of these comments, except we didn't actually have to load it from the database because we already have that feature in memory. So next time you run into a situation like this, where you have a circular relationship, definitely keep the setRelation method in mind.
where you have a circular relationship, definitely keep the setRelation method in mind.
