कई पासों के साथ कोर डाटा माइग्रेशन का उदाहरण या स्पष्टीकरण?


85

मेरे iPhone ऐप को अपने मुख्य डेटा स्टोर को माइग्रेट करने की आवश्यकता है, और कुछ डेटाबेस बहुत बड़े हैं। ऐप्पल के दस्तावेज़ीकरण में मेमोरी के उपयोग को कम करने के लिए डेटा को स्थानांतरित करने के लिए "कई पास" का उपयोग करने का सुझाव दिया गया है। हालाँकि, दस्तावेज़ बहुत सीमित है और यह बहुत अच्छी तरह से नहीं समझाता है कि वास्तव में यह कैसे करना है। क्या कोई मुझे एक अच्छे उदाहरण की ओर इंगित कर सकता है, या इस प्रक्रिया की विस्तार से व्याख्या कर सकता है कि वास्तव में इसे कैसे खींचना है?


क्या आप वास्तव में स्मृति समस्याओं में चले थे? क्या आपका माइग्रेशन लीवेटवेट है या आप NSMigrationManager का उपयोग करना चाहते हैं?
निक वीवर

हां, GDB कंसोल से पता चलता है कि मेमोरी चेतावनी थी, और फिर सीमित मेमोरी के कारण ऐप क्रैश हो गया। मैंने हल्के माइग्रेशन और NSM माइग्रेशन मैनेजर दोनों की कोशिश की है, लेकिन अभी मैं NSM माइग्रेशन मैनेजर का उपयोग करने की कोशिश कर रहा हूं।
जेसन

ठीक है, क्या आप विस्तार में थोड़ा और बदल सकते हैं?
निक वीवर

अंत में, मुझे पता चला है, मेरा उत्तर पढ़ें।
निक वीवर

नमस्ते जेसन, क्या आप इस प्रश्न की तरह ठीक कर सकते हैं?
युकेन झोंग

जवाबों:


174

मुझे पता लगा है कि Apple उनके प्रलेखन में क्या संकेत देता है । यह वास्तव में बहुत आसान है लेकिन स्पष्ट होने से पहले एक लंबा रास्ता तय करना है। मैं एक उदाहरण के साथ स्पष्टीकरण का वर्णन करता हूँ। प्रारंभिक स्थिति यह है:

डेटा मॉडल संस्करण 1

यहाँ छवि विवरण दर्ज करें यहाँ छवि विवरण दर्ज करें

यह वह मॉडल है जो आपको तब मिलता है जब आप "नेविगेशन आधारित ऐप के साथ कोर डेटा स्टोरेज" टेम्पलेट बनाते हैं। मैंने इसे संकलित किया और कुछ अलग-अलग मूल्यों के साथ लगभग 2k प्रविष्टियों को बनाने के लिए लूप की मदद से कुछ कठिन हिट किया। वहाँ हम एक NSDate मान के साथ 2.000 ईवेंट जाते हैं।

अब हम डेटा मॉडल का दूसरा संस्करण जोड़ते हैं, जो इस तरह दिखता है:

यहाँ छवि विवरण दर्ज करें

डेटा मॉडल संस्करण 2

अंतर यह है: ईवेंट इकाई चली गई है, और हमें दो नए मिल गए हैं। एक जो एक टाइमस्टैम्प को एक के रूप में संग्रहीत करता है doubleऔर दूसरा वह जो एक तिथि को स्टोर करना चाहिए NSString

लक्ष्य सभी संस्करण 1 को स्थानांतरित करना है ईवेंट को दो नई संस्थाओं में स्थानांतरित करना है और माइग्रेशन के साथ मूल्यों को परिवर्तित करना है। यह एक अलग इकाई में एक अलग प्रकार के रूप में प्रत्येक में दो बार मूल्यों का परिणाम है।

माइग्रेट करने के लिए, हम हाथ से माइग्रेशन चुनते हैं और यह हम मैपिंग मॉडल के साथ करते हैं। यह आपके प्रश्न के उत्तर का पहला भाग भी है। हम माइग्रेशन दो चरणों में करेंगे, क्योंकि 2k प्रविष्टियों को माइग्रेट करने में लंबा समय लग रहा है और हम मेमोरी फुटप्रिंट को कम रखना पसंद करते हैं।

तुम भी आगे जा सकते हैं और इन मानचित्रण मॉडल को विभाजित करने के लिए आगे संस्थाओं की केवल सीमाओं को स्थानांतरित कर सकते हैं। मान लीजिए कि हमें एक मिलियन रिकॉर्ड मिला, यह पूरी प्रक्रिया को ध्वस्त कर सकता है। यह एक फिल्टर विधेय के साथ नीचे भ्रूण संस्थाओं को संकीर्ण करने के लिए संभव है ।

