Alejandro Pérez
Alejandro Pérez

Reputation: 2637

Symfony2: establish a model relationship by id

I'm building an API on Symfony2 an I have a Model ItemOrder with a ManyToOne relationship to a Model Item. I have a few Items in my database, and I want to add an ItemOrder that points to an Item that is already in the database, and whose id I know. So my first approach is this:

$item = new Item();
$item->setId(2);

$orderItem = new OrderItem();
$orderItem->setItem($item);

$em->persist($orderItem);
$em->flush();

However, Symfony2 understand that I'm trying to create a new item. I know that a valid approach would be fetching the Item object with the entity manager, and then assign it to the ItemOrder, but I think it's a not very efficient way of doing it.

So how should this be done?

Upvotes: 2

Views: 540

Answers (2)

Inoryy
Inoryy

Reputation: 8425

What you're looking for is called Partial Reference.

$item = $em->getPartialReference('Item', 2);

$orderItem = new OrderItem();
$orderItem->setItem($item);

$em->persist($orderItem);
$em->flush();

However, please read the What is the problem? paragraph carefully, it might be safer to query for full entities by ids instead.

getPartialReference() vs getReference()

I've originally also found what forgottenbas linked, but I don't think it's the correct solution.

These two methods seem to be almost identical and both are referenced in official documentation. Seems that only reasonable way to determine which is best is by looking directly into source code: getReference() and getPartialReference().

Straight up you will notice that getPartialReference() is better documented with a clear description of a use case that exactly matches yours:

 * The use-cases for partial references involve maintaining bidirectional associations
 * without loading one side of the association or to update an entity without loading it. 

If you investigate the code for getReferece() you will notice that in some cases it will result in a database call:

if ($class->subClasses) {
    return $this->find($entityName, $sortedId);
}

and finally, getPartialReference() marks partial reference as read-only, better defining it's purpose:

$this->unitOfWork->markReadOnly($entity);

Upvotes: 3

Alexey B.
Alexey B.

Reputation: 12033

You can create special reference object. More info see on this question

$item = $em->getReference('FQCNBundle:Item', 2);

$orderItem = new OrderItem();
$orderItem->setItem($item);

$em->persist($orderItem);
$em->flush();

Upvotes: 1

Related Questions