通八洲科技

Laravel 8 多表联合搜索:在关联模型中实现跨表模糊查询

日期:2026-01-02 00:00 / 作者:碧海醫心

本文详解如何在 laravel 8 中基于 eloquent 关系,在保持原有查询结构(如 `with()`、`withcount()`)的前提下,安全高效地扩展搜索范围至关联表(如 `stock`、`category` 等),避免 n+1 或查询断裂。

在 Laravel 中,当主模型(如 Term)与多个关联模型(如 stock、category、attributes)存在 belongsTo 或 hasOne 关系时,仅对主表字段(如 title)搜索远远不够。用户常需同时按 stock.code、category.name 或 attributes.value 等跨表字段进行模糊检索——而不能破坏已有的 eager loading 和聚合查询逻辑

正确做法是使用 whereHas()(用于 belongsTo/hasOne 关系)或 whereDoesntHave(),配合闭包约束,在关联表中执行子查询。它不会影响主查询的 with() 加载,也不会导致 SQL JOIN 冗余(除非显式调用 join()),语义清晰且性能可控。

以下为优化后的完整示例(适配你的场景):

$posts = Term::where('user_id', $user_id)
    ->where('status', 1)
    ->where('type', 'product')
    ->with(['preview', 'attributes', 'category', 'price', 'options', 'stock', 'affiliate'])
    ->withCount('reviews');

// 支持多字段跨表搜索:title(主表)、code(stock 表)、name(category 表)
if (!empty($request->term)) {
    $search = '%' . $request->term . '%';
    $posts = $posts->where(function ($query) use ($search) {
        // 主表匹配
        $query->where('title', 'LIKE', $search)
              // 关联 stock 表(假设 Term hasOne Stock)
              ->orWhereHas('stock', function ($q) use ($search) {
                  $q->where('code', 'LIKE', $search);
              })
              // 关联 category 表(假设 Term belongsTo Category)
              ->orWhereHas('category', function ($q) use ($search) {
                  $q->where('name', 'LIKE', $search);
              })
              // 可继续添加其他关联字段,如 attributes.value
              ->orWhereHas('attributes', function ($q) use ($search) {
                  $q->where('value', 'LIKE', $search);
              });
    });
}

$data = $posts->get(); // 执行最终查询

关键要点说明:

? 进阶建议:

通过 whereHas(),你既能优雅扩展搜索边界,又能完全保留原有数据加载结构——这才是 Laravel 关系型查询的正确打开方式。