我有一个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();
}
答案 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
也可能对您有用,但是如果您这样做是为了静默忽略新值,那么我建议您改为执行错误处理。