DDC-3298: Persisting one to one not nullable relational entity #4078

Open
opened 2026-01-22 14:34:44 +01:00 by admin · 19 comments
Owner

Originally created by @doctrinebot on GitHub (Sep 8, 2014).

Originally assigned to: @lcobucci on GitHub.

Jira issue originally created by user bil5:

When having a not nullable onetoone unidirectional relation and trying to persist the parent entityn sql throws this exception : SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'deliveryMode_id' cannot be null.

Scheme is Shop has a deliveryMode :

class Shop{

/**
* @ORM\OneToOne(targetEntity="acme\Bundle\DeliveryBundle\Entity\DeliveryMode", cascade={"all"}, orphanRemoval=true)
* @ORM\JoinColumn(nullable=false)
* @Assert\Valid
*/
private $deliveryMode;
}

When I do a :

$shop=new Shop();
$deliveryMode=new DeliveryMode();
$shop->setDeliveryMode($deliveryMode);
...
$entityManager->persist($shop); 
$entityManager->flush();

Then, above exception is thrown

BUT: When I put in on a doctrine transaction, it works perfectly, and it also works when I remove the "not nullable" constraint, deliveryMode is perfectly persisted.

It seems to me there a bug with the order of executing the inserts, the deliveryMode should be inserted, then the shop, I think that is not the case

Originally created by @doctrinebot on GitHub (Sep 8, 2014). Originally assigned to: @lcobucci on GitHub. Jira issue originally created by user bil5: When having a not nullable onetoone unidirectional relation and trying to persist the parent entityn sql throws this exception : SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'deliveryMode_id' cannot be null. Scheme is Shop has a deliveryMode : ```php class Shop{ /** * @ORM\OneToOne(targetEntity="acme\Bundle\DeliveryBundle\Entity\DeliveryMode", cascade={"all"}, orphanRemoval=true) * @ORM\JoinColumn(nullable=false) * @Assert\Valid */ private $deliveryMode; } ``` When I do a : ```php $shop=new Shop(); $deliveryMode=new DeliveryMode(); $shop->setDeliveryMode($deliveryMode); ... $entityManager->persist($shop); $entityManager->flush(); ``` Then, above exception is thrown BUT: When I put in on a doctrine transaction, it works perfectly, and it also works when I remove the "not nullable" constraint, deliveryMode is perfectly persisted. It seems to me there a bug with the order of executing the inserts, the deliveryMode should be inserted, then the shop, I think that is not the case
admin added the Bug label 2026-01-22 14:34:44 +01:00
Author
Owner

@doctrinebot commented on GitHub (Mar 27, 2015):

Comment created by webdevilopers:

Same problem here with the following annotations:

class Bundle
{
    /**
     * @ORM\OneToOne(targetEntity="ParttypeStateNokBlocked", mappedBy="bundle", cascade={"persist"})
     */
    public $parttypeStateNokBlocked;

    /**
     * @param field_type $parttypeStateNokBlocked
     */
    public function setParttypeStateNokBlocked($parttypeStateNokBlocked) {
        $this->parttypeStateNokBlocked = $parttypeStateNokBlocked;
    }
}

class ParttypeStateNokBlocked
{
    /****
     \* @ORM\OneToOne(targetEntity="Bundle", inversedBy="parttypeStateNokBlocked")
     \* @ORM\JoinColumn(name="bundle_id", referencedColumnName="id")
     */
    public $bundle;

    public function setBundle(\Plusquam\Bundle\ContractBundle\Entity\Bundle $bundle = null)
    {
        echo "setting bundle";exit;
        $this->bundle = $bundle;

        return $this;
    }
}

Error: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'bundle_id' cannot be null

The setBundle method is not called. I tested the SQL Query for inserting the bundle and it works fine.

@doctrinebot commented on GitHub (Mar 27, 2015): Comment created by webdevilopers: Same problem here with the following annotations: ```php class Bundle { /** * @ORM\OneToOne(targetEntity="ParttypeStateNokBlocked", mappedBy="bundle", cascade={"persist"}) */ public $parttypeStateNokBlocked; /** * @param field_type $parttypeStateNokBlocked */ public function setParttypeStateNokBlocked($parttypeStateNokBlocked) { $this->parttypeStateNokBlocked = $parttypeStateNokBlocked; } } class ParttypeStateNokBlocked { /**** \* @ORM\OneToOne(targetEntity="Bundle", inversedBy="parttypeStateNokBlocked") \* @ORM\JoinColumn(name="bundle_id", referencedColumnName="id") */ public $bundle; public function setBundle(\Plusquam\Bundle\ContractBundle\Entity\Bundle $bundle = null) { echo "setting bundle";exit; $this->bundle = $bundle; return $this; } } ``` Error: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'bundle_id' cannot be null The setBundle method is not called. I tested the SQL Query for inserting the bundle and it works fine.
Author
Owner

@doctrinebot commented on GitHub (Mar 30, 2015):

Comment created by andy_b_84:

I guess I'm stupid to ask, but isn't your foreign key not nullable, which you cannot set because you don't have any key right now?
Could you mysqldump your database structure? (Or pgdump, or whatever DBS you're using)

@doctrinebot commented on GitHub (Mar 30, 2015): Comment created by andy_b_84: I guess I'm stupid to ask, but isn't your foreign key not nullable, which you cannot set because you don't have any key right now? Could you mysqldump your database structure? (Or pgdump, or whatever DBS you're using)
Author
Owner

@doctrinebot commented on GitHub (Mar 30, 2015):

Comment created by webdevilopers:

Here is my setup causing the error in 2.4.7 and 2.5.0-DEV:
https://gist.github.com/webdevilopers/a8b39361d65b7d9d5ca4

@doctrinebot commented on GitHub (Mar 30, 2015): Comment created by webdevilopers: Here is my setup causing the error in 2.4.7 and 2.5.0-DEV: https://gist.github.com/webdevilopers/a8b39361d65b7d9d5ca4
Author
Owner

@jkosmetos commented on GitHub (Jan 21, 2017):

+1

Was this ever solved?

@jkosmetos commented on GitHub (Jan 21, 2017): +1 Was this ever solved?
Author
Owner

@Ocramius commented on GitHub (Jan 21, 2017):

@jkosmetos don't see any related PRs. Consider providing a test case as a PR.

@Ocramius commented on GitHub (Jan 21, 2017): @jkosmetos don't see any related PRs. Consider providing a test case as a PR.
Author
Owner

@dkarlovi commented on GitHub (May 16, 2017):

@Ocramius at which point does the nested entity get the parent entity ID injected?

I'm just going through this with a debugger and trying to figure out why it's happening. Might be when using a custom ID generator, not sure.

@dkarlovi commented on GitHub (May 16, 2017): @Ocramius at which point does the nested entity get the parent entity ID injected? I'm just going through this with a debugger and trying to figure out why it's happening. Might be when using a custom ID generator, not sure.
Author
Owner

@dkarlovi commented on GitHub (May 16, 2017):

@Ocramius for me, this produces a ProductDetails without a Product ID persisted:

https://github.com/dkarlovi/doctrine2-1-to-1-relationship-4090

@dkarlovi commented on GitHub (May 16, 2017): @Ocramius for me, this produces a ProductDetails without a Product ID persisted: https://github.com/dkarlovi/doctrine2-1-to-1-relationship-4090
Author
Owner

@dkarlovi commented on GitHub (May 16, 2017):

Seems UOW#getEntityChangeSet returns [null, null] for product, but it should return product ID.

Or something like that, I was going through BasicEntiryPersister#prepareUpdateData and it seems values is explicitly set to NULL there. I'd give a better description but the code here is quite complex.

@dkarlovi commented on GitHub (May 16, 2017): Seems `UOW#getEntityChangeSet` returns `[null, null]` for `product`, but it should return product ID. Or something like that, I was going through `BasicEntiryPersister#prepareUpdateData` and it seems values is explicitly set to `NULL` there. I'd give a better description but the code here is quite complex.
Author
Owner

@lcobucci commented on GitHub (May 17, 2017):

@dkarlovi were you able to reproduce it using v2.6.x-dev?

@lcobucci commented on GitHub (May 17, 2017): @dkarlovi were you able to reproduce it using `v2.6.x-dev`?
Author
Owner

@dkarlovi commented on GitHub (May 17, 2017):

@lcobucci yes, just now, it's in a branch: https://github.com/dkarlovi/doctrine2-1-to-1-relationship-4090/tree/dev-master-test

it uses 334b7e68a7

@dkarlovi commented on GitHub (May 17, 2017): @lcobucci yes, just now, it's in a branch: https://github.com/dkarlovi/doctrine2-1-to-1-relationship-4090/tree/dev-master-test it uses 334b7e68a7
Author
Owner

