Merge branch 'master' of github.com:doctrine/orm-documentation
This commit is contained in:
commit
29cb77b964
@ -188,11 +188,12 @@ With Nested Conditions in WHERE Clause:
|
||||
With COUNT DISTINCT:
|
||||
|
||||
[php]
|
||||
$query = $em->createQuery('SELECT COUNT(DISTINCT u.name) FROM CmsUser
|
||||
$query = $em->createQuery('SELECT COUNT(DISTINCT u.name) FROM CmsUser');
|
||||
$users = $query->getResult(); // array of ForumUser objects
|
||||
|
||||
With Arithmetic Expression in WHERE clause:
|
||||
|
||||
[php]
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
|
||||
$users = $query->getResult(); // array of ForumUser objects
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
++ Understanding
|
||||
|
||||
In this chapter we will help you understand the `EntityManager` and the `UnitOfWork`.
|
||||
A Unit of Work is similar to an object-level transaction. A new Unit of Work is
|
||||
@ -8,49 +7,7 @@ implicity started when an EntityManager is initially created or after
|
||||
|
||||
A Unit of Work can be manually closed by calling EntityManager#close(). Any
|
||||
changes to objects within this Unit of Work that have not yet been persisted
|
||||
are lost.
|
||||
|
||||
+++ The size of a Unit of Work
|
||||
|
||||
The size of a Unit of Work mainly refers to the number of managed entities at
|
||||
a particular point in time.
|
||||
|
||||
+++ The cost of flush()
|
||||
|
||||
How costly a flush operation is in terms of performance mainly depends on 2 factors:
|
||||
|
||||
* The size of your current Unit of Work
|
||||
* The configured change tracking policies
|
||||
|
||||
You can get the size of your Unit of Work as follows:
|
||||
|
||||
[php]
|
||||
$uowSize = $em->getUnitOfWork()->size();
|
||||
|
||||
The size represents the number of managed entities in the Unit of Work. This
|
||||
size affects the performance of flush() operations due to change tracking
|
||||
(see "Change Tracking Policies") and, of course, memory consumption, so you
|
||||
may want to check it from time to time during development.
|
||||
|
||||
> **CAUTION**
|
||||
> Do not invoke `flush` after every change to an entity or every single invocation of
|
||||
> persist/remove/merge/... This is an anti-pattern and unnecessarily reduces the
|
||||
> performance of your application. Instead, form units of work that operate on your objects
|
||||
> and call `flush` when you are done. While serving a single HTTP request there should
|
||||
> be usually no need for invoking `flush` more than 0-2 times.
|
||||
|
||||
+++ Direct access to a Unit of Work
|
||||
|
||||
You can get direct access to the Unit of Work by calling `EntityManager#getUnitOfWork()`.
|
||||
This will return the UnitOfWork instance the EntityManager is currently using.
|
||||
|
||||
[php]
|
||||
$uow = $em->getUnitOfWork();
|
||||
|
||||
> **NOTE**
|
||||
> Directly manipulating a UnitOfWork is not recommended. When working directly with the
|
||||
> UnitOfWork API, respect methods marked as INTERNAL by not using them and carefully read
|
||||
> the API documentation.
|
||||
are lost.
|
||||
|
||||
++ Persisting entities
|
||||
|
||||
@ -79,7 +36,7 @@ Example:
|
||||
> **CAUTION**
|
||||
> Generated entity identifiers / primary keys are guaranteed to be available after the
|
||||
> next successful flush operation that involves the entity in question.
|
||||
> You can not reply on a generated identifier to be available directly after invoking `persist`.
|
||||
> You can not rely on a generated identifier to be available directly after invoking `persist`.
|
||||
> The inverse is also true. You can not rely on a generated identifier being not available
|
||||
> after a failed flush operation.
|
||||
|
||||
@ -88,15 +45,12 @@ The semantics of the persist operation, applied on an entity X, are as follows:
|
||||
* If X is a new entity, it becomes managed. The entity X will be entered into the database as a result of the flush operation.
|
||||
* If X is a preexisting managed entity, it 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").
|
||||
* If X is a removed entity, it becomes managed.
|
||||
* If X is a detached entity, the behavior is undefined.
|
||||
|
||||
> **CAUTION**
|
||||
> Do not pass detached entities to the persist operation.
|
||||
* If X is a detached entity, an exception will be thrown on flush.
|
||||
|
||||
|
||||
++ Removing entities
|
||||
|
||||
An entity can be removed from persistent storage by passing it to the `EntityManager#remove($entity)` method. By applying the `remove` operation on some entity, that entity becomes REMOVED, which means that its persistent state will be deleted once `EntityManager#flush()` is invoked. The in-memory state of an entity is unaffected by the `remove` operation.
|
||||
An entity can be removed from persistent storage by passing it to the `EntityManager#remove($entity)` method. By applying the `remove` operation on some entity, that entity becomes REMOVED, which means that its persistent state will be deleted once `EntityManager#flush()` is invoked.
|
||||
|
||||
> **CAUTION**
|
||||
> Just like `persist`, invoking `remove` on an entity does NOT cause an immediate SQL
|
||||
@ -115,8 +69,34 @@ The semantics of the remove operation, applied to an entity X are as follows:
|
||||
* If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities is mapped with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
|
||||
* If X is a detached entity, an InvalidArgumentException will be thrown.
|
||||
* If X is a removed entity, it is ignored by the remove operation.
|
||||
* A removed entity X will be removed from the database as a result of the flush operation.
|
||||
* A removed entity X will be removed from the database as a result of the flush operation.
|
||||
|
||||
After an entity has been removed its in-memory state is the same as before the removal, except for generated identifiers.
|
||||
|
||||
Removing an entity will also automatically delete any exisiting records in many-to-many
|
||||
join tables that link this entity. The action taken depends on the value of the `@joinColumn`
|
||||
mapping attribute "onDelete". Either Doctrine issues a dedicated `DELETE` statement
|
||||
for records of each join table or it depends on the foreign key semantics of
|
||||
onDelete="CASCADE".
|
||||
|
||||
Deleting an object with all its associated objects can be achieved in multiple
|
||||
ways with very different performance impacts.
|
||||
|
||||
1. If an association is marked as `CASCADE=REMOVE` Doctrine 2 will fetch this
|
||||
association. If its a Single association it will pass this entity to
|
||||
´EntityManager#remove()`. If the association is a collection, Doctrine will loop over all
|
||||
its elements and pass them to `EntityManager#remove()`. In both cases the
|
||||
cascade remove semantics are applied recursively. For large object graphs
|
||||
this removal strategy can be very costly.
|
||||
2. Using a DQL `DELETE` statement allows you to delete multiple entities of a
|
||||
type with a single command and without hydrating these entities. This
|
||||
can be very efficient to delete large object graphs from the database.
|
||||
3. Using foreign key semantics `onDelete="CASCADE"` can force the database
|
||||
to remove all associated objects internally. This strategy is a bit
|
||||
tricky to get right but can be very powerful and fast. You should be aware
|
||||
however that using strategy 1 (`CASCADE=REMOVE`) completly by-passes
|
||||
any foreign key `onDelete=CASCADE` option, because Doctrine will fetch and remove
|
||||
all associated entities explicitly nevertheless.
|
||||
|
||||
++ Detaching entities
|
||||
|
||||
@ -340,6 +320,107 @@ Do not blindly apply cascade=all to all associations as it will unnecessarily
|
||||
degrade the performance of your application.
|
||||
|
||||
|
||||
++ Synchronization with the Database
|
||||
|
||||
The state of persistent entities is synchronized with the database on flush of an `EntityManager`
|
||||
which commits the underlying `UnitOfWork`. The synchronization involves writing any updates to
|
||||
persistent entities and their relationships to the database. Thereby bidirectional relationships
|
||||
are persisted based on the references held by the owning side of the relationship as explained
|
||||
in the Association Mapping chapter.
|
||||
|
||||
The flush operation applies to a managed entity with the following semantics:
|
||||
|
||||
* The entity itself is synchronized to the database, if it has changed.
|
||||
|
||||
For all (initialized) relationships of the entity the following semantics apply to each
|
||||
associated entity X:
|
||||
|
||||
* If X is new and persist operations are configured to cascade on the relationship,
|
||||
X will be persisted.
|
||||
* If X is new and no persist operations are configured to cascade on the relationship,
|
||||
an exception will be thrown as this indicates a programming error.
|
||||
* If X is removed and persist operations are configured to cascade on the relationship,
|
||||
an exception will be thrown as this indicates a programming error (X would be re-persisted by the cascade).
|
||||
* If X is detached and persist operations are configured to cascade on the relationship,
|
||||
an exception will be thrown (This is semantically the same as passing X to persist()).
|
||||
|
||||
The flush operation applies to a removed entity by deleting its persistent state from the database.
|
||||
No cascade options are relevant for removed entities on flush.
|
||||
|
||||
+++ The size of a Unit of Work
|
||||
|
||||
The size of a Unit of Work mainly refers to the number of managed entities at
|
||||
a particular point in time.
|
||||
|
||||
+++ The cost of flushing
|
||||
|
||||
How costly a flush operation is, mainly depends on two factors:
|
||||
|
||||
* The size of the EntityManager's current UnitOfWork.
|
||||
* The configured change tracking policies
|
||||
|
||||
You can get the size of a UnitOfWork as follows:
|
||||
|
||||
[php]
|
||||
$uowSize = $em->getUnitOfWork()->size();
|
||||
|
||||
The size represents the number of managed entities in the Unit of Work. This
|
||||
size affects the performance of flush() operations due to change tracking
|
||||
(see "Change Tracking Policies") and, of course, memory consumption, so you
|
||||
may want to check it from time to time during development.
|
||||
|
||||
> **CAUTION**
|
||||
> Do not invoke `flush` after every change to an entity or every single invocation of
|
||||
> persist/remove/merge/... This is an anti-pattern and unnecessarily reduces the
|
||||
> performance of your application. Instead, form units of work that operate on your objects
|
||||
> and call `flush` when you are done. While serving a single HTTP request there should
|
||||
> be usually no need for invoking `flush` more than 0-2 times.
|
||||
|
||||
+++ Direct access to a Unit of Work
|
||||
|
||||
You can get direct access to the Unit of Work by calling `EntityManager#getUnitOfWork()`.
|
||||
This will return the UnitOfWork instance the EntityManager is currently using.
|
||||
|
||||
[php]
|
||||
$uow = $em->getUnitOfWork();
|
||||
|
||||
> **NOTE**
|
||||
> Directly manipulating a UnitOfWork is not recommended. When working directly with the
|
||||
> UnitOfWork API, respect methods marked as INTERNAL by not using them and carefully read
|
||||
> the API documentation.
|
||||
|
||||
+++ Entity State
|
||||
|
||||
As outlined in the architecture overview an entity can be in one of four possible states:
|
||||
NEW, MANAGED, REMOVED, DETACHED. If you explicitly need to find out what the current state
|
||||
of an entity is in the context of a certain `EntityManager` you can ask the underlying
|
||||
`UnitOfWork`:
|
||||
|
||||
[php]
|
||||
switch ($em->getUnitOfWork()->getEntityState($entity)) {
|
||||
case UnitOfWork::MANAGED:
|
||||
...
|
||||
case UnitOfWork::REMOVED:
|
||||
...
|
||||
case UnitOfWork::DETACHED:
|
||||
...
|
||||
case UnitOfWork::NEW:
|
||||
...
|
||||
}
|
||||
|
||||
An entity is in MANAGED state if it is associated with an `EntityManager` and it is not REMOVED.
|
||||
|
||||
An entity is in REMOVED state after it has been passed to `EntityManager#remove()` until the
|
||||
next flush operation of the same EntityManager. A REMOVED entity is still associated with an
|
||||
`EntityManager` until the next flush operation.
|
||||
|
||||
An entity is in DETACHED state if it has persistent state and identity but is currently not
|
||||
associated with an `EntityManager`.
|
||||
|
||||
An entity is in NEW state if has no persistent state and identity and is not associated with an
|
||||
`EntityManager` (for example those just created via the "new" operator).
|
||||
|
||||
|
||||
++ Querying
|
||||
|
||||
Doctrine 2 provides the following ways, in increasing level of power and flexibility, to query for persistent objects. You should always start with the simplest one that suits your needs.
|
||||
|
Loading…
Reference in New Issue
Block a user