95

since 2 weeks, we are having this problem while trying to flush new elements:

CRITICAL: Doctrine\ORM\ORMInvalidArgumentException:

A new entity was found through the relationship 'Comment#capture' that was not configured to cascade persist operations for entity

But the capture is already in the database, and we are getting it by a findOneBy, so if we cascade persist it, or persist it, we get a

Table constraint violation: duplicate entry.

The comments are created in a loop with differents captures, with a new, and all required field are set.

With all of the entities persisted and / or got by a findOne (and all valid), the flush still fails.

I'm on this issue since a while, so please help me

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
isundil
  • 1,051
  • 1
  • 7
  • 4
  • 3
    Show us some code, for example the controller and entities. – cheesemacfly Aug 13 '13 at 19:03
  • This is a related issue, might help you: http://stackoverflow.com/questions/18171801/doctrine-entities-relationship – Flip Aug 13 '13 at 20:10
  • Here is the code from the controller: http://pastebin.com/J0Keukfy, and Here is the fields from the Entity comment: http://pastebin.com/nG4rE1Pp – isundil Aug 14 '13 at 07:55
  • Is it possible that simultaneous access to doctrine provocate this error ? I also tryed to use a custom to lock doctrine, but nothing append... – isundil Aug 14 '13 at 08:05
  • 8
    Your pastebins are no longer there -> a good reason to not use links in your posts unless absolutely necessary. – crafter Feb 09 '15 at 09:49

10 Answers10

64

I had the same problem and it was the same EntityManager. I wanted to insert an object related ManyToOne. And I don't want a cascade persist.

Example :

$category = $em->find("Category", 10);

$product = new Product();
$product->setCategory($category)

$em->persist($product);
$em->flush();

This throws the same exception for me.

So the solution is :

$category = $em->find("Category", 10);

$product = new Product();
$product->setCategory($category)

$em->merge($product);
$em->flush();
Mirza Selimovic
  • 1,669
  • 15
  • 18
  • 5
    Merge causes Doctrine to find an existing $product with the same ID (lets call it $originalProduct) and merge $product with $originalProduct. Notice that this has the side-effect that all properties of $product will be copied to $originalProduct. Source: http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html The semantics of the merge operation, applied to an entity X, are as follows: If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X’ of the same identity. – Rauni Lillemets Apr 15 '15 at 08:00
  • 7
    The solution worked for me too but I'm not really satisfied with it. I think there must be something I am doing wrong somewhere (maybe in some config file) that causes this. I never had this problem on another project. – Francesco D.M. May 01 '16 at 00:17
  • 7
    @FrancescoD.M.: I had the same problem, and I first fixed it with the '_merge_' solution but I had the same unpleasant sensation as you. So I kept on searching and finally found my mistake. I realised that the entity that led to the issue was not managed by my entity manager. In fact it was just de-serialized: it was complete, including the id of course, that gave me the illusion that Doctrine was aware of it. But it was not. So I just asked the serializer (_jms_) to fetch the entity in data base (with a _SubscribingHandlerInterface_) and then the _persist_ succeeded. Hope this helps. – moudug Nov 12 '18 at 12:57
  • 2
    Took me some time but in my case it was different EM instance. – GrumpyHat May 16 '19 at 16:40
  • Worked fine, but only after I got rid of a `class 'VariablesGroup' does not exist` error. Solution was to use my class's FQN, `"App\Domain\VariablesGroup\VariablesGroup"` instead in the $em->find(...) call – Balmipour Nov 12 '20 at 17:11
  • 1
    @moudug This should be the correct answer... Save my day! Thanks! – Rodrigo Teixeira Andreotti Jan 01 '21 at 14:34
  • @RodrigoTeixeiraAndreotti indeed, mine too – javier_domenech Jan 07 '22 at 13:22
52

In my case a too early call of

$this->entityManager->clear();

caused the problem. It also disappeared by only doing a clear on the recent object, like

$this->entityManager->clear($capture);
ownking
  • 1,956
  • 1
  • 24
  • 34
52

My answer is relevant for topic, but not very relevant for your particular case, so for those googling I post this, as the answers above did not help me.

In my case, I had the same error with batch-processing entities that had a relation and that relation was set to the very same entity.

WHAT I DID WRONG:

When I did $this->entityManager->clear(); while processing batch of entities I would get this error, because next batch of entities would point to the detached related entity.

