如何在Laravel模型中创建虚拟计算列?
在Laravel模型中创建虚拟(计算)列的几种实现方式
完全可行,以下是几种满足你需求的实现方案:
方案1:访问器 + $appends 属性(模型层面计算)
这是最常用的方式,能让title_body自动出现在Post::all()等查询的结果中:
- 在
Post模型里定义访问器,实现字段拼接逻辑:
public function getTitleBodyAttribute() { return $this->title . ' ' . $this->body; }
- 将这个自定义属性添加到模型的
$appends数组,确保它会被包含在模型的数组/JSON输出中:
protected $appends = ['title_body'];
这种方式是在PHP层面完成计算,数据从数据库取出后再处理,适合数据量不大、逻辑简单的场景。
方案2:查询构造器 + selectRaw(数据库层面计算)
如果追求性能(尤其是大数据量场景),可以让数据库直接返回计算后的字段:
直接在查询中指定:
$posts = Post::select('*', DB::raw("CONCAT(title, ' ', body) as title_body"))->get();
如果想让所有Post模型的查询都自动带上这个字段,可添加全局作用域:
在Post模型的boot方法中添加:
protected static function boot() { parent::boot(); static::addGlobalScope('title_body', function ($query) { $query->select('*', DB::raw("CONCAT(title, ' ', body) as title_body")); }); }
之后调用Post::all()、Post::find()等方法时,结果都会自动包含title_body字段,这种方式性能更优。
方案3:Laravel 9+ 自定义列简化写法
Laravel 9及以上版本可以结合addSelect在模型中统一处理,本质和全局作用域思路一致,比如在模型中定义:
protected static function boot() { parent::boot(); static::addSelect([ 'title_body' => DB::raw("CONCAT(title, ' ', body)") ]); }
效果和方案2的全局作用域一致。
内容的提问来源于stack exchange,提问作者user20597340
相关产品推荐
相关产品推荐

