Jira issue originally created by user Daveet:
Also asked at SO: https://stackoverflow.com/questions/30402203
I'm adding it here as well as an issue here, because I believe it just might be Doctrine's bug.
I have User and UserProfile OneToOne–related Doctrine ORM entities. They should always exist as a pair, there should be no User without UserProfile.
User should get its id from autoincrement, while UserProfile should have User's id. So they both should have the same id and there is no other column to set up the relationship (Doctrine docs: Identity through foreign Entities).
User's id is both a primary key (PK) and foreign key (FK) at the same time.
I managed to set it up, but it requires that User is saved first and only later UserProfile is created and saved in a separate step.
What I want is that UserProfile is always created with User, in the constructor, but if I do that, I get this exception:
Doctrine\ORM\ORMInvalidArgumentException: The given entity of type 'AppBundle\Entity\UserProfile' (AppBundle\Entity\UserProfile@0000000052e1b1eb00000000409c6f2c) has no identity/no id values set. It cannot be added to the identity map.
Please see code below – it works, but not the way I want. The php comments show what I want to achieve.
/****
* It works, both saving and loading.
* BUT, it requires that I create and save UserProfile
* in a separate step than saving User step.
*/
// create and save User
$user = new User();
$objectManager->persist($user);
$objectManager->flush();
// create and save UserProfile (this should be unnecessary)
$user->createProfile()
$objectManager->flush();
use Doctrine\ORM\Mapping as ORM;
/****
* @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
* @ORM\Table(name="users")
*/
class User
{
/****
* @var int
*
* @ORM\Column(name="uid", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/****
* It's NULL at first, I create it later (after saving User).
*
* @var UserProfile|null
*
* @ORM\OneToOne(targetEntity="UserProfile", mappedBy="user", cascade="persist")
*/
private $profile = null;
public function **construct()
{
// I want to create UserProfile inside User's constructor,
// so that it is always present (never NULL):
//$this->profile = new UserProfile($this);
// but this would give me error:
//
// Doctrine\ORM\ORMInvalidArgumentException:
// The given entity of type 'AppBundle\Entity\UserProfile'
// (AppBundle\Entity\UserProfile@0000000058af220a0000000079dc875a)
// has no identity/no id values set. It cannot be added to the identity map.
}
public function createProfile()
{
$this->profile = new UserProfile($this);
}
}
use Doctrine\ORM\Mapping as ORM;
/****
* @ORM\Entity
* @ORM\Table(name="profiles")
*/
class UserProfile
{
/****
* – UserProfile's "uid" column points to User's "uid" column
* – it is PK (primary key)
* - it is FK (foreign key) as well
* – "owning side"
*
* @var User
*
* @ORM\Id
* @ORM\OneToOne(targetEntity="User", inversedBy="profile")
* @ORM\JoinColumn(name="uid", referencedColumnName="uid", nullable=false)
*/
private $user;
public function **construct(User $user)
{
$this->user = $user;
}
}
Hello,
I would like to ask you if is there any progress? I have the same problem.
Thank you.
Hello, is there any progress with this bug? Is it fixed
Same issue for me. It there any fix or workaround?
+1
Same here.
any fix or workaround?
This was already fixed on #1570 when $weight was introduced on CommitOrderCalculator.
I've ran the test bellow on master and it passes with no issues, so I'm closing this issue.
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
class xxxxTest extends OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(xxxxUser::class),
$this->_em->getClassMetadata(xxxxUserProfile::class),
]
);
}
public function testThingsWorks()
{
$user = new xxxxUser();
$this->_em->persist($user);
$this->_em->flush();
}
}
/**
* @Entity
*/
class xxxxUser
{
/**
* @Id
* @Column(name="uid", type="integer")
* @GeneratedValue(strategy="AUTO")
*
* @var int
*/
private $id;
/**
* @var xxxxUserProfile|null
*
* @OneToOne(targetEntity=xxxxUserProfile::class, mappedBy="user", cascade="persist")
*/
private $profile = null;
public function __construct()
{
$this->profile = new xxxxUserProfile($this);
}
}
/**
* @Entity
*/
class xxxxUserProfile
{
/**
* – UserProfile's "uid" column points to User's "uid" column
* – it is PK (primary key)
* - it is FK (foreign key) as well
* – "owning side"
*
* @var xxxxUser
*
* @Id
* @OneToOne(targetEntity=xxxxUser::class, inversedBy="profile")
* @JoinColumn(name="uid", referencedColumnName="uid", nullable=false)
*/
private $user;
public function __construct(xxxxUser $user)
{
$this->user = $user;
}
}
On the PR we have the explanation why this wasn't backported on v2.5.x.
I have the same issue
@lcobucci Your test is wrong, I've checked it on the last version and UserProfile is not actually saved after flush, it's not passed to UOW::scheduleForInsert() as well as to UOW::addToIdentityMap(), that's why there is no exception. But if you manually persist profile before flush you'll get this:
Doctrine\ORM\ORMInvalidArgumentException: The given entity of type 'Doctrine\Tests\ORM\Functional\Ticket\xxxxUserProfile' (Doctrine\Tests\ORM\Functional\Ticket\xxxxUserProfile@0000000036941110000000004e41ba5a) has no identity/no id values set. It cannot be added to the identity map.
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/ORMInvalidArgumentException.php:68
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/UnitOfWork.php:1402
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/UnitOfWork.php:1214
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/UnitOfWork.php:900
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/UnitOfWork.php:1664
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/UnitOfWork.php:1620
/home/user/projects/lib/doctrine2/lib/Doctrine/ORM/EntityManager.php:595
/home/user/projects/lib/doctrine2/tests/Doctrine/Tests/ORM/Functional/Ticket/xxxxTest.php:24
```php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
class xxxxTest extends OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(xxxxUser::class),
$this->_em->getClassMetadata(xxxxUserProfile::class),
]
);
}
public function testThingsWorks()
{
$user = new xxxxUser();
$this->_em->persist($user);
$this->_em->persist($user->getProfile());
$this->_em->flush();
}
}
/**
/****
* @var xxxxUserProfile|null
*
* @OneToOne(targetEntity=xxxxUserProfile::class, mappedBy="user", cascade={"persist"})
*/
private $profile = null;
public function __construct()
{
$this->profile = new xxxxUserProfile($this);
}
public function getProfile()
{
return $this->profile;
}
}
/**
public function __construct(xxxxUser $user)
{
$this->user = $user;
}
}
__Upd.__ the problem is in four asterisks in phpdoc for `$profile` property, doctrine doesn't see that annotation and User has no relation:
```php
/**** <------ wrong phpdoc
* @var xxxxUserProfile|null
*
* @OneToOne(targetEntity=xxxxUserProfile::class, mappedBy="user", cascade={"persist"})
*/
private $profile = null;
@igaponov you're right about the docblock, now my test fails as well... and it actually fails on persist() and not flush().
IMO this is an edge-case since it only happens if xxxxUser#id is a post insert generated id (auto increment or sequences). If strategy is NONE or UUID it works just fine.
@guilhermeblanco @Ocramius I'd say this is a won't fix and we should actually document this, what do you think?
After updating to Doctrine 2.6 I get the same error while before it was working fine. I now have to use two persist and flush calls even though the main entity has the cascade option set to persist. Plus, I was relying on the fact that all INSERT queries were automatically executed in a transaction and that if any of the statements failed everything failed as well but now I have to wrap all entity operations inside a transactional function call
Im also hitting the same issue. I've identified it for now with int(1) as a value is generated anyway. WFM :) but totally unexpected yes.
Just followed the doctrine docs on Identity through foreign Entities and stumbled upon this bug.
When I create a new Article using the entities declared in "Use-Case 1: Dynamic Attributes", I get the mentioned exception:
$article = new Article();
$article->addAttribute("foo", "bar");
$this->em->persist($article); // throws ORMInvalidArgumentException
This was really unexpected.
@ro0NL thanks for the tip. Initializing the auto-generated id works:
class Article
{
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
private $id = -1;
Maybe this bug should be reopened? Or mentioned in the docs?
I have the same error too after updating to Doctrine 2.6. I can't apply the @ro0NL tip because I can't change the DB structure.
For people having issues with 2.6, see #7003.
Most helpful comment
For people having issues with 2.6, see #7003.