Wow, this is very strange:
$bar = new Bar();
$foo = $entity->getFoo();
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
and I obtain the following message
A new entity was found through the relationship [....]
By reading on the net, I undertand that if fetch two object from two different entity managers, one manager will doesn't know about entities fetched from other manager. Since here I'm into a "db hook" (postPersist) and I've manager injected from DIC, I've tried to change my code in agreement:
$bar = new Bar();
$foo_id = $entity->getFoo()->getId();
$foo = $em->getRepository('MyBundleName:Foo')->findOneBy(array('id'=>$foo_id));
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
but nothing changed.
Can someone point me to right direction and, most important, explain what's going on here?
UPDATE
I've migrated all code outside db hooks and I've created a new service that will do pretty much same things of hooks but has to called explicitly after flush() Is very strange, however, that nothing changed. I've also tried to use spl_obj_hash onto entity manager for retrieve information about the entity manager who flush object into db and "other one" that will retrieve $foo from db and try to persist $bar.
This is the result:
SPL_OBJ ENTITY MANAGER - 1: 0000000021770e03000000001eda54f7
SPL_OBJ ENTITY MANAGER - 2: 0000000021770e03000000001eda54f7
if I'm not wrong, they're the same entity manager object. I'm pretty confused actually...
UPDATE - WORKING CODE
I've found a "code combination" that will do the work but I'm still pretty confused about it.
If I use first snippet of code (where $foo is retrieved from $entity itself) and flush only $bar, error is still there.
If I use second snippet of code (where $foo is retrieved from entity manager) and persist only $bar, all works properly (obviosuly if I call $flush() without parameters, issue is still there)
I had the same problem and resolved it, I'm posting it because I haven't seen it mentioned anywhere and it might help someone.
I have a service that parses data & persists it to entities, service to which I'm feeding the entityManager & child entities. And I started to have the same error on persist. Using merge() didn't help as it just threw me "A managed dirty+entity [...]" error instead.
After a little digging it seems that as far as Doctrine is concerned the entities I was feeding my service came from a different entityManager, so you actually have to get the entities from the entityManager inside the service if you are using it to persist.
I fixed mine by removing clear
$this->getDoctrine()->getManager()->clear();
I'm not sure since I never had this issue before and right now I'm not in the position to replicate it. But I will give you some options I would try:
If the two entitymanagers are using the same database you can merge (http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html#merging-entities) the entity into the other entitymanager. In this case that will look something like this:
$em->merge($foo);
This makes sure the entity $foo is managed by your entitymanager.
Also, remember that a postPersist is executed after the database operations. I think you have better chances if you try your modified code in a prepersist method.
As the documentation says:
prePersist - The prePersist event occurs for a given entity before the respective
EntityManager persist operation for that entity is executed.
postPersist - The postPersist event occurs for an entity after the entity has
been made persistent. It will be invoked after the database insert
operations. Generated primary key values are available in the
postPersist event.
Full documentation can be found here: http://docs.doctrine-project.org/en/2.0.x/reference/events.html#lifecycle-events
Just try this and let me know the result
Try : $em->merge($bar);
$bar = new Bar();
$foo = $entity->getFoo();
$bar->setFoo($foo);
$em->merge($bar);
$em->flush();
[1] Doctrine - A new entity was found through the relationship
It's not so clear from your code, but I think you create a new $foo, but you don't save it before to save $bar.
Try this:
$em->persist($foo);
$em->flush();
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
In general you can escape this by using cascade=persist on the association of your entities.
Related
I'm struggling to find a way to perform a persist() and flush() methods after the final flush (I mainly want to do it in postFlush event).
I collect the necessary entities in onFLush event (with changeSets) and wait up until all entities (which I collected) got flushed to get their id's (auto incremented).
So that I have at this point an array with all needed entities and their change sets and their id's set.
Then I want to create new entities (let's call them "traces") based on fields of previously collected entities and persist & flush "traces" in database.
But I'm really stuck here as I can't know entities id's in onFlush event, and I can't persist & flush them in postFlush when they already have their id's set.
Currently Doctrine documentation states following:
postFlush is called at the end of EntityManager#flush(). EntityManager#flush() can NOT be called safely inside its listeners.
And if I dare do this, it ends up in a recursion and php fails with an error.
Which approach may I take here?
I believe you could do a check if you aren't flushing "traces" entity and then perform your "traces" creation. That shouldn't loop.
Also you might want to look at symfony's eventDispatcher . You could dispatch your events manually, since it might be cleaner.
More details on "traces" would be helpful, from what I can imagine it is some kind of a changelog, history; so for that I might suggest EntityAuditBundle. It works pretty good with doctrine and is not hard to set up, I am using it myself.
For an blog entry entity I am loading data from an api via the doctrine postloadEvent. For this i created a listener service with an postloadMethod in it.
public function postLoad(BlogEntry $blogEntry)
{
$blogentry->setName($apiClient->getName($blogEntry->getId()))
$blogentry->setContent($apiClient->getContent($blogEntry->getId()))
...
}
This means, there is already a local repository with blog entries. These blogentries are connected to a blog. If i now only want to count the blogentries for each blog, i would implement a getBlogEntryCount() method on the BlogEntry entity and call it.
$blog->getBlogEntryCount();
The problem now is, that the postLoad event is triggered unnecessary, even if i need no data from the api.
How can i avoid this behaviour in doctrine/symfony/sonata admin? Is there mechanism like "lazy loading" for doctrine entities?
Update to Jose M. González Solution
To get only the count of the collection, the extra_lazy loading solution will do it.
For getting local information without triggering the api call i used the said repository function. To get this information working in list view in sonata admin, i created a non-doctrine-related array field "blogEntriesSimple" in my Blog Entity next to my "blogEntries" (which is normally holding the complete entity) field.
I attached an entitylistener with postLoad function to the Blog Entity, which is filling up my blogEntriesSimple array with the information from my custom repository function.
Thats it.
I think this solution is a bit hacky, but until no cleaner solution is available, this will do it.
i think that you can achieve this with the extra lazy associations that permit that you count your related entities without hydrating it
Edited
Also you can do a DQL query that only hidrate a partial view of your entity and it can be used to count the rows and access to your properties, for example:
select be.id,be.title from AppBundle\Entity\BlogEntry be
This query must not trigger the postLoad event
I hope this can help you
I am building an app with Symfony.
I've got a Doctrine entity that contains (among other properties) a collection of another Entity (forming a OneToMany association).
Class OuterEntity
{
/**
* #ORM\OneToMany(targetEntity="InnerEntity", mappedBy="outer", cascade={"persist", "remove"})
*/
private $inners;
}
In my OuterEntityController, in the updateOuterEntityAction method, i do the following :
parse the request
get the updated Outer from db
modify it according to the request
call flush() on the entity manager
call findAll() on the OuterEntity repository
return the OuterEntity list to the client in a JsonResponse in order to notify it of the new state of the db. Since I use a JsonResponse, I let Symfony do the serialization (very probably with json_encode).
Everything is allright except when I delete one or more InnerEntity in the association. The issue does not come from the removal, but from the returned json format. Most of the times, the inners I get are under the form of a simple array:
{"inners":[{inner1},{inner2},...]}
, which is fine for me. But after a removal from this association (in the example, I assume the 2nd one was deleted), I get an array like this:
{"inners":{"0":{inner1},"2":{inner2},"3":{...},...}
Furthermore, this issue doesn't happen if the last Inner is deleted (or several Inners all located at the end of the array).
My supposition is that Doctrine places the association in an associative array and when json_encode serializes this array, it renders in the first format if the indexation is normal (0, 1, 2...), or in the second format if the indexation is broken (0, 2, 3...).
So my question is now : why doctrine does not place the result in a "normally indexed" array after a removal?
I think there's something going on with Doctrine's caching mechanism, but I can't figure exactly what. Maybe it's because the entity manager still considers the deleted entities. But I thought that the entity manager was cleared after the flush, isn't it?
I tried to call clear() on the entity manager, but I've had some strange behaviour and quickly gave up.
I'd be glad if one of you could point the mistake I am making.
It seems that the problem is on my side of the keyboard.
I don't know why, but I retried to clear the entity manager today, and everything works just fine as I first expected. I must have made a really dumb move at my first try.
Thanks everybody for the help, and sorry for the inconvenience.
I've got custom entity repository (let's say CategoryRepository) that returns Doctrine entities. I also have newly created entity (let's say Product) that I want to persist.
Product is related to Category and, in that case, Product is the owning side of the relationship so I've got following code:
$category = $categoryRepository->customGetCategory($someCriteria);
$product = new Product();
$product->setCategory($category);
$em->persist($product);
and result is
[Doctrine\ORM\ORMInvalidArgumentException]
A new entity was found through the relationship
'Acme\SomethingBundle\Entity\Product#category' that was not configured
to cascade persist operations for entity: blahblah. 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"})
For now I'm aware that all entities returned by custom repository methods using \Doctrine\ORM\Query::getResult() method where Query object is returned by EntityManager::createQuery($dql) factory method are detached by default. So I've got entity returned by repository that exists in database and I can't find a way for doctrine to have it managed just like any entity returned by f. ex. $repository->findBy() method.
Could anyone point me in right direction with this? I'd really like to solve that, it's killing me.
This is probably one of the top 5 Doctrine questions asked. Just difficult to search for. Could try searching on the error message.
The problem is that Category::setProduct is never being called. Update your Product entity with:
class Product
{
public function setCategory($category);
{
$this->category = $category;
$category->setProduct($this); // *** Add this
}
}
I am doing my first project with Symfony2 + Doctrine, and currently trying to implement replacing records. However when I try to call
$em->save($product);
or
$em->replace($product);
(instead of)
$em->persist($product);
I get fatal errors. So I started digging around to try to find the persist() method so I could see what other methods were available. I searched the entire contents of the vendors/doctrine directory and could not find any references to the persist or flush methods. Where the heck are these located? I tried following the code but quickly got lost.
So the main question: How can I do a replace() with doctrine in Symfony2?
Sub-question: Where are the persist() and flush() methods? Not being able to find them is frustrating in itself.
Incase somebody else is wondering, try looking into:
$em = $service->get('doctrine.orm.entity_manager');
$entity = $em->merge($entity);
$em->flush();
From the docs, Doctrine\ORM\EntityManager::merge():
Merges the state of a detached entity into the persistence context of
this EntityManager and returns the managed copy of the entity. The
entity passed to merge will not become associated/managed with this
EntityManager.
Should do the trick for you.
I don't think that Doctrine's replace() method is supported in Symfony, or at least it is not accessible through EntityManager.
If you need to update your existing entity, then you can simply do it as described here - http://symfony.com/doc/current/book/doctrine.html#updating-an-object.
As for persist() and flush() methods - you can find them in vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php