Yii2关联查询product_url与shop表时ActiveRecord丢失tag字段问题
字段丢失原因
- ActiveRecord(以下简称AR)对象在填充属性时,只会识别当前模型对应数据表的原生字段,以及模型显式声明的自定义属性。你通过JOIN查询带出的
shop表tag字段不属于product_url表原生字段,也没有在ProductUrl模型中做显式声明,所以AR对象会自动过滤该字段。而asArray()返回数组时不会做模型属性合法性校验,会直接返回查询得到的所有字段,因此可以正常拿到tag。 - 如果你是通过
with()预加载shop关联,但直接尝试从ProductUrl对象上取tag属性也会失败:tag属于关联的Shop模型的属性,默认保存在ProductUrl对象的shop关联属性中,不会直接挂载到ProductUrl的一级属性上。
解决方案
方案1:通过关联属性访问(推荐)
只要getShop()关联方法的匹配逻辑正确,查询时预加载关联后,直接从关联对象上取tag即可,不需要额外修改模型字段声明:
// ProductUrl模型中关联方法示例,注意匹配域名的逻辑写在onCondition中 public function getShop() { return $this->hasOne(Shop::class, []) ->onCondition('SUBSTRING_INDEX(shop.url, "/", 3) = SUBSTRING_INDEX(product_url.url, "/", 3)'); } // 查询代码 $productUrls = ProductUrl::find() ->with('shop') ->all(); // 访问tag字段 foreach ($productUrls as $item) { $tag = $item->shop->tag; }
方案2:在ProductUrl模型中声明tag属性
如果你需要直接在ProductUrl对象的一级属性上访问tag,可以手动声明该属性,查询时显式指定查询shop.tag字段:
// 在ProductUrl类中新增公共属性 public $tag; // 查询代码 $productUrls = ProductUrl::find() ->select(['product_url.*', 'shop.tag']) ->leftJoin('shop', 'SUBSTRING_INDEX(shop.url, "/", 3) = SUBSTRING_INDEX(product_url.url, "/", 3)') ->all(); // 直接访问tag $tag = $productUrls[0]->tag;
方案3:重写attributes方法声明额外字段
不想新增公共属性的话,也可以重写ProductUrl的attributes()方法,把tag加入可识别的属性列表,效果和方案2一致:
public function attributes() { return array_merge(parent::attributes(), ['tag']); }
内容的提问来源于stack exchange,提问作者user2285323
相关产品推荐
相关产品推荐

