Skip to content

Commit order issue #5538

@kilhage

Description

@kilhage

I have a very annoying issue regarding the commit order calculated by the UnitOfWork & CommitOrderCalculator components.

I have two entities, the important parts in this case looks like this:

/**
 * @ORM\Entity()
 */
class Hotel
{
    /**
     * @var HotelImage
     *
     * @ORM\ManyToOne(targetEntity="HotelImage", inversedBy="thumbnailHotels")
     * @ORM\JoinColumn(name="thumbnail_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    private $thumbnail;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="HotelImage", mappedBy="hotel")
     */
    private $images;
}
/**
 * @ORM\Entity()
 */
class HotelImage
{
    /**
     * @var Hotel
     *
     * @Assert\NotBlank()
     * @ORM\ManyToOne(targetEntity="Hotel", inversedBy="images")
     * @ORM\JoinColumn(name="hotel_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
     */
    private $hotel;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Hotel", mappedBy="thumbnail")
     */
    private $thumbnailHotels;
}

The code snippet I have problem when looks like this:

$country = $countryRepo->findByName('Sweden');
$city = $cityRepo->findByCountryAndName($country, 'Stockholm');

$hotel = $hotelRepo->findByCityAndName($city, 'Radisson Blu Waterfront Stockholm');

$image = new HotelImage();
$image->setHotel($hotel);
$hotel->addImage($image);
$em->persist($image);

$hotel2 = new Hotel();
$hotel2->setCity($city);
$hotel2->setName('xxxxxxx');
$em->persist($hotel2);

$image = new HotelImage();
$image->setHotel($hotel2);
$hotel2->addImage($image);
$em->persist($image);

$em->flush();

Then the following exception will be thrown:

  [Doctrine\DBAL\Driver\PDOException]
  SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'hotel_id' cannot be null

When looking at the sql statements executed I see these in the logs:

[2015-12-08 21:13:57] doctrine.DEBUG: INSERT INTO hotel_images (file_name, mime_type, url, code, created, updated, supplier_id, hotel_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?) {"1":null,"2":null,"3":null,"4":null,"5":"2015-12-08 21:13:56","6":"2015-12-08 21:13:56","7":null,"8":628550}
[2015-12-08 21:13:57] doctrine.DEBUG: INSERT INTO hotel_images (file_name, mime_type, url, code, created, updated, supplier_id, hotel_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?) {"1":null,"2":null,"3":null,"4":null,"5":"2015-12-08 21:13:56","6":"2015-12-08 21:13:56","7":null,"8":null}

If I instead run the following snippet:

$country = $countryRepo->findByName('Sweden');
$city = $cityRepo->findByCountryAndName($country, 'Stockholm');

$hotel2 = new Hotel();
$hotel2->setCity($city);
$hotel2->setName('xxxxxxx');
$em->persist($hotel2);

$image = new HotelImage();
$image->setHotel($hotel2);
$hotel2->addImage($image);
$em->persist($image);

$em->flush();
[2015-12-08 21:18:00] doctrine.DEBUG: INSERT INTO hotels (type, latitude, longitude, rating, user_score, number_of_reviews, phone_number, fax, url, check_in_time, check_out_time, number_of_rooms, street, postal_code, certified, certification_rating, center_distance, name, created, updated, thumbnail_id, hotel_chain_id, address_id, coordinates_id, city_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) {"1":null,"2":null,"3":null,"4":null,"5":0,"6":0,"7":null,"8":null,"9":null,"10":null,"11":null,"12":null,"13":null,"14":null,"15":false,"16":null,"17":null,"18":"xxxxxxx","19":"2015-12-08 21:18:00","20":"2015-12-08 21:18:00","21":null,"22":null,"23":null,"24":null,"25":2535}
[2015-12-08 21:18:00] doctrine.DEBUG: INSERT INTO hotel_images (file_name, mime_type, url, code, created, updated, supplier_id, hotel_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?) {"1":null,"2":null,"3":null,"4":null,"5":"2015-12-08 21:18:00","6":"2015-12-08 21:18:00","7":null,"8":642815}

The error occurs becouse depending on what entity gets persisted first, the \Doctrine\ORM\UnitOfWork::getCommitOrder will build commit order differently because the two entities are dependent of each other, but since the thumbnail_id is nullable this should still work..

One solution to this would of course be a different approach to the thumbnails but I'd stil expect the above test cases not to throw errors and the commit order to be consistent.

Please suggest a way around this without adding extra flushes, or change the order I persist the objects. I have a number of use cases in the project where this is used where I need to persist the objects in the order as in the test cases and can't add flushes because of performance reasons.

Any help is appreciated, thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions