Reputation: 1598
I must first establish that I'm a total newcomer to Doctrine, even though I know enough about SQL and PHP/Symfony 2.
So, I created this IssueType entity associated to a SQL table:
/**
* IssueType
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Blog\Bundle\CoreBundle\Entity\IssueTypeRepository")
*/
class IssueType
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
// Getters, setters...
}
I populated it, so the content of said table is now:
id | name
1 | Bande dessinée
2 | Livre
3 | Film
4 | Disque
Now I have this other entity, Role, which uses a composite key, made up of a regular string (name) and a foreign key (id from IssueType):
/**
* Role
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Blog\Bundle\CoreBundle\Entity\RoleRepository")
*/
class Role
{
/**
* @var IssueType
*
* @ORM\ManyToOne(targetEntity="Blog\Bundle\CoreBundle\Entity\IssueType")
* @ORM\JoinColumn(nullable=false)
* @ORM\Id
*/
private $issueType;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @ORM\JoinColumn(nullable=false)
* @ORM\Id
*/
private $name;
// Getters, setters...
}
Both tables are correctly generated by doctrine in the database. However, although it should be trivial, I can't for the life of me find a single example of a correct and successful persist operation in such a case.
What I try to do is the following:
$manager = $this->getDoctrine()->getManager();
$issueType = new IssueType();
$issueType->setId(1);
$role = new Role();
$role->setIssueType($issueType);
$role->setName('Dessinateur');
$manager->persist($role);
$manager->flush();
I thus try to persist the following:
Role: {
IssueType: {id: 1, name: ''},
name: 'Dessinateur',
}
And what I get is this nasty exception:
Entity of type Blog\Bundle\CoreBundle\Entity\Role has identity through a foreign entity Blog\Bundle\CoreBundle\Entity\IssueType, 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 'Blog\Bundle\CoreBundle\Entity\Role'. 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.
I understand it wants me to persist first the foreign entity, but I don't want to do that, since the foreign issue type of ID#1 already exists in the database and thus don't need persisting. How can it ask me that when I did not specify any 'cascade' attribute in the annotations?
BTY I tried anyway to do as it says, and it expectedly ended up with a duplicate entry error.
So, what should I do to make Doctrine understand that the foreign issue type should not be persisted?
EDIT
artmees came up with the following solution, which works fine:
$manager = $this->getDoctrine()->getManager();
$issueType = $manager->getRepository('BlogCoreBundle:IssueType')->find(1);
$role = new Role();
$role->setIssueType($issueType);
$role->setName('Dessinateur');
$manager->persist($role);
$manager->flush();
However this implies making an additional request to the database which could have been avoided if not using Doctrine. Since I already know the foreign Id to use, is there any way to use it directly with the persist(), without going to such lengths as actually retrieving the full object from the database?
Upvotes: 1
Views: 2307
Reputation: 1872
I know this is an old article, but...
Just to add to artmees answer, if you know the ID and you just want to insert that, you don't need to load the entity, simply use a reference.
$manager = $this->getDoctrine()->getManager();
$issueType = $manager->getReference('BlogCoreBundle:IssueType',1);
$role = new Role();
$role->setIssueType($issueType);
$role->setName('Dessinateur');
$manager->persist($role);
$manager->flush();
That will create a proxy with that ID (1), which is all you need in order to save the role entity.
Upvotes: 0
Reputation: 8055
try this
$manager = $this->getDoctrine()->getManager();
$issueType = $manager->find('IssueTypeRepository', 1);
$role = new Role();
$role->setIssueType($issueType);
$role->setName('Dessinateur');
$manager->persist($role);
$manager->flush();
Upvotes: 1