WHAT WENT WRONG:

  1. I did not know that $this->entityManager->clear(); works the same as $this->entityManager->detach($entity); only detaches ALL of the repositorie`s entities.

  2. I thought that $this->entityManager->clear(); also detaches related entities.

WHAT I SHOULD HAVE DONE:

I should have iterated over entities and detach them one by one - that would not detach the related entity that the future entities pointed to.

I hope this helps someone.

drakonli
  • 2,304
  • 23
  • 29
  • I would never have find it by myself, great answer thanks! – Hammerbot Sep 20 '16 at 09:56
  • 6
    @drakonli, you don't have to iterate over each entity to detach, you can use `$this->entityManager->clear('EntityName');` to detach only one kind of entities. Might help if the ones to detach are all of same type and no longer needed in EM – Sujan Adiga Oct 27 '18 at 13:57
11

First of all, you should take better care of your code, I see like 3 differents indentations in your entity and controller - this is hard to read, and do not fit the Symfony2 coding standards.

The code you show for your controller is not complete, we have no idea from where $this->activeCapture is coming. Inside you have a $people['capture'] which contains a Capture object I presume. This is very important.

If the Capture in $people['capture'] is persisted / fetched from another EntityManager than $this->entityManager (which, again, we do not know from where it come), Doctrine2 have no idea that the object is already persisted.

You should make sure to use the same instance of the Doctrine Entity Manager for all those operations (use spl_object_hash on the EM object to make sure they are the same instance).

You can also tell the EntityManager what to do with the Capture object.

// Refreshes the persistent state of an entity from the database
$this->entityManager->refresh($captureEntity);

// Or
// Merges the state of a detached entity into the 
// persistence context of this EntityManager and returns the managed copy of the entity.
$captureEntity = $this->entityManager->merge($captureEntity);

If this does not help, you should provide more code.

Damien
  • 5,872
  • 2
  • 29
  • 35
  • I tryed to refresh all of the activeCapture entities I have, but nothing... I'm sure that I only have one EntityManager because I use "get('doctrine.orm.default_entity_manager')". The $this->activeCapture is given here : http://pastebin.com/px0cyWs0 and the getActiveCapture here: http://pastebin.com/D0LRW2TD – isundil Aug 14 '13 at 12:19
  • Why are you detaching Captures line 36 of http://pastebin.com/px0cyWs0 ? If the capture is referenced somewhere, Doctrine doesn't know anything about it anymore and then can throw the kind of exception you got. – Damien Aug 14 '13 at 12:58
  • This process permit us to refresh the capturing entities, but this function print logs, and is not called (no debug is printed) – isundil Aug 14 '13 at 13:21
  • I'm trying to remove it, for check – isundil Aug 14 '13 at 13:29
  • 9
    +1 for mentioning that it has to be the same entity manager instance – kdazzle Oct 02 '13 at 03:59
  • To add to what @kdazzle said, in my instance I had a corner case where I had to change the database connection *after* symfony/doctrine had fetched the entity from a lookup table. This caused doctrine to think the entity was new. My solution was to retrieve the entity from doctrine after changing the database connection and set it on the main entity before persisting the main entity. Very much a corner case. – Dan Morphis Oct 17 '13 at 17:15
11

The error: 'Comment#capture' that was not configured to cascade persist operations for entity

The problem:

/**
 * @ORM\ManyToOne(targetEntity="Capture", inversedBy="comments")
 * @ORM\JoinColumn(name="capture_id", referencedColumnName="id",nullable=true)
 */
 protected $capture;

dont configured the cascade persist

try with this:

/**
 * @ORM\ManyToOne(targetEntity="Capture", inversedBy="comments", cascade={"persist", "remove" })
 * @ORM\JoinColumn(name="capture_id", referencedColumnName="id",nullable=true)
 */
 protected $capture;
M. Abbas
  • 6,409
  • 4
  • 33
  • 46
Roberto
  • 532
  • 7
  • 20
9

Refreshing the entity in question helped my case.

/* $item->getProduct() is already set */

/* Add these 3 lines anyway */
$id = $item->getProduct()->getId();            
$reference = $this->getDoctrine()->getReference(Product::class, $id);
$item->setProduct($reference);

/* Original code as follows */
$quote->getItems()->add($item);
$this->getDoctrine()->persist($quote);
$this->getDoctrine()->flush();

Despite my $item already having a Product set elsewhere, I was still getting the error.

Turns out it was set via a different instance of EntityManager.

So this is a hack of sorts, by retrieving id of the existing product, and then retrieving a reference of it, and using setProduct to "refresh" the whatever connection. I later fixed it by ensuring I have and use only a single instance of EntityManager in my codebase.

Dennis
  • 7,907
  • 11
  • 65
  • 115
1

I've seen this problem as well when you have Entities with a OneToMany <-> ManyToOne relationship.

If at the database level you have included an "on delete cascade" (when you delete the "One" side), and you don't include the concomitant cascade={"remove"} as in:

'... OneToMany(targetEntity="WhateverEntity", mappedBy="aProperty", cascade={"remove"})

Then this problem might arise.

Manuel
  • 127
  • 2
  • 11
0

I got this error too when tried to add new entity.

A new entity was found through the relationship 'Application\Entity\User#chats' 
that was not configured to cascade persist operations for entity: ###. 
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"}).

My case was that I tried to save entity, that shouldn't be saved. Entity relations was filled and tried to be saved (User has Chat in Many2Many, but Chat was a temporary entity), but there were some collisions.

So If I use cascade={"persist"} I get unwanted behaviour - trash entity is saved. My solution was to remove non-saving entity out of any saving entities:

// User entity code
public function removeFromChats(Chat $c = null){
    if ($c and $this->chats->contains($c)) {
        $this->chats->removeElement($c);
    }
}

Saving code

/* some code witch $chat entity */
$chat->addUser($user);

// saving
$user->removeFromChats($chat);
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
shukshin.ivan
  • 11,075
  • 4
  • 53
  • 69
  • Hey already mentioned that the entity is there in database , so your answer does not make any sense regarding this question. – vivex May 19 '15 at 08:57
  • @Vivek Well, I found this page via google as the most relative to the error I got, so I had to find solution by myself and finally I left it here to help others with the same error. I am sorry if it is not convinient for you. – shukshin.ivan May 19 '15 at 12:13
0

I want to tell about my case as that might be helpful to somebody.

Given two entities: AdSet and AdSetPlacemnt. AdSet has the following property:

/**
 * @ORM\OneToOne(targetEntity="AdSetPlacement", mappedBy="adSet", cascade={"persist"})
 *
 * @JMS\Expose
 */
protected $placement;

Then error appears when I try to delete some AdSet objects in a cycle after 1st iteration

foreach($adSetIds as $adSetId) {
    /** @var AdSet $adSet */
    $adSet = $this->adSetRepository->findOneBy(["id" => $adSetId]);

    $this->em->remove($adSet);
    $this->em->flush();
}

Error

A new entity was found through the relationship 'AppBundle\Entity\AdSetPlacement#adSet' that was not configured to cascade persist operations for entity: AppBundle\Entity\AdSet@00000000117d7c930000000054c81ae1. 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 'AppBundle\Entity\AdSet#__toString()' to get a clue.

Solution

The solution was to add "remove" to $placement cascade options to be: cascade={"persist","remove"}. This guarantees that Placement also becomes detached. Entity manager will "forget" about Placement object thinking of it as "removed" once AdSet is removed.


Bad alternative

When trying to figure out what's going on I've seen a couple answers or recommendations to simply use entity manager's clear method to completely clear persistence context.

foreach($adSetIds as $adSetId) {
    /** @var AdSet $adSet */
    $adSet = $this->adSetRepository->findOneBy(["id" => $adSetId]);

    $this->em->remove($adSet);
    $this->em->flush();

    $this->em->clear();
}

So that code also works, the issue gets solved but it's not always what you really wanna do. Indeed it's happens quite rarely that you actually need to clear entity manager.

Sergei Krivosheenko
  • 1,136
  • 7
  • 17
0

The issue is the identity of the entity's object that is colliding with an other entity's object. I guess you were cloning the capture object.

In my case, I was cloning a related entity. As the f prop of E was a new object, but kept the same value for the primary key, Doctrine didn't know what do to do of it.

class E
{
  /** @ORM relationship spec
    */
  private $f;

  public function __construct(F $f)
  {
    $this->f = $f;
  }

  public function __clone()
  {
    $this->f = clone $f;
  }
}

Here solutions are:

  • not to clone the related entity
  • overload F::__clone to ensure the primary key's cleansed
  • copying the object (with the default reference behaviour)

(I'm aware the topic is old, but I wish I had a clearer answer, even if the answers here helped me a lot)