Laravel预加载eager loading关联时主模型属性为空条件失效如何解决
问题原因
Laravel 预加载(with 方法)的执行流程分为两步:
- 先执行主模型的查询,拿到所有符合条件的主模型数据
- 构造关联查询的时候,会调用关联方法生成关联查询构造器,这时候调用关联方法的是未填充属性的空白模型原型,所以你在关联方法里用
$this->stock_status_id读取属性必然为 null,PHP 层面的条件判断完全不会生效。
只有懒加载(拿到主模型实例后再调用关联属性)、延迟预加载(主模型查询完成后调用 load 方法加载关联)的时候,关联方法调用的对象是已经填充了属性的主模型实例,才能读到正确的属性值。
可行解决方案
方案1:修改关联定义,逻辑移到SQL层面(兼容批量预加载,推荐)
把原来PHP层面的条件判断转换成SQL层面的查询条件,关联查询通过join关联主表读取stock_status_id字段做判断,无需依赖PHP层面的模型属性,预加载、懒加载都能生效:
// Product model public function optionValues() { return $this->hasMany(ProductOptionValue::class) ->join('products', 'product_option_values.product_id', '=', 'products.id') ->select('product_option_values.*') // 避免主表、关联表同名字段覆盖 ->where('product_option_values.status', 1) ->where(function ($query) { // 对应 stock_status_id == CustomStock 的情况,无需额外条件 $query->where('products.stock_status_id', Product::CustomStock) // 其他情况加 price、quantity 限制 ->orWhere(function ($subQuery) { $subQuery->where('product_option_values.price', '>', 0) ->where('product_option_values.quantity', '>', 0); }); }); }
注意:代码里的
products、product_option_values替换为你实际对应的表名即可。
方案2:改用延迟预加载(适合单条数据查询场景)
如果你只是查询单条产品数据,不需要批量查询,可以先查主模型,再调用load方法做延迟预加载,这时候主模型已经填充了属性,原来的关联定义不需要修改就能正常触发判断:
$product = Product::find($productId); $product->load('optionValues');
内容的提问来源于stack exchange,提问作者Hadi Sharghi
相关产品推荐
相关产品推荐

