-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
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.