@dkarlovi commented on GitHub (May 17, 2017):

BTW it's not related to custom ID generator as I've tried it without one.

@dkarlovi commented on GitHub (May 17, 2017): BTW it's not related to custom ID generator as I've tried it without one.
Author
Owner

@lcobucci commented on GitHub (May 17, 2017):

@dkarlovi thanks, I'll took that over 😉.

It would be amazing if for next time you could provide a failing test case (instead of a repo) for these kind of things, that helps us A LOT. You can find examples on 334b7e68a7/tests/Doctrine/Tests/ORM/Functional/Ticket

@lcobucci commented on GitHub (May 17, 2017): @dkarlovi thanks, I'll took that over :wink:. It would be amazing if for next time you could provide a failing test case (instead of a repo) for these kind of things, that helps us A LOT. You can find examples on https://github.com/doctrine/doctrine2/tree/334b7e68a7d14443962eff5452f1c7dfe92eff17/tests/Doctrine/Tests/ORM/Functional/Ticket
Author
Owner

@dkarlovi commented on GitHub (May 17, 2017):

I know, sorry about that. :( Will try to convert this to a test case.

@dkarlovi commented on GitHub (May 17, 2017): I know, sorry about that. :( Will try to convert this to a test case.
Author
Owner

@lcobucci commented on GitHub (May 17, 2017):

@dkarlovi no worries, I've found the problem on your code 😉
What we must understand is that doctrine will not inject objects on the bidirectional associations, users must do that.

Your code is fixed with:

$p = new Product;
$p->name = 'foo';
$p->details = new ProductDetails();
$p->details->product = $p;
$p->details->additional = 'bla';
$em->persist($p);
$em->flush();
@lcobucci commented on GitHub (May 17, 2017): @dkarlovi no worries, I've found the problem on your code :wink: What we must understand is that doctrine will not inject objects on the bidirectional associations, users must do that. Your code is fixed with: ```php $p = new Product; $p->name = 'foo'; $p->details = new ProductDetails(); $p->details->product = $p; $p->details->additional = 'bla'; $em->persist($p); $em->flush(); ```
Author
Owner

@dkarlovi commented on GitHub (May 17, 2017):

@lcobucci that's odd, does that apply for all association types or just 1:1 bidirectional? If I change it to a unidirectional, it will work as expected?

The problem here might also be that this case isn't validated / rejected by Doctrine (because it obviously got to the database).

@dkarlovi commented on GitHub (May 17, 2017): @lcobucci that's odd, does that apply for all association types or just 1:1 bidirectional? If I change it to a unidirectional, it will work as expected? The problem here might also be that this case isn't validated / rejected by Doctrine (because it obviously got to the database).
Author
Owner

@lcobucci commented on GitHub (May 17, 2017):

@dkarlovi bidirectional associations should be handled by the users (scroll a bit to the "In the case of bi-directional associations you have to update the fields on both sides").

Sure we could improve the documentation but I'd say that this issue could be closed as invalid if that's the root cause, what do you think @Ocramius?

@lcobucci commented on GitHub (May 17, 2017): @dkarlovi [bidirectional associations should be handled by the users](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#establishing-associations) (scroll a bit to the "In the case of bi-directional associations you have to update the fields on both sides"). Sure we could improve the documentation but I'd say that this issue could be closed as `invalid` if that's the root cause, what do you think @Ocramius?
Author
Owner

@dkarlovi commented on GitHub (May 17, 2017):

If this is expected behavior, you might want to add object validation here: Doctrine should just flat out refuse to persist if your graph is invalid (like mine was, I guess).

@dkarlovi commented on GitHub (May 17, 2017): If this is expected behavior, you might want to add object validation here: Doctrine should just flat out refuse to persist if your graph is invalid (like mine was, I guess).
Author
Owner

@lcobucci commented on GitHub (May 17, 2017):

@dkarlovi maybe you could send a PR with that suggestion? We also need to check the performance impact of that validation

@lcobucci commented on GitHub (May 17, 2017): @dkarlovi maybe you could send a PR with that suggestion? We also need to check the performance impact of that validation
Author
Owner

@mpdude commented on GitHub (Feb 27, 2023):

@lcobucci I think we can close this. To me it seems the error was that the associations were not kept in sync as required per documentation.

@mpdude commented on GitHub (Feb 27, 2023): @lcobucci I think we can close this. To me it seems the error was that the associations were not kept in sync as required per documentation.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#4078