I have a MySQL constraint to ensure unique on a composite key. When inserting a new record in my model Foo
I get the expected error:
$foo = new Foo(['foo' => 42, 'bar => 1]);
$foo->save();
Error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '42' for key 'Unique'...
One solution to avoid this error is to query the model before inserting:
if (!Foo::where('foo', 42)->where('bar', 1)->first()) {
$foo = new Foo(['foo' => 42, 'bar => 1]);
$foo->save();
}
Another one would be to catch the exception when preg_match(/UNIQUE/, $e->message)
is true
.
Is there any better solution?
EDIT
I noticed that in Illuminate\Database\Eloquent\Builder
Laravel does the double query anyway which is a bit sad:
public function findOrNew($id, $columns = ['*'])
{
if (! is_null($model = $this->find($id, $columns))) {
return $model;
}
return $this->newModelInstance();
}
In the general case you should be dealing with database errors using the error code and not any regex.
In your particular case pre-querying or using a Laravel method that does that automatically for you, might be preferable if your intention is to overwrite/update existing data.
If you want to generally anticipate an error and handle it you should do something like:
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
}
}
Refer to https://dev.mysql.com/doc/refman/5.5/en/error-reference.html for an exhaustive list of error codes (but ideally you'd only need to deal with a couple of specific errors and under very specific circumstances.
Lastly the SQL ON DUPLICATE KEY UPDATE
might also work for you, however if you are doing this to silently ignore the new values then I suggest you do the error handling instead.
You can use the firstOrCreate
method:
$foo = Foo::firstOrCreate(['foo' => 42, 'bar' => 1]);
This will check if the record exists in the database before creating it. If it exists, it will return the record.
For more information: https://laravel.com/docs/5.8/eloquent#inserting-and-updating-models
laravel provides you with the firstOrCreate functions, which first checks if that value exist in the database, then you also have updateOrCreate function to use incase you want to update some value, but most important one, if you want to handle only unique records then check the validation rules, you would do a FormRequest and add unique rule to that field, after that laravel with provide you with error messages, so you handle the error on the client side
The verification need to be done at Controller level (like laravel Validator) and it's better to do a count()
instead of the first()
.
There are different solution depending on what you wanna do when the entity exists in the database. For example you can do updateOrCreate()
$foo = App\Foo::updateOrCreate(['foo' => 42, 'bar' => 1]);
or throw an exception