Laravel使用join子查询获取指定产品全部属性报错及实现咨询
问题原因分析
- 你当前触发的
InvalidArgumentException报错,根源是joinSub方法要求第一个参数为未执行查询的查询构造器实例,但你在定义$product_attributes时调用了get()方法,直接执行了SQL返回了集合对象,不符合入参要求。 - 普通左关联只能拿到一条属性的原因是:关联查询会将
products主表的一行和product_attributes的多行匹配结果合并为多行,你调用first()只会取第一行(最终合并后会被覆盖为最后一条匹配的属性),自然拿不到全量属性。
方案1:使用Eloquent关联预加载(最推荐,实现最简单)
首先你需要在Product模型中定义和ProductAttributes的一对多关联:
// Product.php模型中添加关联方法 public function attributes() { return $this->hasMany(ProductAttributes::class, 'product_id', 'id') ->select('product_id', 'name as attribute_name', 'value as attribute_value'); }
然后查询时直接用with预加载关联属性即可:
$data['product'] = Product::select('products.*','vendors.name as vendor_name','product_discounts.start_time', 'product_discounts.end_time', 'product_discounts.discount_type','product_discounts.discount_value') ->leftjoin('product_discounts','products.id','=','product_discounts.product_id') ->leftjoin('vendors','products.vendor_id','=','vendors.id') ->where('products.id',$request->product_id) ->with('attributes') // 预加载该产品的所有属性 ->first();
查询结果中$data['product']['attributes']就是该产品的全部属性数组,无属性时为空数组,完全符合需求。
方案2:使用GROUP_CONCAT将属性拼接为单字段(适合需要把属性合并到主表行的场景)
如果需要所有属性都在主表的行数据中返回,可以用groupBy配合GROUP_CONCAT函数实现:
$data['product'] = Product::selectRaw('products.*,vendors.name as vendor_name,product_discounts.start_time, product_discounts.end_time, product_discounts.discount_type,product_discounts.discount_value, GROUP_CONCAT(CONCAT(product_attributes.name,":",product_attributes.value) SEPARATOR ",") as attributes_str') ->leftjoin('product_discounts','products.id','=','product_discounts.product_id') ->leftjoin('product_attributes','products.id','=','product_attributes.product_id') ->leftjoin('vendors','products.vendor_id','=','vendors.id') ->where('products.id',$request->product_id) ->groupBy('products.id') ->first();
你可以按需拆分attributes_str得到所有属性,无属性时该字段为null。
内容的提问来源于stack exchange,提问作者stackoverflow account
相关产品推荐
相关产品推荐

