0

We have a weird problem in our project where certain Doctrine entities are not being saved. The problem does not occur every time but intermittently and we have no idea what's causing it.

We have two linked entities that are saved thus:

$one = (new One)
    ->setValues()
    ...
;
$two = (new Two)
    ->setOne($one)
    ->setUser($user)
;
$em->persist($one);
$em->persist($two);
$em->flush();

The relationships/entities are defined as follows:

class User {
...

    /**
     * @var Two[]|Collection
     * @ORM\OneToMany(targetEntity="Two", mappedBy="user")
     */
    private $twos;
...
}

class One {
...
    /**
     * @var Two[]|Collection
     * @ORM\OneToMany(targetEntity="Two", mappedBy="one")
     */
    private $twos;
...
}

Class Two {
...
    /**
     * Note this field in the db is an auto-increment
     * @ORM\Column(name="two_id", type="integer")
     */
    private $id;
    /**
     * @var One
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="One", inversedBy="twos")
     * @ORM\JoinColumn(name="one_id", referencedColumnName="one_id")
     */
    private $one;
    /**
     * @var User
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="User", inversedBy="twos")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
     */
    private $user;
...
}

We are not seeing any errors, and when we enable debug logging in DBAL we can see log entries for the start of the transaction, all inserts (including for Two) and for the commit. We cannot reproduce the problem locally so cannot use a step debugger to work through it. Most of the time both entities are saved but not every time.

If we clear the Two entity from the ObjectManager and try to reload it from the database, it is showing that it does have an id.

$em->clear(Two::class);

$two = $twoRepository->findTwo($user, $one);
if ($two) {
    $logger->info('Two created', ['two' => $two->getId(),]);
}

Now, when we get an occurrence of Two not being saved, we can see a log which is outputting an id but when we then check the relevant db table, there is no row with that id in it.

No exceptions are thrown at any point and we cannot see any other log that might indicate a problem.

We have no idea what might be happening. The fact that the entity is given an auto-increment but isn't saved suggests that perhaps there is a problem in the db transaction. But, as I understand it, the transaction would happen within the call to flush() and there is no indication of that transaction having to be rolled back. Plus the subsequent call to reload the entity from the db happens after that so Doctrine must either be retrieving that entity from the database or from it's internal object store (although it's mu understanding that the clear() should mean it has to go back to the db to load that entity).

liquorvicar
  • 6,081
  • 1
  • 16
  • 21
  • Are you using transaction nesting? This is a terrible feature of some ORM packages that might cause confusing results like you describe. DBAL uses it: https://www.doctrine-project.org/projects/doctrine-dbal/en/2.10/reference/transactions.html#transaction-nesting See my answer here for explanation of why this is bad: https://stackoverflow.com/a/319939/20860 – Bill Karwin Jan 20 '20 at 17:09
  • Thanks for the suggestion @BillKarwin. Interesting to read those links. Turns out it wasn't that at all and actually another part of our system was allowing users to delete the entities from the UI. – liquorvicar Jan 21 '20 at 16:22
  • Okay, that would certainly explain it! :-) – Bill Karwin Jan 21 '20 at 16:25

1 Answers1

0

False alarm. Turns out our system was allowing users to delete entity Two from the UI (but not entity One). The site is fairly high traffic and a bunch of users were doing this shortly after creating the entities in the first place which made it looks like the entities were not being created at all.

liquorvicar
  • 6,081
  • 1
  • 16
  • 21