symfony EntityManager बंद है




orm doctrine2 (9)

[Doctrine\ORM\ORMException]   
The EntityManager is closed.  

डेटा डालने पर मुझे डीबीएएल अपवाद मिलने के बाद, EntityManager बंद हो जाता है और मैं इसे फिर से कनेक्ट करने में सक्षम नहीं हूं।

मैंने ऐसा करने की कोशिश की लेकिन इसे कनेक्शन नहीं मिला।

$this->em->close();
$this->set('doctrine.orm.entity_manager', null);
$this->set('doctrine.orm.default_entity_manager', null);
$this->get('doctrine')->resetEntityManager();
$this->em = $this->get('doctrine')->getEntityManager();

किसी को भी फिर से कनेक्ट करने का विचार है?


इस तरह मैंने सिद्धांत को हल किया "EntityManager बंद है।" मुद्दा। असल में प्रत्येक बार एक अपवाद होता है (यानी डुप्लिकेट कुंजी) सिद्धांत इकाई प्रबंधक को बंद कर देता है। यदि आप अभी भी डेटाबेस से बातचीत करना चाहते हैं तो आपको JGrinon द्वारा वर्णित resetManager() विधि को कॉल करके एंटीटी मैनेजर को रीसेट करना होगा

मेरे आवेदन में मैं कई खरगोश एमक्यू उपभोक्ताओं को चला रहा था जो सभी एक ही काम कर रहे थे: यदि डेटाबेस में कोई इकाई मौजूद है, तो जांच करें, अगर हाँ इसे वापस कर दें, तो इसे न बनाएं और फिर इसे वापस कर दें। कुछ मिलीसेकंड में यह जांचने के बीच कि क्या वह इकाई पहले से मौजूद है और इसे बनाने के लिए एक और उपभोक्ता ऐसा ही हुआ और गायब इकाई को अन्य उपभोक्ता को डुप्लिकेट कुंजी अपवाद में बनाने के लिए बनाया गया।

इसने एक सॉफ्टवेयर डिजाइन समस्या का नेतृत्व किया। असल में जो मैं करने की कोशिश कर रहा था वह सभी लेनदेन में सभी इकाइयों को बना रहा था। यह सबसे अधिक प्राकृतिक महसूस कर सकता है लेकिन मेरे मामले में निश्चित रूप से अवधारणात्मक रूप से गलत था। निम्नलिखित समस्या पर विचार करें: मुझे एक फुटबॉल मैच इकाई को स्टोर करना था जिसमें इन निर्भरताओं थी।

  • एक समूह (यानी समूह ए, समूह बी ...)
  • एक दौर (यानी अर्ध-फाइनल)
  • एक स्थल (यानी स्टेडियम जहां मैच हो रहा है)
  • एक मैच स्थिति (यानी आधे समय, पूर्णकालिक)
  • दो टीमें मैच खेल रही हैं
  • मैच खुद ही

अब, क्यों स्थल निर्माण एक ही लेनदेन में मैच के रूप में होना चाहिए? ऐसा हो सकता है कि मुझे अभी एक नया स्थान मिला है कि यह मेरे डेटाबेस में नहीं है इसलिए मुझे इसे पहले बनाना है। लेकिन यह भी हो सकता है कि वह स्थान एक और मैच होस्ट कर सके, इसलिए एक और उपभोक्ता शायद इसे एक साथ बनाने की कोशिश करेगा। तो मुझे क्या करना था, यह सुनिश्चित करने के लिए कि मैं इकाई प्रबंधक को डुप्लिकेट कुंजी अपवाद में रीसेट कर रहा था, अलग-अलग लेन-देन में पहले सभी निर्भरताओं को बना रहा था। मैं कहूंगा कि मैच के बगल में मौजूद सभी इकाइयों को "साझा" के रूप में परिभाषित किया जा सकता है क्योंकि वे संभावित रूप से अन्य उपभोक्ताओं में अन्य लेनदेन का हिस्सा बन सकते हैं। कुछ ऐसा जो "साझा" नहीं होता है वह मैच ही होता है जो एक ही समय में दो उपभोक्ताओं द्वारा नहीं बनाया जाएगा। तो आखिरी लेनदेन में मैं सिर्फ दो टीमों और मैच के बीच मैच और संबंध देखने की उम्मीद करता हूं। इन सभी ने भी एक और मुद्दा उठाया। यदि आप एंटिटी मैनेजर को रीसेट करते हैं, तो रीसेट करने से पहले आपके द्वारा पुनर्प्राप्त की गई सभी ऑब्जेक्ट्स पूरी तरह से सिद्धांत के लिए हैं। तो सिद्धांत उन पर एक अद्यतन चलाने की कोशिश नहीं करेगा, लेकिन एक इंसर्ट ! तो सुनिश्चित करें कि आप अपनी सभी निर्भरताओं को तार्किक रूप से सही लेन-देन में बनाते हैं और फिर अपनी सभी ऑब्जेक्ट को डेटाबेस से वापस लक्ष्य इकाई में सेट करने से पहले पुनर्प्राप्त करें। उदाहरण के रूप में निम्न कोड पर विचार करें:

