Doctrine – entity double insert
- Failips
- Člen | 54
Ahoj,
pri zavolaní nasledujúcej funkcie sa do databáze vloží položka dvakrát.
public function pridajZapis($values, $zapisal) {
$id = $values['id'];
if (!$id) {
return NULL;
}
$item = $this->em->find($this->entity, $id);
$zapis = new Ais\Entities\Zapis($values['text']);
$zapis->setDatum($values['datum']);
$this->em->persist($zapis);
$zapisal = $this->em->find(\Ais\Entities\Person::class, $zapisal->getId());
$zapis->setZapisal($zapisal);
$item->addZapis($zapis);
$this->em->flush();
bdump("Ferko");
return $item;
}
Najskôr som si myslel, že sa funkcia volá 2× a tak som si tam dal bdump(„Ferko“); . Ten sa avšak vypíše iba raz, takže chyba musí byť v práci s Doctrine. Divné je, že niekedy sa nový objekt uloží iba raz a niekedy dvakrát.
Vie niekto pomôcť?
Vďaka, Filip
- kocourPB
- Člen | 47
Ahoj. No vidim, ze tam volas:
// ...
$this->em->persist($zapis); // prvykrat sa persistne entita do pamati
// ...
$item->addZapis($zapis); // pri flushi sa entita persistne a ulozi druhykrat
//...
$this->em->flush();
Ukaz este kod tych entit Ais\Entities\Zapis a $item … predpokladam, ze v tej entite $item mas u toho atributu $zapis nastaveny cascade=persist alebo nieco podobne
PS: Inak brotip do buducnosti. Pouzivaj nazvy atributov, class, metod atd v anglictine ;)
Editoval kocourPB (31. 7. 2019 16:54)
- Failips
- Člen | 54
Zapis:
/**
* @ORM\ManyToOne(targetEntity="Person")
*/
private $zapisal;
/**
* @ORM\ManyToOne(targetEntity="Projekt", inversedBy="zapisy")
*/
private $projekt;
$item je Projekt:
/**
* @ORM\OneToMany(targetEntity="Zapis", mappedBy="projekt")
*/
private $zapisy;
Ak vymažem $item->addZapis($zapis); z kódu vyššie tak mi to neuloží nič, takže ako by si to napísal ty? :)
PS: Projekt som prebral už s českými, slovenskými a anglickými názvami a tiež ma to prekvapilo :D
- kocourPB
- Člen | 47
A ked v tej entite Produkt u $zapisy pridas cascade={„persist“} napr.:
/**
* @ORM\OneToMany(targetEntity="Zapis", mappedBy="projekt", cascade={"persist"})
*/
private $zapisy;
a tu funkciu pridajZapis(..) upravis:
public function pridajZapis($values, $zapisal) {
$id = $values['id'];
if (!$id) {
return NULL;
}
$item = $this->em->find($this->entity, $id);
$zapis = new Ais\Entities\Zapis($values['text']);
$zapis->setDatum($values['datum']);
$zapisal = $this->em->find(\Ais\Entities\Person::class, $zapisal->getId());
$zapis->setZapisal($zapisal);
$item->addZapis($zapis);
$this->em->flush();
return $item;
}
tak ti to ulozi kolkokrat?
Editoval kocourPB (1. 8. 2019 9:28)
- jiri.pudil
- Nette Blogger | 1032
Divné je, že niekedy sa nový objekt uloží iba raz a niekedy dvakrát.
Nemůže to v tom případě být třeba nechtěný double-submit
formuláře? V práci s Doctrine totiž žádný problém nevidím;
persist($entity)
můžeš zavolat klidně tisíckrát, dokud je to
stejný objekt, Doctrine ho uloží jenom jednou.
- Failips
- Člen | 54
jiri.pudil napsal(a):
Divné je, že niekedy sa nový objekt uloží iba raz a niekedy dvakrát.
Nemůže to v tom případě být třeba nechtěný double-submit formuláře? V práci s Doctrine totiž žádný problém nevidím;
persist($entity)
můžeš zavolat klidně tisíckrát, dokud je to stejný objekt, Doctrine ho uloží jenom jednou.
Presne to aj mne napadlo a tak som tam dal ten bdump(), avšak ten sa vypíše iba raz.
- Failips
- Člen | 54
kocourPB napsal(a):
A ked v tej entite Produkt u $zapisy pridas cascade={„persist“} napr.:
/** * @ORM\OneToMany(targetEntity="Zapis", mappedBy="projekt", cascade={"persist"}) */ private $zapisy;
a tu funkciu pridajZapis(..) upravis:
public function pridajZapis($values, $zapisal) { $id = $values['id']; if (!$id) { return NULL; } $item = $this->em->find($this->entity, $id); $zapis = new Ais\Entities\Zapis($values['text']); $zapis->setDatum($values['datum']); $zapisal = $this->em->find(\Ais\Entities\Person::class, $zapisal->getId()); $zapis->setZapisal($zapisal); $item->addZapis($zapis); $this->em->flush(); return $item; }
tak ti to ulozi kolkokrat?
Taktiež 2×
- jiri.pudil
- Nette Blogger | 1032
Presne to aj mne napadlo a tak som tam dal ten bdump(), avšak ten sa vypíše iba raz.
To nic neznamená. Pokud se formulář odešle dvakrát, první request nejspíš doběhne někde na pozadí a do prohlížeče se vrátí až ten druhý. Myslím si, že kdyby měla být chyba v uvedeném kódu, dařilo by se ti to nežádoucí chování vyvolávat konzistentně.
Zkus možná ještě prosím ukázat, kde a jak se volá ta metoda
pridajZapis
:)
- Failips
- Člen | 54
class MyPresenter extends \MainPresenter {
protected function createComponentEditGrid($name) {
// <-- tu je vytváranie iných prvkov datagridu (Ublaboo/Datagrid)
$grid->setItemsDetailForm(function(\Nette\Forms\Container $container) use ($grid, $presenter) {
// <-- tu sú vytvárané rôzne inputy
$container->addSubmit('save', 'Save')
->onClick[] = function($button) use ($grid, $presenter) {
$values = $button->getParent()->getValues();
$values['datum']=new \DateTime();
$presenter->model->pridajZapis($values, $presenter->getUser()->identity->data['osoba']);
$presenter['editGrid']->redrawItem($values->id);
};
});
}
}
- Failips
- Člen | 54
Martk napsal(a):
Zkus si to dumpnout do souboru, třeba tam bude nějaký skrytý request. Myslím, že se mi to taky jednou stalo, chyba v doctrine to nebyla, ale už nevím čím to bylo.
nejako som si nevsimol tvoju odpoved.. pomocou dumpu do suboru sa dumpla hodnota 2×, takze mate pravdu a vola sa to 2× ale nechapem celkom preco a ako tomu zabranit.
- F.Vesely
- Člen | 369
Otevri si v Chrome DevTools, prepni na zalozku Network, zaskrtni Preserve log a klikni na odeslani formulare. Tim zjistis, jestli se ti na server posila jen 1 request nebo 2.
Pokud 1, tak mas chybu v backendu, ze tu funkci volas 2×.
Pokud 2, tak mas chybu ve frontendu, asi nejakej JS, kterej to odesila.
- Failips
- Člen | 54
To som už skúšal.. posiela sa 1 POST request a v backende je tá funkcia volaná iba raz :D Ostatným užívateľom sa to stáva cca 1× z ôsmich pokusov, takže som sa rozhodol tam iba dať tlačítko na mazanie a v prípade, že niekto tam dá 2× záznam tak si jeden môže vymazať. To ale nerieši ten fakt divný problém :D