将雄辩的结果放在另一个表中以执行Laravel 5.4中的查询

 2021-04-26 

Putting eloquent results in another table to doing where queries in Laravel 5.4

由于某些特殊原因,我在模型中使用了附加属性,现在当我要对自定义属性进行where查询时,例如" category",我遇到了一个错误,这意味着无法雄辩地找到带有"类别"名称!

要解决此问题,我想如果将查询结果放入临时表中,我可以做我想做的事情!

有人对此有任何想法吗?如果对我有用,如何将结果传输到临时表?


您将无法使用模型访问器的动态字段来限制数据库查询,因为该字段在数据库中显然不存在。

但是,Collection对象具有相当强大的过滤功能,因此您可以在查询数据库之后使用动态字段来过滤Collection结果。这不像在从数据库中检索结果之前过滤掉结果那样有表现力,但是您可能会遇到这样的情况:性能不是那么关键,或者代码的清洁/维护成本超过了性能成本。

作为示例,给定以下模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Book extends Model
{
    public function getCategoryAttribute()
    {
        if ($this->targetAge < 13) {
            return 'child';
        }

        if ($this->targetAge < 18) {
            return 'teen';
        }

        return 'adult';
    }
}

以下查询将不起作用,因为表中实际上不存在category字段:

1
$childrenBooks = Book::where('category', 'child')->get(); // error: no category field

但是,以下操作将起作用,因为您正在从数据库返回的模型集合上调用where(),并且模型确实可以访问动态字段:

1
$childrenBooks = Book::get()->where('category', 'child');

在这种情况下的问题是,尽管它确实起作用,但是它将从数据库中获取所有书籍,并为每个书籍创建一个Model实例,然后通过该完整Collection进行过滤。但是,这样做的好处是您不必在访问器方法中重复逻辑。在这里,您需要权衡利弊,并确定在您的情况下这是否可以接受。

一个中间选项是创建一个Model作用域方法,以便您的访问器逻辑仅在一个地方重复(如果可以为查询重复):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Book extends Model
{
    public function getCategoryAttribute()
    {
        if ($this->targetAge < 13) {
            return 'child';
        }

        if ($this->targetAge < 18) {
            return 'teen';
        }

        return 'adult';
    }

    public function scopeCategory($query, $category)
    {
        if ($category == 'child') {
            return $query->where('target_age', '<', 13);
        }

        if ($category == 'teen') {
            return $query->where(function ($query) {
                return $query
                    ->where('target_age', '>=', 13)
                    ->where('target_age', '<', 18);
            });
        }

        return $query->where('target_age', '>=', 18);
    }
}

然后您可以像下面这样使用此查询范围:

1
$childrenBooks = Book::category('child')->get();

这里的好处是该逻辑适用于实际查询,因此在从数据库返回记录之前限制了记录。主要的问题是,现在一次在访问器中一次在作用域中重复了您的"类别"逻辑。此外,仅当您可以将访问器逻辑转换为可由数据库查询处理的内容时,此方法才有效。


您可以使用原始语句创建临时表。这篇文章对它进行了相当深入的介绍:

https://laracasts.com/discuss/channels/laravel/how-to-implement-temporary-table