Jak zachytit 2 různé UniqueConstraintViolationException
- popcorn
- Člen | 28
Ahoj, chtěl bych zachytit dva různé duplicitní klíče v Db pomocí
catch (Nette\Database\UniqueConstraintViolationException $e)
Ale nevím, kde použít jméno toho klíče,
"":http://prntscr.com/ov7lzx protože bych chtěl pokaždé
vyhodit jiný error.
Něco jako:
catch (Nette\Database\UniqueConstraintViolationException['name'] $e) {
throw new Exceptions\DuplicateNameException;
} catch (Nette\Database\UniqueConstraintViolationException['email'] $e) {
throw new Exceptions\DuplicateEmailException;
}
^^ Což je nesmysl.
Díky za všechny rady. ;)
Hezký večer.
- David Matějka
- Moderator | 6445
chytej to jen jednou a dle obsahu te vyjimky (asi budes muset nejak parsovat error message) se rozhodnes, co udelas
- filsedla
- Člen | 101
Ahoj. Ano, ta exception opravdu název sloupce samostatně nikde neobsahuje, tudíž budeš parsovat error message. Příklad:
try {
...
} catch (UniqueConstraintViolationException $e) {
$matches = Strings::match($e->errorInfo[2], "#Duplicate entry '.*' for key '(.*)'#");
$columnName = Arrays::get($matches, 1);
switch ($columnName) {
case 'name':
...
break;
case 'email':
...
break;
default:
throw new InvalidStateException("Unimplemented case: '{$columnName}'");
};
}
Nicméně, používat takový kód se nedá doporučit.
V realitě je lepší se exception vyhnout a předem kontrolovat, jestli náhodou už kolidující záznam neexistuje, a když ano, tak insert nedělat.
Co víc, reálně často ani nemůže být v databázi např. na sloupci email nebo name UNIQUE constraint, protože aspoň na databázové úrovni data v těchto sloupcích nemohou být unikátní.
Editoval filsedla (20. 8. 2019 20:33)
- popcorn
- Člen | 28
filsedla napsal(a):
Nicméně, používat takový kód se nedá doporučit.
V realitě je lepší se exception vyhnout a předem kontrolovat, jestli náhodou už kolidující záznam neexistuje, a když ano, tak insert nedělat.
No já myslel, že to kontroluji právě těmi exceptions a pak vypíšu, že ten záznam již existuje.
Co víc, reálně často ani nemůže být v databázi např. na sloupci email nebo name UNIQUE constraint, protože aspoň na databázové úrovni data v těchto sloupcích nemohou být unikátní.
Proč by nemohly být unikátní? Já nechci mít dva uživatele např. „test“ a také chci mít pouze jeden e-mail na účet.
- filsedla
- Člen | 101
popcorn napsal(a):
No já myslel, že to kontroluji právě těmi exceptions a pak vypíšu, že ten záznam již existuje.
Proč by nemohly být unikátní? Já nechci mít dva uživatele např. „test“ a také chci mít pouze jeden e-mail na účet.
Hm, no tak jo. Asi k tomu ty exceptions jsou.
Zajímalo by mě, co si o tom myslí ostatní.
Psal jsem ze svojí zkušenosti kvůli tomu, že já většinou UNIQUE
constraint nemůžu mít vůbec. Je to kvůli smazaným záznamům, například
v aplikaci sice může být jenom jeden účet s určitým emailem, ale
v databázi mohou být také smazané účty (deleted=1
) se
stejným emailem.
Závisí na tom, co stavíš.
Editoval filsedla (20. 8. 2019 21:06)
- David Matějka
- Moderator | 6445
@filsedla to se necha vyresit treba partial unique indexama (to asi nepodporuje mysql), slozenyma unique constrainama, kde jeden sloupec bude nullable (ty se nepocitaji do unikatnosti) nebo treba unique indexama s expression (mysql 8+)
- filsedla
- Člen | 101
popcorn napsal(a):
Jak kontroluješ ty kolidující záznamy jak jsi psal?
Jenom takhle (příklad, když chci vložit nový záznam s
$email
):
$row = $this->database->where('email', $email)->fetch();
if ($row){
// Error, return / throw / ...
}
// else
$this->database->insert(['email' => $email, ...]);
- filsedla
- Člen | 101
Potom teda kód se selectem navíc má ještě jednu nevýhodu (oproti přístupu s exceptions): je tam hazard, že jiný proces může vložit znovu stejný email zrovna v okamžiku, kdy už první proces otestoval, že tam žádný takový email není, ale ještě ho nestihl vložit. To se pak musí řešit.
Editoval filsedla (20. 8. 2019 22:00)