“AUTO” रणनीति का उपयोग करते समय स्पष्ट रूप से Id के साथ Id सेट करें


100

मेरी संस्था इस एनोटेशन का उपयोग आईडी के लिए करती है:

/**
 * @orm:Id
 * @orm:Column(type="integer")
 * @orm:GeneratedValue(strategy="AUTO")
 */
protected $id;

एक स्वच्छ डेटाबेस से, मैं पुराने डेटाबेस से मौजूदा रिकॉर्ड में आयात कर रहा हूं और समान आईडी रखने की कोशिश कर रहा हूं। फिर, नए रिकॉर्ड जोड़ते समय, मैं चाहता हूं कि MySQL हमेशा की तरह आईडी कॉलम को ऑटो-इंक्रीमेंट करे।

दुर्भाग्य से, ऐसा प्रतीत होता है कि Doctrine2 निर्दिष्ट आईडी की पूरी तरह से उपेक्षा करता है।


नया समाधान

नीचे दी गई सिफारिशों के अनुसार, निम्नलिखित पसंदीदा समाधान है:

$this->em->persist($entity);

$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());

पुराना हल

क्योंकि जनरेटर की रणनीति का निर्धारण करने के लिए क्लासमैटाटाटा के डॉक्ट्रिन पिवोट्स हैं, इसे एंटिटीमैनगर में इकाई के प्रबंधन के बाद संशोधित किया जाना है:

$this->em->persist($entity);

$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);

$this->em->flush();

मैंने सिर्फ MySQL पर यह परीक्षण किया और यह उम्मीद के मुताबिक काम किया, जिसका अर्थ है कि एक कस्टम आईडी के साथ संस्थाओं को उस आईडी के साथ संग्रहीत किया गया था, जबकि बिना आईडी वाले लोग इसका उपयोग नहीं करते थे lastGeneratedId() + 1


क्या आप मौजूदा रिकॉर्ड आयात करने के लिए सिद्धांत का उपयोग कर रहे हैं?
रोजा

2
एरिक, कोई बात नहीं ... मैं देख रहा हूं कि आप क्या करने की कोशिश कर रहे हैं। आपको मूल रूप से @GeneratedValue (रणनीति = "ItDepends") की आवश्यकता है :)
Wil मूर III

1
इस पर ध्यान देने वाली एक बात यह है कि ऐसा लगता है कि Id जनरेटर्स जो "isPostInsertGenerator" == सच नहीं है, पहले ही चल चुके होंगे। आप जारी रहने के बाद आईडी के मूल्य को बदल सकते हैं, हालांकि, आप एक क्रम संख्या खो देंगे।
gview

15
नया समाधान अब मुझे एक सिद्धांत निर्धारण में आईडी सेट करने की अनुमति देता है। हालांकि, $ मेटाडेटा-> setIdGeneratorType (\ Doctrine \ ORM \ Mapping \ ClassMetadata :: GENERATOR_TYPE_NONE) का उपयोग करके; आईडी को सेट करने और सहेजने की अनुमति देता है। (माई एसक्यूएल)।
jmoz

2
यह नया समाधान सिम्फनी 3.0 में काम नहीं करता है। मैं का इस्तेमाल किया था$metadata = $this->getEntityManager()->getClassMetaData(User::class); $metadata->setIdGenerator(new AssignedGenerator()); $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
piotrekkr

जवाबों:


51

यद्यपि आपका समाधान MySQL के साथ ठीक काम करता है, मैं इसे PostgreSQL के साथ काम करने में विफल रहा क्योंकि यह अनुक्रम आधारित है।

मुझे इस लाइन को पूरी तरह से काम करने के लिए जोड़ना है:

$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());

सादर,


धन्यवाद! सिद्धांत पहले से थोड़ा सुधार हुआ है क्योंकि यह एक मुद्दा था, इसलिए मैंने आपके उत्तर को स्वीकार कर लिया है और तदनुसार अपने मूल टिकट को अपडेट किया है।
एरिक

धन्यवाद और मैं थोड़ी मदद करने के लिए खुश हूं जितना मैं कर सकता हूं :)
निकोलसबुई

2
क्या यह इस जनरेटर को स्थायी रूप से सेट करेगा? क्या मैं जबरन आईडी के साथ एक रिकॉर्ड जोड़ सकता हूं और फिर इसे ऑटोइन्क्रिमेंट आईडी का उपयोग कर सकता हूं?
पावेल डबिनिन

1
मैं पुष्टि कर सकता हूं कि यह सिम्फनी 3.2 के साथ काम करता है। हालांकि मुझे उम्मीद नहीं थी कि निष्पादन के बाद जनरेटर सेट करना होगा $em->persist($entity)
बोडो

29

शायद क्या सिद्धांत बदल गया है लेकिन अब सही तरीका है:

$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);

1
यह अभी भी प्रासंगिक जानकारी है और Doctrine 2.4.1 के लिए काम करता है, लेकिन @gphilip द्वारा बताई गई दूसरी पंक्ति को हटा दिया जाना चाहिए।
मंटास

