Hi guys,
I'm having a hard time understanding why Doctrine (version 2.5.3) won't handle the following schemas as expected. I made two example entities Test and TestTranslated. In the first example the TestTranslated table has a dedicated primary key and in the second example the TestTranslated entity has a compound primary key build out of two foreign keys.
...Bundle\Entity\Test:
type: entity
table: test
id:
id:
type: integer
nullable: false
id: true
generator:
strategy: AUTO
fields:
datetime:
type: datetime
nullable: false
city:
type: string
nullable: false
length: 45
fixed: false
oneToMany:
testTranslation:
targetEntity: TestTranslation
mappedBy: test
indexBy: language_id
cascade: ["persist"]
Example1:
...Bundle\Entity\TestTranslation:
type: entity
table: testtranslation
id:
id:
type: integer
nullable: false
id: true
generator:
strategy: AUTO
fields:
location:
type: text
nullable: true
length: 255
fixed: false
metaTitle:
type: string
nullable: true
length: 75
fixed: false
column: meta_title
metaDescription:
type: string
nullable: true
length: 210
fixed: false
column: meta_description
metaKeyword:
type: string
nullable: true
length: 150
fixed: false
column: meta_keyword
slug:
type: string
nullable: false
length: 255
fixed: false
manyToOne:
test:
targetEntity: Test
joinColumns:
test_id:
referencedColumnName: id
language:
targetEntity: Language
joinColumns:
language_id:
referencedColumnName: id
In this case everything works as expected. Running the code:
$em = $this->getDoctrine()->getEntityManager();
$a = new Test();
$a->setCity('Berlin');
$a->setDatetime(new \DateTime());
$c = $em->getRepository(Language::class)->findOneById('en');
$b = new TestTranslation();
$b->setTest($a);
$b->setLanguage($c);
$b->setLocation('Ljubljana');
$b->setMetaDescription('Meta description');
$b->setMetaKeyword('Meta keyword');
$b->setMetaTitle('Meta title');
$b->setSlug('ljubljana');
$a->addTestTranslation($b);
$em->persist($a);
$em->flush();
I get MySQL entries in both Test and TestTranslated entities with one flush. So all good.
Example2:
...Bundle\Entity\TestTranslation:
type: entity
table: testtranslation
id:
test:
associationKey: true
language:
associationKey: true
fields:
location:
type: text
nullable: true
length: 255
fixed: false
metaTitle:
type: string
nullable: true
length: 75
fixed: false
column: meta_title
metaDescription:
type: string
nullable: true
length: 210
fixed: false
column: meta_description
metaKeyword:
type: string
nullable: true
length: 150
fixed: false
column: meta_keyword
slug:
type: string
nullable: false
length: 255
fixed: false
manyToOne:
test:
targetEntity: Test
inversedBy: testTranslation
joinColumns:
test_id:
referencedColumnName: id
nullable: false
language:
targetEntity: Language
inversedBy: testTranslation
joinColumns:
language_id:
referencedColumnName: id
nullable: false
In this case I get an error:
Entity of type ...Bundle\Entity\TestTranslation has identity through a foreign entity ...Bundle\Entity\Test, however this entity has no identity itself. You have to call EntityManager#persist() on the related entity and make sure that an identifier was generated before trying to persist '...Bundle\Entity\TestTranslation'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations.
What I can do is run the code in the following way:
$em = $this->getDoctrine()->getEntityManager();
$a = new Test();
$a->setCity('Berlin');
$a->setDatetime(new \DateTime());
$em->persist($a);
$em->flush();
$c = $em->getRepository(Language::class)->findOneById('en');
$b = new TestTranslation();
$b->setTest($a);
$b->setLanguage($c);
$b->setLocation('Ljubljana');
$b->setMetaDescription('Meta description');
$b->setMetaKeyword('Meta keyword');
$b->setMetaTitle('Meta title');
$b->setSlug('ljubljana');
$a->addTestTranslation($b);
$em->flush();
but I don't understand why in this case Doctrine isn't that smart to deal with insert sequence. Meaning that it would first save Test entity and then TestTranslated. It works as expected with Example1 but not with Example2 although there's almost no difference in table schema. The only difference is the compound primary key.
I personally don't see any reason why Doctrine wouldn't act the same. Is there a reason behind this behavior or is it just expected that every table has a dedicated primary key? I prefer having a compound primary key.
This seems to be related to https://github.com/doctrine/doctrine2/pull/6701 (and duplicates #6531 and #6043).
@va5ja you can use a pre-generated value as ID in order to solve this for now (UUID, for example).
@va5ja please verify if this is actually a duplicate - we merged all related changes and will release 2.6.1 with them.
I don't get the above error anymore. Both examples work fine so obviously the problem has been fixed and this issue is a duplicate.
@va5ja thanks!