本文目录导读:

- 基本的动态加载(
load()方法) - 条件性加载
- 加载特定列
- 嵌套加载
- 延迟加载(懒加载)
- 按需加载 API 响应
- 更优雅的 API 实现
- 使用 API Resource 控制加载
- 性能优化:避免 N+1 问题
- 最新的语法(Laravel 9+)
是的,Laravel 的 Eloquent ORM 支持按需加载关联(动态加载 / 懒加载),主要通过以下几种方式实现:
基本的动态加载(load() 方法)
当模型已经查询出来后,动态加载关联:
// 先获取用户
$user = User::find(1);
// 按需动态加载关联
$user->load('posts');
// 或加载多个关联
$user->load(['posts', 'profile']);
条件性加载
$user = User::find(1);
// 只在某个条件下加载
if (auth()->user()->can('view_posts')) {
$user->load('posts');
}
// 使用 loadWhen 方法
$user->loadWhen($condition, 'posts');
加载特定列
$user = User::find(1);
// 只加载 posts 的 title 和 body 列
$user->load('posts:id,title,body');
嵌套加载
$user = User::find(1);
// 加载 posts 及其中的 comments
$user->load('posts.comments');
// 带条件的嵌套加载
$user->load(['posts' => function($query) {
$query->where('published', true);
}]);
// 加载 posts 的评论并限制
$user->load(['posts.comments' => function($query) {
$query->where('approved', true)->latest();
}]);
延迟加载(懒加载)
Laravel 默认对所有关联使用懒加载:
$user = User::find(1);
// 第一次访问时自动加载
foreach ($user->posts as $post) {
echo $post->title;
}
按需加载 API 响应
在 API 控制器中,根据请求参数动态加载:
class UserController extends Controller
{
public function show($id, Request $request)
{
$user = User::findOrFail($id);
// 根据请求参数动态加载
$with = [];
if ($request->boolean('with_posts')) {
$with[] = 'posts';
}
if ($request->boolean('with_profile')) {
$with[] = 'profile';
}
if ($request->boolean('with_all')) {
$user->load(['posts', 'profile', 'settings']);
} else {
$user->load($with);
}
return response()->json($user);
}
}
更优雅的 API 实现
class UserController extends Controller
{
public function show($id, Request $request)
{
$user = User::findOrFail($id);
// 定义允许的关联
$allowedRelations = ['posts', 'profile', 'settings'];
// 解析请求中的 include 参数 ( include=posts,profile)
$includes = $request->has('include')
? explode(',', $request->input('include'))
: [];
// 过滤合法的关联
$validIncludes = array_intersect($includes, $allowedRelations);
// 动态加载
if (!empty($validIncludes)) {
$user->load($validIncludes);
}
return response()->json($user);
}
}
使用 API Resource 控制加载
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
// 按需包含关联数据
'posts' => $this->whenLoaded('posts'),
'profile' => $this->whenLoaded('profile'),
];
}
}
性能优化:避免 N+1 问题
// 不好的做法(N+1 问题)
$users = User::all();
foreach ($users as $user) {
$user->posts; // 每个循环都查询数据库
}
// 好的做法:预先加载
$users = User::with('posts')->get();
// 或者在需要时批量加载
$users = User::all();
$users->load('posts'); // 只执行一次 SQL
最新的语法(Laravel 9+)
// 使用 when 条件
$user = User::find(1);
$user->when($request->boolean('with_posts'), function ($user) {
$user->load('posts');
})->when($request->boolean('with_profile'), function ($user) {
$user->load('profile');
});
最佳实践建议:
- 在 API 中使用
include参数让客户端决定加载哪些关联 - 始终验证客户端请求的关联是否在允许列表中
- 考虑使用 API Resource 来控制输出内容
- 监控 N+1 查询问题,使用
load()代替循环内访问关联 - 对于常用场景,在模型中使用
$with属性预先加载