When inserting an entity with associations, is there a way to just use the FK instead of retrieving the entity?

12,346

Solution 1

You want a reference proxy

Let's say I have Posts and Tags. A Post hasMany Tags. I get a bunch of tags from the user, who checked a bunch of checkboxes.

The following would add tags to an existing post, without fetching each tag entity first. It does this by using reference proxies, generated by EntityManager::getReference():

$tag_ids = $_POST['tag_id']; // an array of integers representing tag IDs.
$post = $em->getRepository('Post')->find($post_id); // returns a Post entity.

foreach($tags_ids as $tid){
   $post->addTag($em->getReference('Tag',$tid));
}
$em->persist($post);
$em->flush();

Solution 2

In regards to using a reference proxy
In my investigations this is only partly a solution, as follows:

Yes, you do not have to pro-actively retrieve the related record (because you create a proxy record), but when you flush (commit) the update transaction it still first executes a select statement to retrieve the related record, and then only does the update (all in one hit to the db).
This is inefficient and should not be necessary (we have the foreign-key id, why retrieve the record..?)

So while not a complete solution, what you do gain is only a single connection to the database (which is good) and slightly simplified code.

I am not sure if there is a solution to this at the moment...??
Hopefully the doctrine bods will update in the future and if using the proxy logic we should gain an automatic performance enhancement...

Share:
12,346
blacktie24
Author by

blacktie24

Updated on June 03, 2022

Comments

  • blacktie24
    blacktie24 almost 2 years

    I need to insert an entity which has associations.

    If I already have the FK's of the associated entities, is there a way to insert the primary entity into the db with just the FK's populated?

    Or do I always have to

    • retrieve the associated entities via the FK's,
    • populate the primary entity's properties referring to the assocations,
    • and then invoke the persist method.
  • blacktie24
    blacktie24 about 13 years
    Cobby, yeah that's what I was expecting, but why exactly would this not be recommended, as it would technically save an extra query? Thanks again for taking time out to follow up on my question, I really appreciate it.
  • Cobby
    Cobby about 13 years
    Going by your example, you should already have your roles cached (ensure this in the previous request when they are loaded for the drop down list). So it's not really an extra query. By doing it this way, you maintain a cleaner domain layer at expense of an extremely small performance hit.
  • blacktie24
    blacktie24 about 13 years
    ahhh got it, that makes a lot of sense, but what actually happens in the backend? When doctrine persists the post, with its newly added tags, does it end up replacing the proxies with the actual entities, and then adding these associations to the join table?
  • timdev
    timdev about 13 years
    I'm not sure what Doctrine does internally, but I expect it's efficient -- it simply inserts and/or updates as necessary. If you create a reference proxy with an id that doesn't exist, you probably get an exception when you try to flush(), and the transaction gets rolled back. But don't rely on my word, test it yourself.
  • blacktie24
    blacktie24 about 13 years
    ya i'll try it out. Thx again for your time, timdev, I really appreciate it. Cheers.
  • Cobby
    Cobby almost 13 years
    Totally didn't know about the EntityManager::getReference() function, mega fail. Should probably re-read the API docs more closely :P
  • Mick
    Mick almost 11 years
    +1 awesome reply @timdev. If the id does not exist, it is still generating a reference proxy, I have posted this question here. I still don't understand why doctrine generates a proxy for an entity that does not exist...
  • user1236048
    user1236048 almost 11 years
    nice answer. it works fine but I had to remove the method type hinting because of the difference between entity and proxy. is this the best solution regarding this issue?
  • timdev
    timdev almost 11 years
    @alex.dominte Proxies extend the entity classes, so if you're type-hinting an entity class, substituting a proxy should work fine.
  • Nicodemuz
    Nicodemuz almost 6 years
    Does not work for me: Argument 1 passed to App\Entity\Post::setPostCategory() must be an instance of App\Entity\PostCategory or null, array given