हमारे दो मैपिंग मॉडल पर वापस जाएं।

हम इस तरह का पहला मैपिंग मॉडल बनाते हैं:

1. नई फाइल -> संसाधन -> मैपिंग मॉडल यहाँ छवि विवरण दर्ज करें

2. एक नाम चुनें, मैंने StepOne को चुना

3. सेट स्रोत और गंतव्य डेटा मॉडल

यहाँ छवि विवरण दर्ज करें

मैपिंग मॉडल स्टेप वन

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

मल्टी पास माइग्रेशन के लिए कस्टम इकाई माइग्रेशन नीतियों की आवश्यकता नहीं होती है, हालांकि हम इस उदाहरण के लिए थोड़ा और विस्तार पाने के लिए ऐसा करेंगे। इसलिए हम इकाई में एक कस्टम नीति जोड़ते हैं। यह हमेशा एक उपवर्ग है NSEntityMigrationPolicy

यहाँ छवि विवरण दर्ज करें

यह नीति वर्ग हमारे प्रवासन को बनाने के लिए कुछ तरीकों को लागू करता है। लेकिन यह तो हम केवल एक विधि को लागू करना होगा इस मामले में सरल है: createDestinationInstancesForSourceInstance:entityMapping:manager:error:

कार्यान्वयन इस तरह दिखेगा:

StepOneEntityMigrationPolicy.m

#import "StepOneEntityMigrationPolicy.h"


@implementation StepOneEntityMigrationPolicy

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance 
                                      entityMapping:(NSEntityMapping *)mapping 
                                            manager:(NSMigrationManager *)manager 
                                              error:(NSError **)error
{
    // Create a new object for the model context
    NSManagedObject *newObject = 
        [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] 
                                      inManagedObjectContext:[manager destinationContext]];

    // do our transfer of nsdate to nsstring
    NSDate *date = [sInstance valueForKey:@"timeStamp"];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    

    // set the value for our new object
    [newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
    [dateFormatter release];

    // do the coupling of old and new
    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];

    return YES;
}

अंतिम चरण: माइग्रेशन ही

मैं दूसरे मैपिंग मॉडल को स्थापित करने के लिए भाग को छोड़ दूंगा जो लगभग समान है, बस एक बार InInvalvalSince1970 NSDate को एक डबल में परिवर्तित करने के लिए उपयोग किया जाता है।

अंत में हमें माइग्रेशन को ट्रिगर करना होगा। मैं अब के लिए बॉयलरप्लेट कोड छोड़ दूंगा। यदि आपको इसकी आवश्यकता है, तो मैं यहां पोस्ट करूंगा। यह माइग्रेशन प्रक्रिया को अनुकूलित करने पर पाया जा सकता है यह पहले दो कोड उदाहरणों का एक मर्ज है। तीसरे और अंतिम भाग के रूप में निम्नानुसार संशोधित किया जाएगा: के वर्ग विधि उपयोग करने के बजाय NSMappingModelवर्ग mappingModelFromBundles:forSourceModel:destinationModel:हम का उपयोग करेगा initWithContentsOfURL:क्योंकि वर्ग विधि केवल एक ही है, शायद पहले पाया मानचित्रण बंडल में मॉडल वापस आ जाएगी।

अब हमें दो मैपिंग मॉडल मिल गए हैं जो लूप के हर पास में इस्तेमाल किए जा सकते हैं और माइग्रेट मैनेजर को माइग्रेट विधि भेज सकते हैं। बस।

NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;

NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];

NSString *destinationStoreType = NSSQLiteStoreType;

NSDictionary *destinationStoreOptions = nil;

for (NSString *mappingModelName in mappingModelNames) {
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];

    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];

    BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
                                               type:sourceStoreType
                                            options:sourceStoreOptions
                                   withMappingModel:mappingModel
                                   toDestinationURL:destinationStoreURL
                                    destinationType:destinationStoreType
                                 destinationOptions:destinationStoreOptions
                                              error:&error2];
    [mappingModel release];
} 

टिप्पणियाँ

  • cdmबंडल में एक मैपिंग मॉडल समाप्त होता है ।

  • गंतव्य स्टोर प्रदान किया जाना चाहिए और स्रोत स्टोर नहीं होना चाहिए। आप सफल माइग्रेशन के बाद पुराने को हटा सकते हैं और नया नाम बदल सकते हैं।

  • मैंने मैपिंग मॉडल के निर्माण के बाद डेटा मॉडल में कुछ बदलाव किए, इसके परिणामस्वरूप कुछ संगतता त्रुटियां हुईं, जिन्हें मैं केवल मैपिंग मॉडल को फिर से बनाने के साथ हल कर सकता था।


