Nextras\ORM UniqueConstraintViolationException zablokuje nasledujúci persistAndFlush()

Čamo
Člen | 786
+
0
-

Zdravím,
prosím vás narazil som na problém pri perzistovaní v cykle a pri čekovaní UniqueConstraintViolationException. Kód normálne funguje. Ale keď sa vyskytne tá vínimka, tak sa do databázy nič čo nasleduje po tej vínimke neuloží. Pritom je to urobené tak aby sa flushovalo všetko po jednotlivých položkách. Trochu nechápem čo sa vlastne deje.

Kód je celkom triviálny:

foreach ( $values['doctors'] as $doctor )
{
	try
	{
		$medicalplanDoctor = new MedicalplanDoctor();
		$medicalplanDoctor->medicalPlan = $this->medicalPlan;
		$medicalplanDoctor->doctor = $doctor;
		$this->orm->persistAndFlush( $medicalplanDoctor );
	}
	catch ( UniqueConstraintViolationException $e )
	{
		continue;
	}
}

Díky za rady.

Viem, že v doctrine 2 sa pri vínimke uzamkne entitymanager a treba ho znova „naštartovať“, ale tu neviem čo mám robiť.

Editoval Čamo (25. 8. 2017 17:33)

JZechy
Člen | 161
+
0
-

Ve chvíli, kdy ti vznikne výjimka se už žádný další kod od místa vzniku nespouští. Takže by sis měl napravit to, co ti způsobuje duplicitní klíč.

Editoval JZechy (25. 8. 2017 19:18)

Čamo
Člen | 786
+
0
-

Ja v tom kóde nevidím problém. Dúfam, že sa to bude dať vyriešiť bez toho aby som písal SQL. Alebo sa to riešiť nedá?

Editoval Čamo (25. 8. 2017 21:44)

JZechy
Člen | 161
+
0
-

@Čamo Problém je v tom, že vkládáš duplicitní hodnotu do databáze, jelikož máš bud nějaký sloupec jako primary key nebo máš na něm unique, tudíž tam nemůže existovat dvakrát stejná hodnota.

Čamo
Člen | 786
+
0
-

JZechy Ja chápem, že DB v tomto prípade skončí chybou a php zachytí výnimku. A to nieje problém to sa deje každý deň. A záznamy vkladám po jednom, takže nevidím dôvod, prečo by som sa nemohol s tou vínimkou vysporiadať tak ako mi to vyhovuje. Od toho vinimky predsa sú. A databáze je jedno čo v tom cykle robím. Tak prečo to nieje jedno aj ORMku? Nechápem to a ešte raz sa pýtam, či je možné toto nejako v Nextras ORM riešiť na úrovni ORM aby som nemusel písať INSERT IGNORE …

Editoval Čamo (27. 8. 2017 14:39)

hrach
Člen | 1834
+
0
-

@Čamo zkusím to poresit, vypadá to na chybu. Jakou verzi máš?

Čamo
Člen | 786
+
0
-

Hrach
V composer.json je „nextras/orm“: "~2.2@dev". Inak sa s tým robí dosť dobre až výborne.

Editoval Čamo (27. 8. 2017 16:25)

hrach
Člen | 1834
+
0
-

@Čamo

  • na master jsem pridal test, bylo to trochu vic tricky :D (sam jsem se nachytal), ale funguje to. https://github.com/…ef129675cb84
  • zalozil jsem issue na zkodumentovani https://github.com/…m/issues/242
  • na 2.2 by to mohlo fungovat taky, vyzkousej:
    • je treba persistovat bez kaskady, jinak to zkusi vytvorit znovu entity z predchoziho cyklu
    • je treba rollbackout connection pres mapper (ja nejdriv zkousel naprimo, ale to neni dobre)
foreach ( $values['doctors'] as $doctor )
{
    try
    {
        $medicalplanDoctor = new MedicalplanDoctor();
        $medicalplanDoctor->medicalPlan = $this->medicalPlan;
        $medicalplanDoctor->doctor = $doctor;
        $this->orm->persistAndFlush( $medicalplanDoctor, false );
    }
    catch ( UniqueConstraintViolationException $e )
    {
		$this->orm->medicalplanDoctos->getMapper()->rollback();
        continue;
    }
}

Editoval hrach (28. 8. 2017 22:11)

Čamo
Člen | 786
+
0
-

@hrach Díky vyskúšam. Škoda toho rollbacku. Fakt to nešlo rollbacknuť v rámci toho persistAndFlush? :)

hrach
Člen | 1834
+
0
-

@Čamo sitauce se má tak, že aktualně Repository/Model vrstva nezna koncept rollbacku. Pokud by to melo delat automaticky, muselo by to skoncit ve validnim stavu, coz ani nahodou po vyhozeni te exception ve validnim stavu nekonci. Jenom pak ignorujes to, ze tam mas nepersistnutou entitu. Do validniho stavu si to muzes prevest uplne na konci pomoci refreshAll(). Tim ale muzes prijit o neperzistnuta data, takze neni aktualne realne, aby se to nejak automatizovane delalo prave pri rollbacku.

Čamo
Člen | 786
+
+1
-

Ok ešte raz díky. Všetko funguje.

Hologos
Člen | 19
+
0
-

Ahoj, mám stejný problém. Podle vlákna jsem přidal rollback, ale nastává problém, když se dotážu na počet. Používám Nextras\Orm 2.2 + Nextras\Dbal 2.1.

Sample code

<?php
echo "Set<br>";
$set = new Set();
$set->name = 'Test Set';

$cards =
[
  [
      'id' => '1',
      'name' => 'Test #1'
  ],
  [
      'id' => '1',
      'name' => 'Test #1'
  ],
  [
      'id' => '2',
      'name' => 'Test #2'
  ],
];

foreach($cards as $card2)
{
  try
  {
      echo "Karta<br>";
      $card = new Card();
      $card->id = $card2['id'];
      $card->set = $set;
      $card->name = $card2['name'];

      $this->orm->cards->persistAndFlush($card);
  }
  catch(Nextras\Dbal\DriverException $e)
  {
      echo '<error>Cannot insert card \''. $card->name .'\' due to '. $e->getMessage() . '</error><br>';
      $this->orm->cards->getMapper()->rollback();
  }
}

echo "Inserted ". $set->cards->countStored() ." of  ". sizeof($cards);
?>

Výstup je

<?php
Set
Karta (id: 1, name: Test #1)
Karta (id: 1, name: Test #1)
Cannot insert card 'Test #1' due to Duplicate entry '1' for key 'PRIMARY'
Karta (id: 2, name: Test #2)
Inserted 3 of 3
?>

Data v databázi

Sets

<?php
+----+----------+
| id | name     |
+----+----------+
| 1  | Test Set |
+----+----------+
?>

Cards

<?php
+----+-----+---------+
| id | set | name    |
+----+-----+---------+
| 1  | 1   | Test #1 |
| 2  | 1   | Test #2 |
+----+-----+---------+
?>

Editoval Hologos (13. 9. 2017 14:29)

Hologos
Člen | 19
+
0
-

Přešel jsem na Nextras\Orm 3.0 a Nextras\Dbal 3.0.
Výše uvedený kód, jak problém vyřešit, jsem zrušil a zdá se, že vše funguje správně.
Znamená to, že v nové verzi není potřeba toto řešit (rollback se udělá automaticky)?

hrach
Člen | 1834
+
0
-

@Hologos z hlavy ted nevim, ze by se to melo dit automatizovane, ale nejake zmeny kolem transakci byly…