यहां बताया गया है कि मैं इसे कैसे करूंगा। मैं यह नहीं कह रहा हूं कि यह सबसे अच्छा तरीका है, अगर कोई कुछ आसान या बेहतर जानता है, तो मुझे इसे सीखने में सबसे पहले दिलचस्पी होगी।
सबसे पहले, ये हैं सिद्धांत घटनाएँ जिसका आप उपयोग कर सकते हैं। सादगी के लिए, मैं यह समझाने जा रहा हूँ कि मैं इसे हटाने के लिए कैसे करूँगा। सादगी के लिए, मैं एक स्थिर सरणी का उपयोग करने जा रहा हूं (इसे कुछ अन्य तरीकों से किया जा सकता है, मुझे यह पसंद है) और जीवनचक्र कॉलबैक . इस मामले में कॉलबैक बहुत ही सरल तरीके होने जा रहे हैं (इसीलिए श्रोता या ग्राहक )।
मान लें कि हमारे पास यह इकाई है:
Acme\MyBundle\Entity\Car:
type: entity
table: cars
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
length: '25'
unique: true
color:
type: string
length: '64'
lifecycleCallbacks:
preRemove: [entityDueToDeletion]
postRemove: [entityDeleted]
जैसा कि आप देख सकते हैं, मैंने दो कॉलबैक परिभाषित किए हैं जिन्हें प्रीरिमूव इवेंट और पोस्ट रिमूव इवेंट के साथ ट्रिगर किया जाएगा।
फिर इकाई का php कोड:
class Car {
// Getters & setters and so on, not going to copy them here for simplicity
private static $preDeletedEntities;// static array that will contain entities due to deletion.
private static $deletedEntities;// static array that will contain entities that were deleted (well, at least the SQL was thrown).
public function entityDueToDeletion() {// This callback will be called on the preRemove event
self::$preDeletedEntities[] = $this->getId();// This entity is due to be deleted though not deleted yet.
}
public function entityDeleted() {// This callback will be called in the postRemove event
self::$deletedEntities[] = $this->getId();// The SQL to delete the entity has been issued. Could fail and trigger the rollback in which case the id doesn't get stored in the array.
}
public static function getDeletedEntities() {
return array_slice(self::$preDeletedEntities, 0, count(self::$deletedEntities));
}
public static function getNotDeletedEntities() {
return array_slice(self::$preDeletedEntities, count(self::$deletedEntities)+1, count(self::$preDeletedEntities));
}
public static function getFailedToDeleteEntity() {
if(count(self::$preDeletedEntities) == count(self::$deletedEntities)) {
return NULL; // Everything went ok
}
return self::$preDeletedEntities[count(self::$deletedEntities)]; // We return the id of the entity that failed.
}
public static function prepareArrays() {
self::$preDeletedEntities = array();
self::$deletedEntities = array();
}
}
कॉलबैक और स्थिर सरणियों और विधियों पर ध्यान दें। हर बार हटाने को Car
. पर कॉल किया जाता है इकाई, preRemove
कॉलबैक इकाई की आईडी को सरणी $preDeletedEntities
. में संग्रहीत करेगा . जब निकाय हटा दिया जाता है, तो postRemove
ईवेंट आईडी को $entityDeleted
. में संग्रहीत करेगा . preRemove
घटना महत्वपूर्ण है क्योंकि हम जानना चाहते हैं कि किस इकाई ने लेन-देन को विफल कर दिया।
और अब, नियंत्रक में हम यह कर सकते हैं:
use Acme\MyBundle\Entity\Car;
$qb = $em->createQueryBuilder();
$ret = $qb
->select("c")
->from('AcmeMyBundle:Car', 'c')
->add('where', $qb->expr()->in('c.id', ':ids'))
->setParameter('ids', $arrayOfIds)
->getQuery()
->getResult();
Car::prepareArrays();// Initialize arrays (useful to reset them also)
foreach ($ret as $car) {// Second approach
$em->remove($car);
}
try {
$em->flush();
} catch (\Exception $e) {
$couldBeDeleted = Car::getDeletedEntities();
$entityThatFailed = Car::getFailedToDeleteEntity();
$notDeletedCars = Car::getNotDeletedEntities();
// Do what you please, you can delete those entities that didn't fail though you'll have to reset the entitymanager (it'll be closed by now due to the exception).
return $this->render('AcmeMyBundle:Car:errors.html.twig', array(// I'm going to respond with the ids that could've succeded, the id that failed and those entities that we don't know whether they could've succeeded or not.
'deletedCars' => $couldBeDeleted,
'failToDeleteCar' => $entityThatFailed,
'notDeletedCars' => $notDeletedCars,
));
}
आशा है ये मदद करेगा। पहले दृष्टिकोण की तुलना में इसे लागू करना थोड़ा अधिक बोझिल है लेकिन प्रदर्शन के मामले में बहुत बेहतर है।
अपडेट करें
मैं थोड़ा और समझाने की कोशिश करने जा रहा हूं कि catch
के अंदर क्या हो रहा है ब्लॉक करें:
इस बिंदु पर, लेनदेन विफल हो गया है। इस तथ्य के कारण एक अपवाद उठाया गया है कि कुछ इकाई को हटाना संभव नहीं है (उदाहरण के लिए fk बाधा के कारण)।
लेन-देन वापस ले लिया गया है और वास्तव में डेटाबेस से कोई भी प्रविष्टि नहीं हटाई गई है।
$deletedCars
एक वेरिएबल है जिसमें उन संस्थाओं की आईडी शामिल हैं जिन्हें हटाया जा सकता था (उन्होंने कोई अपवाद नहीं उठाया) लेकिन नहीं हैं (रोल बैक के कारण)।
$failToDeleteCar
उस इकाई की आईडी शामिल है जिसके विलोपन ने अपवाद को जन्म दिया है।
$notDeletedCars
इसमें शेष निकाय आईडी शामिल हैं जो लेन-देन में थे लेकिन हमें नहीं पता कि वेटर सफल होगा या नहीं।
इस बिंदु पर, आप इकाई प्रबंधक को रीसेट कर सकते हैं (यह बंद है), आईडी के साथ एक और क्वेरी लॉन्च करें जिससे समस्या नहीं हुई और उन्हें हटा दें (यदि आप चाहें) और उपयोगकर्ता को यह बताते हुए एक संदेश वापस भेज सकते हैं कि आपने उन इकाइयों को हटा दिया है और वह $failToDeleteCar
विफल रहा और हटाया नहीं गया और $notDeletedCars
भी नहीं हटाए गए। यह आपको तय करना है कि क्या करना है।
Entity::getDeletedEntities()
. के बारे में आपके द्वारा बताई गई समस्या को मैं पुन:पेश नहीं कर सकता , यह यहाँ ठीक काम कर रहा है।
आप अपने कोड को परिशोधित कर सकते हैं ताकि आपको इन विधियों को अपनी संस्थाओं में जोड़ने की आवश्यकता न हो (जीवनचक्र कॉलबैक भी नहीं)। उदाहरण के लिए, आप घटनाओं पर कब्जा करने के लिए एक ग्राहक का उपयोग कर सकते हैं और उन संस्थाओं का ट्रैक रखने के लिए स्थिर विधियों के साथ एक विशेष वर्ग का उपयोग कर सकते हैं जो असफल नहीं हुए, जो असफल रहे और जिनके पास हटाए जाने का अवसर नहीं था/ अद्यतन/सम्मिलित। मैं आपको मेरे द्वारा प्रदान किए गए दस्तावेज़ीकरण का संदर्भ देता हूं। यह जितना लगता है उससे थोड़ा अधिक जटिल है, कोड की कुछ पंक्तियों में आपको एक सामान्य उत्तर देने में सक्षम नहीं है, क्षमा करें, आपको और जांच करनी होगी।
मेरा सुझाव है कि आप मेरे द्वारा प्रदान किए गए कोड को एक नकली इकाई के साथ आज़माएँ और यह पूरी तरह से समझने के लिए कुछ परीक्षण करें कि यह कैसे काम करता है। फिर आप इसे अपनी संस्थाओं पर लागू करने का प्रयास कर सकते हैं।
शुभकामनाएँ!