59
खूनी नरक जो जटिल है। Apple क्या सोच रहा था?
एरोथ

7
मुझे नहीं पता, लेकिन जब भी मुझे लगता है कि कोर डेटा एक अच्छा विचार है मैं एक सरल और अधिक प्राप्य समाधान खोजने के लिए कड़ी मेहनत करता हूं।
निक वीवर

5
धन्यवाद! यह एक शानदार जवाब है। यह जटिल लगता है, लेकिन जब आप कदम सीख लेते हैं तो यह उतना बुरा नहीं होता। सबसे बड़ी समस्या यह है कि प्रलेखन इस तरह से आपके लिए नहीं है।
बेंटफोर्ड

2
यहाँ माइग्रेशन प्रक्रिया को अनुकूलित करने के लिए अद्यतन लिंक है। यह पोस्ट लिखे जाने के बाद से चला गया है। डेवलपर
.apple.com

@NickWeaver आप किस प्रकार गंतव्य का निर्धारण कर रहे हैं क्या आप इसे बना रहे हैं या यह माइग्रेशन प्रक्रिया के दौरान कोर डेटा सिस्टम द्वारा बनाया जाता है ????
देव जीआर

3

ये प्रश्न संबंधित हैं:

स्मृति मुद्दों iPhone पर बड़े CoreData datastores पलायन

IOS के साथ कई पास कोर डाटा माइग्रेशन इन चंक्स

पहले लिंक को उद्धृत करने के लिए:

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


1
लिंक के लिए धन्यवाद। समस्या यह है कि कोई भी वास्तव में विस्तार से नहीं बताता है कि इसे कई पास में कैसे सेट किया जाए। मुझे कई मैपिंग मॉडल कैसे सेट करने चाहिए ताकि यह प्रभावी रूप से काम करे?
जेसन

-5

मान लीजिए कि आपके डेटाबेस स्कीमा में 5 संस्थाएं हैं, जैसे कि व्यक्ति, छात्र, पाठ्यक्रम, कक्षा, और पंजीकरण मानक मानक उदाहरण का उपयोग करने के लिए, जहां छात्र उप-वर्ग व्यक्ति, कक्षा लागू करता है, और पंजीकरण कक्षा और छात्र में शामिल होता है। यदि आपने इन सभी तालिका परिभाषाओं में परिवर्तन किया है, तो आपको आधार कक्षाओं में शुरू करना होगा, और अपना काम करना होगा। इसलिए, आप पंजीकरण को परिवर्तित करने के साथ शुरू नहीं कर सकते, क्योंकि प्रत्येक पंजीकरण रिकॉर्ड कक्षा और छात्रों के वहां होने पर निर्भर करता है। इसलिए, आप केवल व्यक्ति तालिका को माइग्रेट करने, नई पंक्तियों में मौजूदा पंक्तियों की प्रतिलिपि बनाने और जो कुछ नए फ़ील्ड हैं उसमें भरने (यदि संभव हो) और हटाए गए स्तंभों को छोड़ने के साथ शुरू करेंगे। ऑटोरिलिज़ पूल के अंदर प्रत्येक माइग्रेशन करें, ताकि एक बार यह हो जाने के बाद, आपकी मेमोरी वापस शुरू हो जाए।

एक बार जब व्यक्ति तालिका हो जाती है, तो आप छात्र तालिका को बदल सकते हैं। फिर कोर्स और फिर क्लास, और अंत में पंजीकरण तालिका पर हॉप करें।

अन्य विचार रिकॉर्ड की संख्या है, अगर व्यक्ति की एक हजार पंक्तियाँ थीं, तो आपको हर 100 या तो, एक रिलीज के बराबर NSManagedObject को निष्पादित करना होगा, जो कि प्रबंधित ऑब्जेक्ट संदर्भ को बताना है [moc refreshObject: mergeChanges: नहीं]; इसके अलावा अपने बासी डेटा टाइमर तरीका कम सेट करें, ताकि मेमोरी अक्सर फ्लश हो जाए।


तो क्या आप अनिवार्य रूप से एक नया कोर डेटा स्कीमा रखने का सुझाव दे रहे हैं जो पुराने स्कीमा का हिस्सा नहीं है, और डेटा को नए स्कीमा को हाथ से कॉपी करें?
जेसन

-1 अपने डेटाबेस को मैन्युअल रूप से मैप करना आवश्यक नहीं है। आप हल्के माइग्रेशन का उपयोग करके या स्पष्ट MappingModels के साथ तैनात डेटाबेस को माइग्रेट कर सकते हैं।
बेंटफोर्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.