1
0
mirror of synced 2024-12-15 07:36:03 +03:00
doctrine2/manual/en/change-tracking-policies.txt
2010-08-01 16:37:53 +02:00

128 lines
5.0 KiB
Plaintext

++ Change Tracking Policies
Change tracking is the process of determining what has changed in managed
entities since the last time they were synchronized with the database.
Doctrine provides 3 different change tracking policies, each having its
particular advantages and disadvantages. The change tracking policy can
be defined on a per-class basis (or more precisely, per-hierarchy).
+++ Deferred Implicit
The deferred implicit policy is the default change tracking policy and the most
convenient one. With this policy, Doctrine detects the changes by a
property-by-property comparison at commit time and also detects changes
to entities or new entities that are referenced by other managed entities
("persistence by reachability"). Although the most convenient policy, it can
have negative effects on performance if you are dealing with large units of
work (see "Understanding the Unit of Work"). Since Doctrine can't know what
has changed, it needs to check all managed entities for changes every time you
invoke EntityManager#flush(), making this operation rather costly.
+++ Deferred Explicit
The deferred explicit policy is similar to the deferred implicit policy in that
it detects changes through a property-by-property comparison at commit time. The
difference is that only entities are considered that have been explicitly marked
for change detection through a call to EntityManager#persist(entity) or through
a save cascade. All other entities are skipped. This policy therefore gives
improved performance for larger units of work while sacrificing the behavior
of "automatic dirty checking".
Therefore, flush() operations are potentially cheaper with this policy. The
negative aspect this has is that if you have a rather large application and
you pass your objects through several layers for processing purposes and
business tasks you may need to track yourself which entities have changed
on the way so you can pass them to EntityManager#persist().
This policy can be configured as follows:
[php]
/**
* @Entity
* @ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
class User
{
// ...
}
+++ Notify
This policy is based on the assumption that the entities notify interested
listeners of changes to their properties. For that purpose, a class that
wants to use this policy needs to implement the `NotifyPropertyChanged`
interface from the Doctrine\Common namespace. As a guideline, such an
implementation can look as follows:
[php]
use Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener;
/**
* @Entity
* @ChangeTrackingPolicy("NOTIFY")
*/
class MyEntity implements NotifyPropertyChanged
{
// ...
private $_listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener)
{
$this->_listeners[] = $listener;
}
}
Then, in each property setter of this class or derived classes, you need to
notify all the `PropertyChangedListener` instances. As an example we
add a convenience method on `MyEntity` that shows this behaviour:
[php]
// ...
class MyEntity implements NotifyPropertyChanged
{
// ...
protected function _onPropertyChanged($propName, $oldValue, $newValue)
{
if ($this->_listeners) {
foreach ($this->_listeners as $listener) {
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
}
}
}
public function setData($data)
{
if ($data != $this->data) {
$this->_onPropertyChanged('data', $this->data, $data);
$this->data = $data;
}
}
}
You have to invoke `_onPropertyChanged` inside every method that changes the
persistent state of `MyEntity`.
The check whether the new value is different from the old one is not mandatory
but recommended. That way you also have full control over when you consider a
property changed.
The negative point of this policy is obvious: You need implement an interface
and write some plumbing code. But also note that we tried hard to keep this
notification functionality abstract. Strictly speaking, it has nothing to do
with the persistence layer and the Doctrine ORM or DBAL. You may find that
property notification events come in handy in many other scenarios as well.
As mentioned earlier, the `Doctrine\Common` namespace is not that evil and
consists solely of very small classes and interfaces that have almost no
external dependencies (none to the DBAL and none to the ORM) and that you
can easily take with you should you want to swap out the persistence layer.
This change tracking policy does not introduce a dependency on the Doctrine
DBAL/ORM or the persistence layer.
The positive point and main advantage of this policy is its effectiveness. It
has the best performance characteristics of the 3 policies with larger units of
work and a flush() operation is very cheap when nothing has changed.