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
相关产品推荐
相关产品推荐

