【问题标题】:Laravel Eloquent, how to handle UNIQUE error?Laravel Eloquent,如何处理 UNIQUE 错误?
【发布时间】:2019-11-03 08:16:40
【问题描述】:

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

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

错误:

SQLSTATE[23000]:违反完整性约束:1062 键 'Unique' 的重复条目 '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();
}

【问题讨论】:

  • 为什么不更新您的迁移文件以消除约束?

标签: php laravel eloquent


【解决方案1】:

在一般情况下,您应该使用错误代码而不是任何正则表达式来处理数据库错误。

在您的特定情况下,如果您的意图是覆盖/更新现有数据,则预查询或使用自动为您执行此操作的 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 也可能对您有用,但是如果您这样做是为了默默地忽略新值,那么我建议您改为进行错误处理。

【讨论】:

  • 如果异常与$e->code == 23000不匹配,如何重新抛出异常?
  • throw $e 从 catch 块重新抛出
  • 看来code 是受保护的属性:Cannot access protected property Illuminate\Database\QueryException::$code
  • @nowox 抱歉。错过了。打算写 getCode() 而不是 code 。现已修复
【解决方案2】:

需要在 Controller 级别进行验证(如 laravel Validator),最好使用 count() 而不是 first()

当实体存在于数据库中时,根据您想要执行的操作,有不同的解决方案。比如你可以updateOrCreate()

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

或者抛出异常

【讨论】:

    【解决方案3】:

    您可以使用firstOrCreate 方法:

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

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

    欲了解更多信息:https://laravel.com/docs/5.8/eloquent#inserting-and-updating-models

    【讨论】:

    • 如何检查它是否插入了一个新条目,或者它是否刚刚获得了一个现有条目?
    • @nowox 您可以使用$foo->wasRecentlyCreated 来检查它是否已创建。
    • 这超出了我的问题范围,但我该如何处理$foo->baz()->associate($baz)firstOrCreate
    • 我不明白你的意思@nowox。
    • @nowox 我认为您必须使用必要的(模型、迁移)信息提出一个新问题,以便我们正确理解。如果一开始就不应该有唯一索引,我还建议修复您的数据库结构。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2015-03-08
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-03
      • 2018-12-06
      • 1970-01-01
      • 2021-08-16
      相关资源
      最近更新 更多