3
votes

According to Doctrine 2.0 docs (http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html) a

..preexisting managed entity, is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are mapped with cascade=PERSIST or cascade=ALL (see “Transitive Persistence”)."

My understanding is that cascading to referenced managed entities should lead to referenced entities being ignored by the persist operation (case 3):

Persistence by Reachability: Cascade Persist

  1. New entities in a collection marked as cascade persist will be directly persisted by Doctrine.
  2. New entities in a collection not marked as cascade persist will produce an Exception and rollback the flush() operation.
  3. Collections without new entities are skipped.

This is however not what happens. I have a managed Channel entity with 1:n Properties and Data entities. When the Channel entity is created some properties are retrieved but not modified.

When I add data and persist the entity via

$channel->addData(new Model\Data($channel, $timestamp, $value));
$em->persist();

I can see SQL for writing the new Data entities but do also see updates to the existing Properties (with the old, unchanged value).

Why does Doctrine (2.4.1) persist relationships of managed entities?

The entity definitions look like below:

class Channel extends Entity {
    /**
     * @OneToMany(targetEntity="Data", mappedBy="channel", cascade={"persist"}, orphanRemoval=true)
     * @OrderBy({"timestamp" = "ASC"})
     */
    protected $data = NULL;

    /**
     * Constructor
     */
    public function __construct($type) {
        parent::__construct($type);
        $this->data = new ArrayCollection();
    }

    /**
     * Add a new data to the database
     */
    public function addData(\Volkszaehler\Model\Data $data) {
        $this->data->add($data);
    }

    ...
}

abstract class Entity {

    /**
     * @OneToMany(targetEntity="Property", mappedBy="entity", cascade={"remove", "persist"}, orphanRemoval=true)
     * @OrderBy({"key" = "ASC"})
     */
    protected $properties = NULL;

    /**
     * Constructor
     *
     * @param string $type
     */
    public function __construct($type) {
        if (!Definition\EntityDefinition::exists($type)) {
            throw new \Exception('Unknown entity type: \'' . $type . '\'');
        }

        $this->properties = new Collections\ArrayCollection();
    }

    ...
}
1
any luck with finding answer to your question? I have same problem: when I only need to persist UserPreferences entity which has ManyToOne relationship to the User entity, when doing $em->persist($user_preferences); it also persists the User entity (which I do not want, an it is a waste of UPDATE sql operation)... :(Dimitry K

1 Answers

1
votes

I've finally out that Doctrine does not insist on persisting referenced managed entities.

In the case described above I had however modified the related entities (changed type on some of the properties) which Doctrine, due to its === comparison when computing the change sets, did interpret as update.

There is some discussion about using the PostFlush event to prevent this, but sofar not conclusive: https://github.com/doctrine/doctrine2/pull/382#issuecomment-43421295