firstOrFail从Eloquent Query Builder返回错误的记录

时间:2014-12-21 15:09:01

标签: php laravel laravel-4 eloquent

我的数据库中有一个名为tallies的表,用于跟踪特定实体的count。表中的两个关键字段是:

  • 类型:实体名称
  • 计数:实体的数量

现在我在表格中有两条记录,第一个记录的类型为hardDrives第二个的类型为{{1} }。

我的存储库中有一个方法用于递增monitors表中特定记录的计数:

tallies

当我发送请求以递增public function decreaseCountBy($type, $number){ $countCollection = $this->tally->where('type', '=', $type )->firstOrFail(); $record = $countCollection->first(); // Troubleshooting output die(var_dump([$type, $record->toArray()])); // The rest of the method $record->count -= $number; $result = $record->save(); if(!$result){ throw new \Exception('Error saving decrementation'); } return $record->count; } 并查看故障排除模具的输出并在此方法中转储并获得以下输出:

monitors

即使我在查询中使用array (size=2) 0 => string 'monitors' (length=8) 1 => array (size=5) 'id' => int 4 'type' => string 'hardDrives' (length=10) 'count' => int 15 'created_at' => string '2014-12-21 03:50:04' (length=19) 'updated_at' => string '2014-12-21 14:35:28' (length=19) 作为monitors的值,我也会获得$type的记录。

在此之后,我尝试更改方法以触发查询:

hardDrives

然后我得到了正确的结果:

$countCollection = $this->tally->where('type', $type )->get();

如果找到记录时出错,我可以在这里停止添加我自己的异常抛出,但是当我读取API Documentation的Builder类'方法array (size=2) 0 => string 'monitors' (length=8) 1 => array (size=5) 'id' => int 5 'type' => string 'monitors' (length=8) 'count' => int 3 'created_at' => string '2014-12-21 03:50:04' (length=19) 'updated_at' => string '2014-12-21 03:50:04' (length=19) 时(对不起,我不能直接链接到它),该方法描述为:

  

执行查询并获取第一个结果或抛出异常。

我想使用内置的Laravel Exception,当找不到记录而不是使用我自己的记录时会抛出它。

这里有什么我想念的吗?当我在laravel Eloquent文档中查找其他示例时,看起来我正在构建查询。

最重要的是,我想知道为什么它失败而不只是一个解决方案。

解决

这是该方法的最终版本,只是为了向大家展示它是如何结束的:

firstOrFail()

通常,当您执行public function decreaseCountBy($type, $number){ $record = $this->tally->where('type', '=', $type )->firstOrFail(); $record->count -= $number; $result = $record->save(); if(!$result){ throw new \Exception('Error saving decrementation'); } return $record->count; } 检索数据时,结果是一个包含多个记录的雄辩->get();实例。从那里,如果您只想检索第一条记录,可以使用Collection类的Collection方法获取具有该记录信息的雄辩->first()类实例。

对于Model,您告诉查询构建器的是您只需要找到第一条记录。因为您只会收到一条记录的数据,所以eloquent会跳过该集合并返回一个模型实例。

在上面的代码中,我删除了“抓取第一条记录的模型”的行,即firstOrFail(),并重命名变量以更好地符合预期结果,即$record = $countCollection->first();到位$record

1 个答案:

答案 0 :(得分:1)

在您调用first()后,无需致电firstOrFail()。 firstOrFail()已经返回单个模型而不是集合,并且在模型上调用first()会触发一个全新的select语句(这次没有where

正如@Jarek Tkaczyk在下面指出的那样,使用您的代码,将对数据库运行两个查询

  1. select * from tallies where type = ?
  2. select * from tallies
  3. 这意味着在您的情况下,第一个查询的结果会被第二个查询覆盖。

    一些背景信息

    firstOrFail()只会调用first(),然后在first()返回null时抛出异常

    public function firstOrFail($columns = array('*'))
    {
        if ( ! is_null($model = $this->first($columns))) return $model;
    
        throw (new ModelNotFoundException)->setModel(get_class($this->model));
    }