"EntityManager kapalı" Doktrini bu şekilde çözüldü . konu. Temel olarak, her seferinde bir istisna olduğunda (yani anahtarın kopyası) veya zorunlu bir sütun için veri sağlanmaması, Doktrinin Varlık Yöneticisini kapatmasına neden olacaktır. Hala veritabanı ile etkileşim kurmak istiyorsanız, JGrinonresetManager()
tarafından belirtildiği gibi yöntemi çağırarak Varlık Yöneticisini sıfırlamanız gerekir .
Uygulamamda, hepsi aynı şeyi yapan birden fazla RabbitMQ tüketicisi çalıştırıyordum: veritabanında bir varlığın olup olmadığını kontrol ediyor, eğer evet ise, yaratmamışsa geri ver ve sonra iade et. O varlığın zaten var olup olmadığını kontrol etmekle onu oluşturmak arasındaki birkaç milisaniye içinde başka bir tüketici de aynısını yaptı ve eksik varlığı yaratarak diğer tüketiciyi yinelenen bir anahtar istisnasına ( yarış durumu ) maruz bıraktı .
Bu, bir yazılım tasarım sorununa yol açtı. Temelde yapmaya çalıştığım şey tüm varlıkları tek bir işlemde yaratmaktı. Bu çoğu kişiye doğal gelebilir ama benim durumumda kesinlikle kavramsal olarak yanlıştı. Şu sorunu düşünün: Bu bağımlılıklara sahip bir futbol Maçı varlığını depolamam gerekiyordu.
- bir grup (örn. Grup A, Grup B ...)
- bir tur (örn. Yarı finaller ...)
- bir mekan (yani maçın yapıldığı stadyum)
- bir maç durumu (örneğin ilk yarı, maç sonu)
- maç oynayan iki takım
- maçın kendisi
Şimdi, neden mekan yaratımı maçla aynı işlemde olmalı? Veritabanımda olmayan yeni bir mekan almış olabilirim, bu yüzden önce onu oluşturmalıyım. Ama aynı zamanda o yer başka bir maça ev sahipliği yapabilir, böylece başka bir tüketici muhtemelen aynı anda onu yaratmaya çalışacaktır. Bu yüzden yapmam gereken, tüm bağımlılıkları önce ayrı işlemlerde oluşturmak ve varlık yöneticisini yinelenen bir anahtar istisnasında sıfırladığımdan emin olmaktı. Eşleşmenin yanındaki tüm varlıkların "paylaşılan" olarak tanımlanabileceğini söyleyebilirim çünkü bunlar potansiyel olarak diğer tüketicilerdeki diğer işlemlerin parçası olabilirler. Orada "paylaşılmayan" bir şey, muhtemelen aynı anda iki tüketici tarafından yaratılmayacak olan maçın kendisidir.
Bütün bunlar başka bir soruna da yol açtı. Varlık Yöneticisini sıfırlarsanız, sıfırlamadan önce aldığınız tüm nesneler tamamen yeni Doctrine içindir. Yani Doctrine, bir GÜNCELLEME çalıştırmayı denemeyecek, ancak INSERT ! Bu nedenle, tüm bağımlılıklarınızı mantıksal olarak doğru işlemlerde oluşturduğunuzdan ve ardından tüm nesnelerinizi hedef varlığa ayarlamadan önce veritabanından geri aldığınızdan emin olun. Aşağıdaki kodu bir örnek olarak düşünün:
$group = $this->createGroupIfDoesNotExist($groupData);
$match->setGroup($group);
$venue = $this->createVenueIfDoesNotExist($venueData);
$round = $this->createRoundIfDoesNotExist($roundData);
İşte bu şekilde yapılması gerektiğini düşünüyorum.
$group = $this->createGroupIfDoesNotExist($groupData);
$venue = $this->createVenueIfDoesNotExist($venueData);
$round = $this->createRoundIfDoesNotExist($roundData);
$group = $this->getGroup($groupData);
$venue = $this->getVenue($venueData);
$round = $this->getGroup($roundData);
$match->setGroup($group);
$match->setVenue($venue);
$match->setRound($round);
$matchTeamHome = new MatchTeam();
$matchTeamHome->setMatch($match);
$matchTeamHome->setTeam($teamHome);
$matchTeamAway = new MatchTeam();
$matchTeamAway->setMatch($match);
$matchTeamAway->setTeam($teamAway);
$match->addMatchTeam($matchTeamHome);
$match->addMatchTeam($matchTeamAway);
$em->persist($match);
$em->persist($matchTeamHome);
$em->persist($matchTeamAway);
$em->flush();
Umut ediyorum bu yardım eder :)