$group = $this->createGroupIfDoesNotExist($groupData);

$match->setGroup($group); // this is NOT OK!

$venue = $this->createVenueIfDoesNotExist($venueData);

$round = $this->createRoundIfDoesNotExist($roundData);

/**
 * If the venue creation generates a duplicate key exception
 * we are forced to reset the entity manager in order to proceed
 * with the round creation and so we'll loose the group reference.
 * Meaning that Doctrine will try to persist the group as new even
 * if it's already there in the database.
 */

तो इस तरह मुझे लगता है कि यह किया जाना चाहिए।

$group = $this->createGroupIfDoesNotExist($groupData); // first transaction, reset if duplicated
$venue = $this->createVenueIfDoesNotExist($venueData); // second transaction, reset if duplicated
$round = $this->createRoundIfDoesNotExist($roundData); // third transaction, reset if duplicated

// we fetch all the entities back directly from the database
$group = $this->getGroup($groupData);
$venue = $this->getVenue($venueData);
$round = $this->getGroup($roundData);

// we finally set them now that no exceptions are going to happen
$match->setGroup($group);
$match->setVenue($venue);
$match->setRound($round);

// match and teams relation...
$matchTeamHome = new MatchTeam();
$matchTeamHome->setMatch($match);
$matchTeamHome->setTeam($teamHome);

$matchTeamAway = new MatchTeam();
$matchTeamAway->setMatch($match);
$matchTeamAway->setTeam($teamAway);

$match->addMatchTeam($matchTeamHome);
$match->addMatchTeam($matchTeamAway);

// last transaction!
$em->persist($match);
$em->persist($matchTeamHome);
$em->persist($matchTeamAway);
$em->flush();

मुझे उम्मीद है यह मदद करेगा :)


यह वास्तव में पुराना मुद्दा है, लेकिन मुझे बस इसी तरह की समस्या थी। मैं ऐसा कुछ कर रहा था:

// entity
$entityOne = $this->em->find(Parent::class, 1);

// do something on other entites (SomeEntityClass)
$this->em->persist($entity);
$this->em->flush();
$this->em->clear();

// and at end I was trying to save changes to first one by
$this->em->persist($entityOne);
$this->em->flush();
$this->em->clear();

समस्या यह थी कि पहले सभी समेत सभी इकाइयों को अलग करें और त्रुटि फेंक दें EntityManager बंद है।

मेरे मामले में समाधान केवल विशिष्ट प्रकार की इकाई पर स्पष्ट करना था और $entityOne इकाई छोड़ना अभी भी ईएम के तहत है:

$this->em->clear(SomeEntityClass::class);

आप अपने ईएम को रीसेट कर सकते हैं

// reset the EM and all aias
$container = $this->container;
$container->set('doctrine.orm.entity_manager', null);
$container->set('doctrine.orm.default_entity_manager', null);
// get a fresh EM
$em = $this->getDoctrine()->getManager();

मुझे यह मुद्दा था। यह मैंने इसे कैसे तय किया।

फ़्लश या जारी रखने की कोशिश करते समय कनेक्शन बंद हो रहा है। इसे फिर से खोलने का प्रयास करना एक खराब विकल्प है क्योंकि नए मुद्दे पैदा करते हैं। मैंने यह समझने की कोशिश की कि कनेक्शन क्यों बंद कर दिया गया था और पाया कि मैं लगातार बने रहने से पहले बहुत सारे संशोधन कर रहा था।

