I don’t understand how detach() works..
This is a use case:
/**
* @ORMEntity(repositoryClass="UsersRepository")
* @ORMTable(name="users")
*/
class Users
{
// ....
/**
* @ORMManyToOne(targetEntity="AppEntityParentType")
* @ORMJoinColumn(name="ID_PARENT_TYPE", referencedColumnName="ID_PARENT_TYPE")
*
private ParentType $parentType;
}
/**
* @ORMEntity(repositoryClass="CustomInfoRepository")
* @ORMTable(name="custom_info")
*/
class CustomInfo
{
// ....
/**
* @ORMManyToOne(targetEntity="AppEntityUsers")
* @ORMJoinColumn(name="ID_USER", referencedColumnName="ID_USER")
*
*/
private Users $user;
/**
* @ORMManyToOne(targetEntity="AppEntityParentType")
* @ORMJoinColumn(name="ID_PARENT_TYPE", referencedColumnName="ID_PARENT_TYPE")
*
private ParentType $parentType;
}
// UsersRepository
public function detach(object $entity) {
$this->_em->detach($entity);
}
// CustomInfoRepository
public function save(CustomInfo $customInfo, bool $isUpdate = false)
{
if($isUpdate === false) {
$this->_em->persist($monthlyBalance);
}
$this->_em->flush();
}
// $users = $this->createQueryBuilder('q')->getQuery()
foreach ($users->toIterable() as $user) {
// return CustomInfo object
$customInfo = $customInfoRepository->getCustomInfo($user->getId());
// update some fields of $customInfo...
$customInfoRepository->save($customInfo)
// detach $user to keep memory...
$this->usersRepository->detach($user);
}
On the first iteration: save is ok
On the second iteration: ORMInvalidArgumentException.php line 102:
A new entity was found through the relationship ‘AppEntityCustomInfo#user’ that was not configured to cascade persist operations for entity: AppEntityUsers …
Why detach() detach other entities of $users collections ?
2
Answers
In batch loop, if you get an entity but don't flush it, doctrine keep them (thanks xdebug), even after a detach
Though it’s more a guess as it’s not quite clear what changes you make with customInfo (if you do). You seems to only retrieve and immediately save again.
I would suggest that you only detached child object but parent is still managed. Try detaching customInfo as well.
EntityManager keeps track of all object saved/retrieved from db (until cleared or detached at least). This helps it to generate least possible set of SQL queries to persist the state of entities kept inside EntityManager onto your DB.
After detaching $user the state of customInfo changed (as if you destroyed the user object or set user property to null). Doctrine flush call is applied to all entities inside EntityManager hence doctrine saw change of state – it tried to save customInfo again, but the state was invalid and error was thrown
.
Doc about entity states