Doctrine2 Entites - Is it possible to compare a "dirty" object to one from the database
Asked Answered
M

2

7

Is it possible to compare the state of an entity object between the current "dirty" version (an object that has some of its properties changed, not yet persisted) and the "original" version (the data still in the database).

My assumption was that I could have a "dirty" object, then pull a fresh one from the DB and compare the two. For instance:

$entity = $em->getRepository('MyContentBundle:DynamicContent')->find($id);

$editForm = $this->createContentForm($entity);
$editForm->bind($request);

if ($editForm->isValid()) {
    $db_entity = $em->getRepository('MyContentBundle:DynamicContent')->find($id);

    // compare $entity to $db_entity

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

    return $this->redirect($this->generateUrl('content_edit', array('id' => $id)));
}

But in my experience, $entity and $db_entity are always the same object (and have the same data as $entity, after the form $request bind). Is there a way to get a fresh version of the $entity alongside the "dirty" version for comparison's sake? The solutions I've seen all pull the needed data before the form bind happens, but I'd rather not have that limitation.

Update: To clarify, I'm looking not only for changes to the entities' properties but also its related collections of entities.

Microphysics answered 13/3, 2013 at 14:50 Comment(5)
I ask specifically so Ican make a better solution to removing items from a Symfony2 form collection. The current solution where you pull the values before the bind seems too limiting and not conducive to making a nice function to handle it.Microphysics
This is a duplicate of #9058058Eleonoreeleoptene
I should expand the scope of my question, since I'm not just looking for changes to the entity itself, but also changes to the related collections within the entity. Using UnitOfWork only helps with the former. However, its looking like Alex's suggestion of using $em->clear() before doing another find() will get the "fresh" entity I'm looking for.Microphysics
that's not possible outside of the flush cycle (without losing your currently managed entities) You may want to check #15282114Eleonoreeleoptene
You won't be able to get more than what I answered in a non dirty way...Lapides
M
7

After you flush the $em it happens (it is commited) in database.. so... you might want to retrieve the $db_entity before flush()


  1. I am not sure what you want.. but you can also use merge instead of persist.

    • merge is returning the object modified - id generated and setted
    • persist is modifying your instance
  2. If you want to have the object modified and not persisted use it before flush.

  3. EntityManager is giving you the same instance because you didn't $em->clear()
    • flush is commiting all changes (all dirty objects)
    • clear is clearing memory cache. so when you find(..., $id) , you will get a brand new instance
  4. Is clone keyword working for you? like in this example:

$entity = $em->find('My\Entity', $id);
$clonedEntity = clone $entity;

And you might also want to read this: Implementing Wakeup or Clone

Mutinous answered 13/3, 2013 at 14:57 Comment(2)
Whoops, my example was bad and I've updated it. The $db_entity should be retrieved before the persist() and flush(). Even when doing that, $entity and $db_entity are the same.Microphysics
added another solution to my post (the clone part)Mutinous
L
12

You can get what has changed on the entity through Doctine's UnityOfWork. It is quite simple : after you persisted the entity, Doctrine knows what to update in the database. You can get these informations by doing :

// Run these AFTER persist and BEFORE flush
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();
$changeset = $uow->getEntityChangeSet($entity);
Lapides answered 13/3, 2013 at 14:56 Comment(2)
Can this be called in a controller? Because when I attempt this, it does not show any changes for my entity (just empty array).Fatness
Be sure you read the warning related to this method in this post: #9058058Jolson
M
7

After you flush the $em it happens (it is commited) in database.. so... you might want to retrieve the $db_entity before flush()


  1. I am not sure what you want.. but you can also use merge instead of persist.

    • merge is returning the object modified - id generated and setted
    • persist is modifying your instance
  2. If you want to have the object modified and not persisted use it before flush.

  3. EntityManager is giving you the same instance because you didn't $em->clear()
    • flush is commiting all changes (all dirty objects)
    • clear is clearing memory cache. so when you find(..., $id) , you will get a brand new instance
  4. Is clone keyword working for you? like in this example:

$entity = $em->find('My\Entity', $id);
$clonedEntity = clone $entity;

And you might also want to read this: Implementing Wakeup or Clone

Mutinous answered 13/3, 2013 at 14:57 Comment(2)
Whoops, my example was bad and I've updated it. The $db_entity should be retrieved before the persist() and flush(). Even when doing that, $entity and $db_entity are the same.Microphysics
added another solution to my post (the clone part)Mutinous

© 2022 - 2024 — McMap. All rights reserved.