जारी रखें () पहले इस मुद्दे को हल किया।


नियंत्रक में।

अपवाद इकाई प्रबंधक को बंद कर देता है। यह थोक सम्मिलन के लिए परेशानी बनाता है। जारी रखने के लिए, इसे फिर से परिभाषित करने की आवश्यकता है।

/** 
* @var  \Doctrine\ORM\EntityManager
*/
$em = $this->getDoctrine()->getManager();

foreach($to_insert AS $data)
{
    if(!$em->isOpen())
    {
        $this->getDoctrine()->resetManager();
        $em = $this->getDoctrine()->getManager();
    }

  $entity = new \Entity();
  $entity->setUniqueNumber($data['number']);
  $em->persist($entity);

  try
  {
    $em->flush();
    $counter++;
  }
  catch(\Doctrine\DBAL\DBALException $e)
  {
    if($e->getPrevious()->getCode() != '23000')
    {   
      /**
      * if its not the error code for a duplicate key 
      * value then rethrow the exception
      */
      throw $e;
    }
    else
    {
      $duplication++;
    }               
  }                      
}

कम से कम सिम्फनी 2.0 और सिद्धांत 2.1 के लिए यह एक बहुत ही मुश्किल समस्या है, इसलिए इसे बंद करने के बाद EntityManager को फिर से खोलना किसी भी तरह से संभव नहीं है।

इस समस्या को दूर करने का एकमात्र तरीका यह है कि आप अपना खुद का डीबीएएल कनेक्शन क्लास बनाएं, सिद्धांत को लपेटें और अपवाद हैंडलिंग प्रदान करें (जैसे EntityManager को अपवाद पॉप करने से पहले कई बार पुनः प्रयास करना)। यह थोड़ा हैकी है और मुझे डर है कि यह लेन-देन वातावरण में कुछ असंगतता पैदा कर सकता है (यानी मुझे वास्तव में यकीन नहीं है कि क्या होता है यदि असफल क्वेरी लेनदेन के बीच में होती है)।

इस तरह से जाने के लिए एक उदाहरण कॉन्फ़िगरेशन है:

doctrine:
  dbal:
    default_connection: default
    connections:
      default:
        driver:   %database_driver%
        host:     %database_host%
        user:     %database_user%
        password: %database_password%
        charset:  %database_charset%
        wrapper_class: Your\DBAL\ReopeningConnectionWrapper

कक्षा को इस तरह कम या कम शुरू करना चाहिए:

namespace Your\DBAL;

class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection {
  // ...
}

एक बहुत ही कष्टप्रद बात यह है कि आपको अपने अपवाद-हैंडलिंग रैपर प्रदान करने वाले कनेक्शन की प्रत्येक विधि को ओवरराइड करना होगा। बंद करने का उपयोग कुछ दर्द को कम कर सकता है।


मेरा समाधान

कुछ भी करने से पहले चेक करें:

if (!$this->entityManager->isOpen()) {
    $this->entityManager = $this->entityManager->create(
        $this->entityManager->getConnection(),
        $this->entityManager->getConfiguration()
    );
}

सभी संस्थाओं को बचाया जाएगा। लेकिन यह विशेष वर्ग या कुछ मामलों के लिए आसान है। यदि आपके पास इंजेक्शन इकाई प्रबंधक के साथ कुछ सेवाएं हैं, तो यह अभी भी बंद हो जाएगी।


मुझे एक ही समस्या का सामना करना पड़ा। यहां कई जगहों को देखने के बाद मैंने इसका सामना कैसे किया।

//function in some model/utility
function someFunction($em){
    try{
        //code which may throw exception and lead to closing of entity manager
    }
    catch(Exception $e){
        //handle exception
        return false;
    }
    return true;
}

//in controller assuming entity manager is in $this->em 
$result = someFunction($this->em);
if(!$result){
    $this->getDoctrine()->resetEntityManager();
    $this->em = $this->getDoctrine()->getManager();
}

उम्मीद है कि यह किसी की मदद करता है!


सिम्फनी 2.0 :

$em = $this->getDoctrine()->resetEntityManager();

सिम्फनी 2.1+ :

$em = $this->getDoctrine()->resetManager();






entitymanager