Laravel雄辩,如何处理UNIQUE错误?

时间:2019-06-20 13:33:46

标签: php laravel eloquent

我有一个MySQL约束来确保复合键上的唯一性。在模型Foo中插入新记录时,出现预期的错误:

$foo = new Foo(['foo' => 42, 'bar => 1]);
$foo->save();

错误:

  

SQLSTATE [23000]:违反完整性约束:1062键“唯一”的条目“ 42”重复...

一种避免此错误的解决方案是在插入之前查询模型:

if (!Foo::where('foo', 42)->where('bar', 1)->first()) {
  $foo = new Foo(['foo' => 42, 'bar => 1]);
  $foo->save();
}

另一种情况是在preg_match(/UNIQUE/, $e->message)true时捕获异常。

有更好的解决方案吗?

编辑

我注意到,在Illuminate\Database\Eloquent\Builder中,Laravel还是会进行两次重复查询,这有点令人遗憾:

public function findOrNew($id, $columns = ['*'])
{
    if (! is_null($model = $this->find($id, $columns))) {
        return $model;
    }

    return $this->newModelInstance();
}

4 个答案:

答案 0 :(得分:3)

您可以使用list方法:

MyClass

这将在创建记录之前检查记录是否存在于数据库中。如果存在,它将返回记录。

有关更多信息:https://laravel.com/docs/5.8/eloquent#inserting-and-updating-models

答案 1 :(得分:2)

laravel为您提供了firstOrCreate函数,该函数首先检查该值是否存在于数据库中,然后还具有updateOrCreate函数以供您更新某些值时使用,但最重要的是,如果您只想处理唯一值记录,然后检查验证规则,您将执行FormRequest并向该字段添加唯一规则,在该laravel之后会向您提供错误消息,以便您在客户端处理错误

答案 2 :(得分:2)

验证需要在控制器级别完成(例如laravel Validator),最好执行count()而不是first()

根据您要在数据库中存在实体时要执行的操作,可以使用不同的解决方案。例如,您可以进行updateOrCreate()

$foo = App\Foo::updateOrCreate(['foo' => 42, 'bar' => 1]);

或引发异常

答案 3 :(得分:2)

通常,您应该使用错误代码而不是任何正则表达式来处理数据库错误。

在特定情况下,如果您打算覆盖/更新现有数据,则最好进行预查询或使用Laravel方法自动为您执行此操作。

如果您通常希望预测并处理错误,则应执行以下操作:

try {
   $foo = new Foo(['foo' => 42, 'bar' => 1]);
   $foo->save();
} catch (\Exception $e) { // It's actually a QueryException but this works too
   if ($e->getCode() == 23000) {
       // Deal with duplicate key error  
   }
}

有关错误代码的详尽列表,请参见https://dev.mysql.com/doc/refman/5.5/en/error-reference.html(但理想情况下,您只需要在非常特殊的情况下处理几个特定的​​错误即可。

最后,SQL ON DUPLICATE KEY UPDATE也可能对您有用,但是如果您这样做是为了静默忽略新值,那么我建议您改为执行错误处理。