I have some tables, which were modified. Added some annotation to some relation:
cascade={"persist", "remove"}
In the SQL, the fields have only a reference to another table.
Now, I want to create a migration file, and run bin/console doctrine:migrations:diff, but it does not add the constraint modification for this.
Is it possible to generate a migration file only for this entity?
Cascade persist will not be handled by your database, because it's related to how doctrine handle entities with the UnitOfWork.
Cascade delete can be managed by doctrine or your database.
Using cascade={"remove"} does not affect your database schema, as opposed to using onDelete.
That's the reason you do not see any change because there is no SQL to be executed to update your entity schema.
Basically, cascade={"remove"} will only be used by doctrine and its UnitOfWork when an $entityManager is used toremove an entity.
That's why if you execute a raw query in SQL that remove one of your entry, the cascade option will not do anything which could indeed cause an error if you use raw sql instead of Doctrine DQL.
So if you don't use any raw sql in your code that would remove an entry, it's fine to not do anything.
Otherwise, you can use onDelete which will modify your database structure.
You only need to do it for remove like this:
cascade={"persist"}, onDelete="CASCADE"
Be sure to check the documentation if you use it to understand more about it.
Related
I'm migrating the DBAL of a ZF3 application to Doctrine and want to go ahead step by step. Currently I'm using a hierarchy of Mapper objects. Each entity in the like FooEntity hierarchy has an according FooMapper. Saving of nested entities is performed by nested Mappers. Every Mappers saves its entity with Zend\Db\Sql\Insert or Zend\Db\Sql\Update and calls the proper Mappers for the sub-entities like BarMapper for BarEntity.
Now, before I start with Doctrine's convenience features like cascade={"persist"}, I want to keep the Mapper's hierarchy and just to perform the saving of the top level of the nested entity with persist(...) & flush().
But when I try it
public function save(AbstractDataObject $dataObject)
{
$newLogicalConnection = $this->logicalConnectionMapper->save($dataObject->getLogicalConnection());
$newUser = $this->userMapper->save($dataObject->getUser());
$dataObject->setLogicalConnection($this->entityManager->find(LogicalConnection::class, $newLogicalConnection->getId()));
$dataObject->setUser($this->entityManager->find(User::class, $newUser->getId()));
$this->entityManager->persist($dataObject);
$this->entityManager->flush();
return $dataObject;
}
I get an error
A new entity was found through the relationship 'MyNamespace\DataObject\AbstractEndpoint#externalServer' that was not configured to cascade persist operations for entity: MyNamespace\DataObject\ExternalServer#000000006098ccff0000000068c23676. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'MyNamespace\DataObject\ExternalServer#__toString()' to get a clue.
So, Doctrine seems to try saving the whole entity with its sub-entities, and this attempt fails on one of the lower levels. But why? I have not activated any cascade options and expect Doctrine to save only the top level.
Why does Doctrine try to save the whole entity and not only the top level? And how to get it saving only the top level of the given entity?
You get this error because you have a new entity (not persisted yet) in AbstractEndpoint->externalServer and this field is not annotated as cascade={"persist"}
In other words you have just created a new entity ExternalServer and did not persisted it and added it as a relation to AbstractEndpoint->externalServer entity which is not annotated as cascade={"persist"}
So Doctrine ends up having this new entity and does not know what to do with it. In order not to lost any data this exception is raised.
To fix this you can do two things:
Add $this->entityManager->persist($externalServer); right after you create ExternalServer entity
Annotate AbstractEndpoint->externalServer with cascade={"persist"}. Which you don't want to do because you want only top level entity to be saved to DB so you need to persist it manually or DO NOT add it is a relation.
And now answering your question:
But why? I have not activated any cascade options and expect Doctrine to save only the top level.
Somehow through relations in your object model Doctrine goes down to ExternalServer entity and finds it in unpersisted state. You can not save only top level of object hierarchy with link to unexisting record in relational database. If you do not want Doctrine to do it for you - you must handle this situations by yourself or remove not persisted entities from relations
I have a database table which has a lot of fields. I want to create an Entity which maps only to few of those fields.
Is there a practical way to achieve that?
When I try to make an entity and mapping it via annotations, the doctrine:schema:validate command says that the entity is not in sync, and is right.
When I try to make a doctrine:schema:update it automatically drops all the fields that the entity doesn't have. I want that the schema update command updates only the fields written in my entity class.
With Doctrine ORM you map your database table to a PHP class and a row from that table is mapped to an instance of the entity class.
So i am pretty sure that you have to map all your fields. Otherwise if you dont want to - user ActiveRecord, it is possible there.
If I run
php app/console doctrine:schema:update --force
It will update my database from all entities.
I need to update database only for the User entity, what is the solution?
One solution is to define a custom entity manager and then pass that entity manager to
php app/console doctrine:schema:update --force --em="custom"
But maybe it exists something faster without defining a custom entity manager?
According to the command documentation, there is no such option. If this is something you have to do only once, I'd suggest to use the --dump-sql option to get the required SQL instructions, and manually run the ones you need.
P.S. I fail to understand what's the reason to only update the schema for an entity, and leave all the rest of entities not sync'd with the database. That sounds like a recipe for getting db errors.
You can manually use the Doctrine SchemaTool class to generate an SQL diff based only on a single entity. You’ll need access to Doctrine’s EntityManager – the example below assumes access to Symfony’s container.
use Doctrine\ORM\Tools\SchemaTool;
$em = $this->container->get('doctrine')->getManager();
$schemaTool = new SchemaTool($em);
$metadata = $em->getClassMetadata(YourEntity::class);
$sqlDiff = $schemaTool->getUpdateSchemaSql([$metadata], true);
The variable $sqlDiff will now contain an array of SQL statements that are needed to bring the database schema up to date with your entity mapping.
The second argument passed to SchemaTool::getUpdateSchemaSql() is important – without it, the default behaviour would be to generate DROP TABLE statements for every other table that appears in your database.
I have the following problem with clearing entities in doctrine:
I have two entities connected together, one of which is the main-entity so to say and one of which is the sub-entity that belongs to the main-entity. Then when I use the according repository to clear, it only clears the main-entity but leaves the sub-entity.Flushing the entities is actually working fine, because the entities are connected via cascade, so when I flush the main entity, the sub-entity gets flushed also. But this cascading does not seem to work with the clear.
Is there a way to also clear all the sub-entites together with the main entities without creating an extra (and actually not needed for other things) repository for the sub-entities?
Thank you in advance.
EDIT: Ok since I've seemingly been too unspecific, my goal is to clear the entities in doctrine, not delete them in the database. The problem is, that I have a lot of entities to process and doctrine doesn't clear up all entity references in the memory. So is there a way to cascade that, or do I need the repositories for that?
LAST EDIT: Problem has been fixed by doctrine. See accepted answer!
As of the last commit, the issue is fixed. Now cascade clearing works like a charm for me.
Thanks a lot to the developers of doctrine!
Additional info, see here:
https://github.com/doctrine/doctrine2/pull/995#issuecomment-40562699
https://github.com/doctrine/doctrine2/commit/1cd0b26a40dc22b0d11b1860eb058ab9cdc29f36
You need to add cascade={"remove"} to your mapping information in the main entity for field that represent sub-entity.
You can use cascade={"remove"} for each main-entity and sub-entity; it will be do the removal for children on memory which may lead to performance overhead.
If you want to rely on DB for removal which is faster and reliable you can configure each column on delete event onDelete="CASCADE"
(however you did not provide any code but as example see below)
/**
* #ORM\OneToMany(targetEntity="SubEntity", mappedBy="mainEntity")
*/
protected $subEntiy;
and in the other entity you have
/**
* #ORM\ManyToOne(targetEntity="MainEntity", inversedBy="subEntity")
* #ORM\JoinColumn(name="entity_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $mainEntity;
I am working with two entities related by a 'one to many' relation but I'm having some problems.
Let say the entity Article has a property with a collection of Post's, and I configure the entities to use cascade. Something like that:
#ORM\OneToMany(targetEntity="Post", mappedBy="article", cascade={"remove", "persist"}, orphanRemoval=true)
When I try to save a instance of Article with his nested instances of Post's works fine but I don't want to save all the Post's anytime I change a property of the Article.
Seems like once you have the cascade relation defined you can only save using the cascade. Is not possible to enable and disable the cascade on demand and save a single entity without having to save all his childrens entities too?
Someone had this problem before and solved that somehow?
Thanks in advance!
This is expected behavior. Try to use events to update/save related entities