【问题标题】:How to create a complexe virtual column in an Eloquent Model?如何在 Eloquent 模型中创建复杂的虚拟列?
【发布时间】:2023-03-05 04:34:01
【问题描述】:

这个问题与this one有关,但我把我真正的问题简化了太多。所以我创建了一个单独的问题:

我有两张桌子。一个以天为单位的间隔与名称相关联,例如bimonthly = 15,另一个列出定期操作并与间隔相关联。

我想列出下一个在纯 SQL 中很容易的周期性操作:

SELECT *, DATE_ADD(updated_at, INTERVAL days DAY) AS next_action 
FROM periodic_actions 
INNER JOIN intervals ON interval_id = intervals.id
HAVING next_action > NOW()

这是我的桌子:

CREATE TABLE `intervals` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  `days` INT NULL,
  PRIMARY KEY (`id`));

CREATE TABLE `periodic_actions` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `interval_id` INT NOT NULL,
  `name` VARCHAR(45) NULL,
  `updated_at` TIMESTAMP NOT NULL,
  PRIMARY KEY (`id`));

以及区间的内容:

+----+----------+------+
| id | name     | days |
+----+----------+------+
|  1 | daily    |    1 |
|  2 | monthly  |   30 |
|  3 | annually |  365 |
+----+----------+------+

我想用 Eloquent 构建相同的查询,我可以在我的虚拟列 next_action 上使用 where

Action::orderBy('next_action', 'asc')
    ->where('next_action', '>', Carbon::now())
    ->get()

我无法隐藏在模型中的最接近的是:

Action::join('intervals', 'interval_id', '=', 'intervals.id')
    ->select(['*', DB::RAW('DATE_ADD(updated_at, INTERVAL days DAY) AS next_action')])
    ->havingRaw(DB::RAW('next_action > NOW()'))->get();

当然我有这个基础模型:

class Action extends Model
{
    protected $table = 'periodic_actions';

    public function interval() 
    {
        return $this->belongsTo(Interval::class);
    }
}

【问题讨论】:

标签: php mysql laravel eloquent


【解决方案1】:

解决方案 1:使用全局范围将字段添加到您的选择语句中

虚拟列的一个问题是,如果您不阻止它,Eloquent 会尝试更新它们。您可以将其从 $fillable 数组中排除,并在模型中使用 global scope 来添加虚拟列,例如:

protected static function boot()
{
    parent::boot();

    static::addGlobalScope('next_action', function (Builder $builder) {
        $builder->addSelect(DB::raw('DATE_ADD(updated_at, INTERVAL days DAY) AS next_action'));
    });
}

您必须记住,这会将您的模型与 MySQL 耦合,因为您使用的日期函数在 sqlite 等数据库中不起作用。

解决方案 2:使用 MySQL 视图

当我有多个计算字段时,我通常会创建一个 MySQL 视图。使用所需的所有计算字段创建视图,然后您可以为该视图创建新的 Eloquent 模型,而无需担心查询范围。

需要注意的是,您当然不能在此模型上使用 create/update/delete,但如果您仅将模型用于显示目的,那应该不是问题。

【讨论】:

  • 你把这个方法放在模型本身上吗?
  • 是的,这是模型类中的静态方法。
  • OP 想在他的查询中使用where()。不过,这个解决方案仍然无法实现,对吧? OP 需要改用having() 吗?
  • 我同意哪里会更好,因为我可以从 Kendo Grid 构建通用过滤器。但是boot 的解决方案还不错
  • @Mozammil,你是对的,你必须使用计算字段。
猜你喜欢
  • 2019-06-12
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 2017-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多