Doctrine – entity double insert

Failips
Člen | 54
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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 | 1028
+
0
-

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
+
0
-

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.

Martk
Člen | 652
+
+1
-

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.

Failips
Člen | 54
+
0
-

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×

kocourPB
Člen | 47
+
0
-

no tak funkcia pridajZapis(..) sa ti musi volat 2×

jiri.pudil
Nette Blogger | 1028
+
0
-

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
+
0
-
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
+
0
-

Tak co.. niekto nejake napady ako by som sa mohol priblizit k spravnemu chovaniu formulara?? :D

Failips
Člen | 54
+
0
-

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 | 368
+
+2
-

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
+
0
-

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