Doctrine> 2.5 के लिए काम नहीं करता है क्योंकि ClassMetadataएक इंटरफ़ेस है और इसके बाद कोई स्थिरांक नहीं हो सकता है।
TiMESPLiNTER


@gphilip दूसरी पंक्ति महत्वपूर्ण है यदि आप चाहते हैं कि यह संघों के साथ काम करे
ताज़

1
का उपयोग करके सरल कर सकते हैं$metadata::GENERATOR_TYPE_NONE
fyrye

7

यदि इकाई एक वर्ग तालिका विरासत का हिस्सा है, तो आपको दोनों संस्थाओं के लिए वर्ग मेटाडेटा में आईडी-जनरेटर को बदलने की आवश्यकता है (आप जिस इकाई को बनाए रख रहे हैं और मूल इकाई है)


मुझे लगता है कि मामला यह है कि आपको केवल मूल इकाई को निर्दिष्ट करने की आवश्यकता है। आईडी रणनीति का निर्धारण करते समय मेटाडेटाफैक्टरी इनहेरिटेंस की जांच करता है।
सेठ बट्टिन

वास्तव में, जब मैं इसे केवल मूल इकाई में जोड़ता हूं तो यह त्रुटिपूर्ण रूप से काम करता है। जब मैं इसे दोनों में जोड़ता हूं, तो मुझे SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint failsत्रुटियां हो रही हैं। डाउनवोटेड
ioleo

5

नया समाधान ठीक तभी काम करता है जब सभी इकाइयाँ डालने से पहले आई.डी. जब एक इकाई में आईडी होती है और दूसरा नहीं होता है - नया समाधान विफल हो रहा है।

मैं अपने सभी डेटा आयात करने के लिए इस फ़ंक्शन का उपयोग करता हूं:

function createEntity(\Doctrine\ORM\EntityManager $em, $entity, $id = null)
{
    $className = get_class($entity);
    if ($id) {
        $idRef = new \ReflectionProperty($className, "id");
        $idRef->setAccessible(true);
        $idRef->setValue($entity, $id);

        $metadata = $em->getClassMetadata($className);
        /** @var \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata */
        $generator = $metadata->idGenerator;
        $generatorType = $metadata->generatorType;

        $metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
        $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);

        $unitOfWork = $em->getUnitOfWork();
        $persistersRef = new \ReflectionProperty($unitOfWork, "persisters");
        $persistersRef->setAccessible(true);
        $persisters = $persistersRef->getValue($unitOfWork);
        unset($persisters[$className]);
        $persistersRef->setValue($unitOfWork, $persisters);

        $em->persist($entity);
        $em->flush();

        $idRef->setAccessible(false);
        $metadata->setIdGenerator($generator);
        $metadata->setIdGeneratorType($generatorType);

        $persisters = $persistersRef->getValue($unitOfWork);
        unset($persisters[$className]);
        $persistersRef->setValue($unitOfWork, $persisters);
        $persistersRef->setAccessible(false);
    } else {
        $em->persist($entity);
        $em->flush();
    }
}

4

Doctrine 2.5 और MySQL के लिए समाधान

"नया समाधान" Doctrine 2.5 और MySQL के साथ काम नहीं करता है। आपको उपयोग करना होगा:

$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_‌​NONE);

हालाँकि मैं केवल MySQL के लिए पुष्टि कर सकता हूं, क्योंकि मैंने अभी तक किसी अन्य DBMS की कोशिश नहीं की है।


1

मैंने डॉक्ट्रिन संस्थाओं के लिए भविष्य की आईडी सेट करने के लिए एक लाइब्रेरी बनाई है । यह मूल आईडी पीढ़ी की रणनीति को प्रभावित करता है जब प्रभाव को कम करने के लिए सभी कतारबद्ध आईडी का उपभोग किया जाता है। यह यूनिट परीक्षणों के लिए एक आसान ड्रॉप-इन होना चाहिए ताकि इस तरह के कोड को दोहराया न जाए।


1

विलेरमैन के काम से प्रेरित होकर , मैंने लाइब्रेरी tseho / doctrine-असाइन-आइडेंटिटी बनाई, जो आपको मैन्युअल रूप से एक Doctrine एंटिटी को ID असाइन करने की अनुमति देता है, यहां तक ​​कि जब यूनिट स्टैटीज़ AUTO, SEQUENCE, IDRITY या UUID का उपयोग करता है।

आपको इसे उत्पादन में कभी भी उपयोग नहीं करना चाहिए लेकिन यह कार्यात्मक परीक्षणों के लिए वास्तव में उपयोगी है।

पुस्तकालय स्वचालित रूप से एक निर्धारित आईडी के साथ संस्थाओं का पता लगाएगा और केवल जरूरत पड़ने पर जनरेटर को बदल देगा। लायब्रेरी प्रारंभिक जनरेटर पर वापस आ जाएगी जब एक उदाहरण में एक निर्दिष्ट आईडी नहीं है।

जनरेटर का प्रतिस्थापन एक Doctrine EventListener में होता है, आपके जुड़नार में कोई अतिरिक्त कोड जोड़ने की आवश्यकता नहीं होती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.