0
votes

I have two entities , user and store, they have a many-to-one relationship, before I create a user, I have to make sure a store is existed, it is not allowed to create a store while creating a user ,that means cascade={"persist"} can't be used.

Store class

public function addUser(User $user)
    {
        if (!$this->users->contains($user))
        {
            $this->users->add($user);
            $user->setStore($this);
        }
        return $this;
    }

before I create a user , I am pretty sure that a store is already existed.these code below is the way I used to create user

$store= $this->get('vmsp.store_provider')->getCurrentStore();
$store->addUser($user);
$userManager->updateUser($user);

code in updateUser method is not special:

$this->entityManager->persist($user);
$this->entityManager->flush();

code in getCurrentStore method:

 public function getCurrentStore($throwException=true)
    {
        if (isset(self::$store)) {
            return self::$store;
        }

        $request = $this->requestStack->getCurrentRequest();
        $storeId = $request->attributes->get('storeId', '');

        $store = $this->entityRepository->find($storeId);
        if ($store === NULL&&$throwException) {
            throw new NotFoundHttpException('Store is not found');
        }
        self::$store = $store;


        return $store;
    }

this gives me a error:

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

thing is getting very interesting, why does a existed store become new entity? why does doctrine think that existed store entity as a new entity?

1
Looks like $this->get('vmsp.store_provider')->getCurrentStore(); does not really return a Doctrine object, so Doctrine doesn't really know it is persisted. Please show us this code ..tchap
@tcap, I updated the question , as you can see ,those code is quite normal. these code works as expected in production environment, but when is being tested, a store will be created twice, sorry for that I did't mention that this only happened in test environment.Vidy Videni
Can you please also add the code for UserManager's updateUser(). As a side note you should avoid bidirectional relationships (see docs Best Practices-chapter)dbrumann
You should get rid of self::$store and use proper caching instead. Your way will likely bring no (or close to no) performance gains, but introduces major headaches. This pretty much introduces global state that's difficult to test and might cause nasty side effects, e.g. when a different part of your code causes the current store to point to a different id.dbrumann
@dbrumann, thanks for your clue, the code for updateUser is to save the user object.Vidy Videni

1 Answers

0
votes

It seems like your Store-entity is detached from the EntityManager somehow. I can't really see where it happens. Finding that out will probably take a few debugging sessions by you.

A quick fix might be to merge the user's store back into the EntityManager using EntityManager::merge($entity), e.g. in your updateUser-method:

public function updateUser(User $user) {
    $store = $user->getStore();
    $this->entityManager->merge($store);
    $this->entityManager->persist($user);
    $this->entityManager->flush();
}

You might also want to play around with Doctrine's UnitOfWork especially with getState($entity, $assumedState) to find out whether your store is still managed or not.