Door
Erik Rijk
op 18-05-2014 16:53
gewijzigd op 18-05-2014 17:36
2.089 views
Ik heb 3 tabellen:
* Travel
* Youtube
* rel_travel_youtube.
1 reis kan meerdere youtube filmps hebben en 1 film kan bij meerdere reizen horen.
Via de cli heb ik de 2 entiteiten gekregen:
* Travel
* Youtube
Er is dus geen entiteit van de koppeltabel aanwezig.
Beide kolommen binnen de koppeltabel zijn gedfineerd als primary key(s).
Ik loop door een feed heen en per element insert ik de data.
Wanneer een video key al bestaat, krijg ik netjes de melding terug dat de waarde al voorkomt. ( unique ), maar dan wil ik alsnog een record in de koppeltabel inschieten.. Ik krijg het maar niet voor elkaar.
public function __construct() {
$this->movies = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
/** @Entity */
class Movie
{
// ...
/**
* @ORM/ManyToMany(targetEntity="Travel", mappedBy="movies")
*/
private $travels;
public function __construct() {
$this->travels = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
?>
Als je deze entities genereert dan krijg je in beiden classen een addMovie() / addTravel() method. Waneer een film al in de tabel aanwezig is doe je dan vervolgens gewoon in de enitity van DIE film de addTravel() method aanroepen. en niet vergeten de persist en flush aan te roepen natuurlijk.
Oke je uitleg is duidelijk. Heb ik nog een nieuwe vraag:
<?php
case 'youtube_video_key':
$oObj = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );
if( null !== $oObj )
{
$oObj->addTravel( $oTravel );
}
else
{
$oYoutube->setVideo( $o->nodeValue );
$oObjectManager->persist( $oYoutube );
$oObjectManager->flush();
$oTravel->addYoutube( $oYoutube );
}
break;
?>
De koppeltabel wordt netjes gevuld, maar in tabel ´youtube´ worden de records dubbel ingeschoten.. Wanneer ik de kolom ´video´ uniek maak, krijg ik het helemaal niet meer voor elkaar.
Ok je maakt dus een nieuwe entity aan zet de unieke youtube code in die entity en je slaat hem op in de database. Vervolgens Koppel je deze aan de $oTravel entity. Kan het zijn dat je deze dan ook nog eens opslaat met
<?php
$oObjectManager->persist( $oTravel );
$oObjectManager->flush();
?>
???
Volgens mij is dit beter (hoop ik)
<?php
$oYoutube = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );
Hmm, de logica van het script is volgens mij een beetje kwijt. Of dat komt door vreemde variabele benamingen weet ik niet, maar het helpt er in elk geval wel aan mee :)
Wat jij nu doet:
- Selecteer Youtube waar video = $o->nodeValue
- Vervolgens set je video in op $o->nodeValue (dat is niet nodig, want daar heb je hem op geselecteerd)
- Je persist dan Youtube (die nog steeds hetzelfde is)
- Dan ga je met Travel aan de slag
Behalve dat het script dus eigenlijk niks doet is de persist van Youtube ook verkeerd. Persist betekend namelijk een CREATE query. Je selecteert dus eerst een Youtube object, doet daar vervolgens niks mee en zegt dan tegen Doctrine dat hij dat Youtube object in de database moet aanmaken. Dan krijg je dus 2 dezelfde rijen in je tabel. Sterker nog, als je hem nog een keer runt krijg je er 3 :)
Als je iets update (wat je hier dus niet doet) hoef je alleen maar ->flush() aan te roepen. Doctrine ontdekt zelf welke geselecteerde entities aangepast zijn en welke dus een UPDATE query nodig hebben.
Volgens mij is dit hele probleem dus slechts een verkeerd geplaatste accolade: De accolade van Regel 7 moet naar regel 11:
Ik heb clear() nog aan het einde toegevoegd en dan krijg ik de melding:
An exception occurred while executing 'INSERT INTO youtube (video) VALUES (?)' with params ["1XHA0t0zHFo"]:
Gedeelde primary key & de volgende query nog uitgevoerd:
ALTER TABLE `rel_travel_youtube` DROP FOREIGN KEY `rel_travel_youtube_ibfk_1`; ALTER TABLE `rel_travel_youtube` ADD CONSTRAINT `rel_travel_youtube_ibfk_1` FOREIGN KEY (`travel_id`) REFERENCES `vacation`.`travel`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `rel_travel_youtube` DROP FOREIGN KEY `rel_travel_youtube_ibfk_2`; ALTER TABLE `rel_travel_youtube` ADD CONSTRAINT `rel_travel_youtube_ibfk_2` FOREIGN KEY (`youtube_id`) REFERENCES `vacation`.`youtube`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;