You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10:基于商品编号的复杂搜索,按type_id筛选关联表字段

解决方案:Laravel 10 按商品type_id动态指定查询字段

针对你的需求,这里提供两种实用的实现方案,既满足按type_id仅查询对应关联表字段的要求,又保证搜索逻辑的高效性:


方案一:查询构建器+Union合并(性能优先)

通过为不同type_id构建独立查询分支,再用Union合并结果,每个分支仅关联对应选项表、查询指定字段,避免冗余数据。

代码实现

public function ProductQuery($queryValue)
{
    // 映射type_id到对应选项表
    $typeTableMap = [
        1 => 'option_tables_one',
        2 => 'option_tables_two',
        3 => 'option_tables_three',
    ];

    $unionQueries = [];
    foreach ($typeTableMap as $typeId => $tableName) {
        // 为每个type构建独立查询
        $unionQueries[] = Product::select(
                'products.*',
                "{$tableName}.item_number",
                "{$tableName}.sales_price_netto",
                "{$tableName}.stock"
            )
            ->join($tableName, 'products.id', '=', "{$tableName}.product_id")
            ->where('products.type_id', $typeId)
            ->where("{$tableName}.item_number", 'LIKE', "%{$queryValue}%");
    }

    // 合并所有查询分支
    $mainQuery = array_shift($unionQueries);
    foreach ($unionQueries as $query) {
        $mainQuery->union($query);
    }

    return $mainQuery->get();
}

优势:仅执行一次数据库查询,性能最优;返回结果结构统一,每个商品仅包含自身字段和对应选项表的3个字段。


方案二:Eloquent关联+动态字段提取(代码优雅)

先通过关联筛选出符合搜索条件的商品,再根据type_id动态加载对应关联表并提取字段,保持Eloquent的语法风格。

步骤1:在Product模型定义关联

// app/Models/Product.php
public function optionOne()
{
    return $this->hasOne(OptionTableOne::class, 'product_id');
}

public function optionTwo()
{
    return $this->hasOne(OptionTableTwo::class, 'product_id');
}

public function optionThree()
{
    return $this->hasOne(OptionTableThree::class, 'product_id');
}

步骤2:实现动态查询逻辑

public function ProductQuery($queryValue)
{
    $products = Product::query()
        // 筛选出商品编号匹配的记录
        ->where(function ($query) use ($queryValue) {
            $query->whereHas('optionOne', fn($q) => $q->where('item_number', 'LIKE', "%{$queryValue}%"))
                  ->orWhereHas('optionTwo', fn($q) => $q->where('item_number', 'LIKE', "%{$queryValue}%"))
                  ->orWhereHas('optionThree', fn($q) => $q->where('item_number', 'LIKE', "%{$queryValue}%"));
        })
        ->get()
        // 根据type_id动态提取对应选项字段
        ->map(function ($product) {
            switch ($product->type_id) {
                case 1:
                    $product->load(['optionOne:id,product_id,item_number,sales_price_netto,stock']);
                    $product->fill($product->optionOne->only(['item_number', 'sales_price_netto', 'stock']));
                    unset($product->optionOne);
                    break;
                case 2:
                    $product->load(['optionTwo:id,product_id,item_number,sales_price_netto,stock']);
                    $product->fill($product->optionTwo->only(['item_number', 'sales_price_netto', 'stock']));
                    unset($product->optionTwo);
                    break;
                case 3:
                    $product->load(['optionThree:id,product_id,item_number,sales_price_netto,stock']);
                    $product->fill($product->optionThree->only(['item_number', 'sales_price_netto', 'stock']));
                    unset($product->optionThree);
                    break;
            }
            return $product;
        });

    return $products;
}

优势:代码可读性强,符合Laravel的Eloquent设计思想;后续新增type_id只需添加关联和分支逻辑即可。


修正你的"短查询写法"

原写法中用.=拼接模型对象会导致结果变成字符串,改为集合merge方法合并结果,并统一返回结构:

public function ProductQuery($queryValue)
{
    $products = collect();

    // 合并type=1的查询结果
    $products = $products->merge(
        ProductOptionTableOne::with(['product' => fn($q) => $q->select('id', 'type_id', 'name')]) // 指定需要的商品字段
            ->select('product_id', 'item_number', 'sales_price_netto', 'stock')
            ->where('item_number', 'LIKE', "%{$queryValue}%")
            ->get()
            ->map(fn($option) => $option->product->merge($option->only(['item_number', 'sales_price_netto', 'stock'])))
    );

    // 合并type=2的查询结果
    $products = $products->merge(
        ProductOptionTableTwo::with(['product' => fn($q) => $q->select('id', 'type_id', 'name')])
            ->select('product_id', 'item_number', 'sales_price_netto', 'stock')
            ->where('item_number', 'LIKE', "%{$queryValue}%")
            ->get()
            ->map(fn($option) => $option->product->merge($option->only(['item_number', 'sales_price_netto', 'stock'])))
    );

    // 合并type=3的查询结果
    $products = $products->merge(
        ProductOptionTableThree::with(['product' => fn($q) => $q->select('id', 'type_id', 'name')])
            ->select('product_id', 'item_number', 'sales_price_netto', 'stock')
            ->where('item_number', 'LIKE', "%{$queryValue}%")
            ->get()
            ->map(fn($option) => $option->product->merge($option->only(['item_number', 'sales_price_netto', 'stock'])))
    );

    return $products;
}

内容的提问来源于stack exchange,提问作者Fzol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:35:05