2012-04-19 15 views
11

मेरे पास एक बड़े, प्रीलोड किए गए डेटाबेस और एक छोटे उपयोगकर्ता डेटाबेस (कोरडाटा SQLite स्टोर्स दोनों) के साथ एक आईओएस प्रोजेक्ट है। पिछले प्रश्नों ने कॉन्फ़िगरेशन का उपयोग करके सुझाव दिया है कि कौन सी इकाइयों का उपयोग किस स्टोर के साथ किया जाता है। मुझे काम करने में परेशानी हो रही है। यहाँ मैं क्या कोशिश कर रहा है ... हैएकाधिक स्टोर्स के साथ कोरडाटा: कॉन्फ़िगरेशन woes

- (NSManagedObjectModel *)managedObjectModel 
{ 
    if (_managedObjectModel != nil) return _managedObjectModel; 
    // set up the model for the preloaded data 
    NSURL *itemURL = [[NSBundle mainBundle] URLForResource:@"FlagDB" withExtension:@"momd"]; 
    NSManagedObjectModel *itemModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:itemURL]; 
    // set up the model for the user data 
    NSURL *userDataURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"]; 
    NSManagedObjectModel *userDataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:userDataURL]; 
    // merge the models 
    _managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:itemModel, userDataModel, nil]]; 
    // define configurations based on what was in each model 
WRONG [_managedObjectModel setEntities:itemModel.entities forConfiguration:@"ItemData"]; 
WRONG [_managedObjectModel setEntities:userDataModel.entities forConfiguration:@"UserData"]; 
    return _managedObjectModel; 
} 

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator; 
    // preloaded data is inside the bundle 
    NSURL *itemURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"FlagDB.sqlite"]; 
    // user data is in the application directory 
    NSURL *userDataURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"]; 

    NSManagedObjectModel *mom = self.managedObjectModel; 
    NSError *error = nil; 
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 

    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:nil error:&error]) 
    { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 
    ... 

इस के साथ "दुकान खोलने के लिए किया मॉडल की दुकान बनाने के लिए इस्तेमाल एक के साथ असंगत है" aborts। दुकान में हैश के खिलाफ मॉडल में हैश की जांच से पता चलता है कि वे आइटमडेटा कॉन्फ़िगरेशन में मौजूद इकाइयों के समान हैं।

अगर मैं ऐसा तरह एक हल्के प्रवास कर रही है, की कोशिश:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:options error:&error]) 

यह NSInvalidArgumentException ', कारण के साथ विफल रहता है:'। 'ItemData' मॉडल विन्यास शामिल नहीं है ' मुझे लगता है कि ऐसा इसलिए है क्योंकि लाइटवेट माइग्रेशन प्रक्रिया द्वारा एक नया मॉडल बनाया जा रहा है, और इसमें मेरी कॉन्फ़िगरेशन नहीं है।

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

NSDictionary *migrationOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

// make a temp persistent store coordinator to handle the migration 
NSPersistentStoreCoordinator *tempPsc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
// migrate the stores 
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:itemURL options:migrationOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:userDataURL options:migrationOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

// make a permanent store coordinator 
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 

NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil]; 
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:readOnlyOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

/*if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserData" URL:userDataURL options:nil error:&error]) 
{ 
NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
abort(); 
}*/ 

और फिर बाद में ...

OSAppDelegate *delegate = [UIApplication sharedApplication].delegate; 
    NSManagedObjectContext *context = delegate.managedObjectContext; 
    // sanity check 
    for (NSPersistentStore *store in context.persistentStoreCoordinator.persistentStores) { 
     NSLog(@"store %@ -> %@", store.configurationName, store.URL); 
     NSMutableArray *entityNames = [[NSMutableArray alloc] init]; 
     for (NSEntityDescription *entity in [context.persistentStoreCoordinator.managedObjectModel entitiesForConfiguration:store.configurationName]) { 
      [entityNames addObject:entity.name]; 
     } 
     NSLog(@"entities: %@", entityNames); 
    } 

    NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init]; 
    categoryFetchRequest.entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context]; 
    categoryFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", categoryName]; 
    NSError *error = nil; 
    Category *category = [[delegate.managedObjectContext executeFetchRequest:categoryFetchRequest error:&error] lastObject]; 

यह ठीक काम करता है, उचित नाम श्रेणी वस्तु लौटने, जब तक मैं दूसरे की दुकान के अलावा uncomment। अगर मैं ऐसा करता हूं, तो fetch परिणाम वापस खाली आता है। डायग्नोस्टिक एनएसएलओजी संदेश वास्तव में प्रिंट करते हैं जो मैं अपेक्षा करता हूं। प्रत्येक स्टोर सही विन्यास से जुड़ा हुआ है, और प्रत्येक कॉन्फ़िगरेशन में उपयुक्त इकाइयां हैं।

क्या कोई मुझे एक काम करने वाले एकाधिक स्टोर सेटअप के लिए स्रोत कोड पर इंगित कर सकता है, या मुझे गलत करने के लिए मुझे बता सकता है? अग्रिम में धन्यवाद!


हल: समस्या की जड़ दो पंक्तियों पहले कोड सूची में गलत चिह्नित किया गया था। मैं प्रोग्रामेटिक रूप से कॉन्फ़िगरेशन बनाने का प्रयास कर रहा था, लेकिन यह अपर्याप्त प्रतीत होता है। यदि आप ऐसा करने के बाद कॉन्फ़िगरेशन के लिए ManagedObjectModel से पूछताछ करते हैं, तो आप वास्तव में सूची में कॉन्फ़िगरेशन देखते हैं, और सही इकाइयां उन कॉन्फ़िगरेशन से जुड़ी हैं। हालांकि, ऐसा लगता है कि PersistentStoreCoordinator को ठीक से उपयोग करने में सक्षम बनाने के लिए कुछ और करने की आवश्यकता है। एक्सकोड में कॉन्फ़िगरेशन बनाना उन्हें काम करता है।


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

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

+0

सुनिश्चित करें कि आप ऐप सैंडबॉक्स की उपयोगकर्ता दस्तावेज़ निर्देशिका पर माइग्रेशन कर रहे हैं - जिसे पढ़ा/लिखना है - और ऐप बंडल में नहीं। – Sunny

+0

मैं डेटा को दस्तावेज़ निर्देशिका में स्थानांतरित नहीं करना चाहता था क्योंकि मैं नहीं चाहता कि (स्थैतिक) डेटा का बैकअप लिया जाए और उपयोगकर्ता के iCloud कोटा के विरुद्ध गिना जाए। लेकिन यह आईओएस 5.0.1 में लगता है जैसे बैक अप लेने के लिए फ़ाइलों को नामित करने का एक तरीका है: http://developer.apple.com/library/ios/#qa/qa1719/_index.html – Aneel

+2

ठीक है, आपने मुझे प्रेरित किया और मेरी समस्या को हल करने के लिए कुछ घंटों खर्च करने के बाद, मैंने इस पर एक पूरा लेख लिखा [यहां] (http://blog.atwam.com/blog/2012/05/11/multiple-persist-stores-and-seed-data -साथ कोर-डेटा /)। मुझे लगा कि यह भविष्य में कुछ अन्य लोगों की मदद कर सकता है। – Wam

उत्तर

5

क्या आपने एक ही मॉडल (यानी एक ही माँ) में परिभाषित दोनों कॉन्फ़िगरेशन करने का प्रयास किया है? आप अपने डेटा मॉडल में से किसी एक को संपादित करते समय "संपादक-> कॉन्फ़िगरेशन जोड़ें" चुनकर आसानी से ऐसा कर सकते हैं। उपयुक्त कॉन्फ़िगरेशन में UserData और ItemData के लिए इकाइयों को खींचें। इस तरह से कॉन्फ़िगर किया गया कॉन्फ़िगरेशन कोर डेटा का सम्मान करता है; यह फ़ाइल/यूआरएल नाम के बारे में नहीं है। एक बार जब आप उपर्युक्त कर लेंगे, तो जब भी इसे कॉल किया जाता है तो एकल माम फ़ाइल/यूआरएल को देखने के लिए उपरोक्त अपने _managedObjectModel को सरल बनाएं।

वैकल्पिक रूप से, यदि आप दो अलग-अलग माताओं फ़ाइलों को रखने का निर्णय लेते हैं, तो सुनिश्चित करें कि आपने वास्तव में अपने मॉडल परिभाषा फ़ाइलों में "उपयोगकर्ता डेटा" और "आइटमडाटा" नामक कॉन्फ़िगरेशन में कॉन्फ़िगरेशन में अपने मॉडल को परिभाषित किया है।

मेरा प्रारंभिक सुझाव एक मॉडल फ़ाइल रखना है। जब तक कोई कारण नहीं है कि ये कॉन्फ़िगरेशन एक ही ऑब्जेक्ट मॉडल में नहीं रह सकते हैं, तो कई फ़ाइलों के साथ चीजों को जटिल बनाने में कोई समझ नहीं आता है। मुझे लगता है कि कोर डेटा को ऊपर करने के लिए जो कुछ भी लाया जा रहा है, उसे करने में काफी मुश्किल होगी। अपने कोड के मॉडलिंग भाग को सरल बनाने का प्रयास करें।

+1

उत्तर के लिए धन्यवाद। मेरे पास दो अलग-अलग मॉडल का उपयोग करने का एक अच्छा कारण है। आइटम डेटा मॉडल को किसी अन्य प्रोजेक्ट के साथ साझा किया जाता है (ओएस एक्स एप्लिकेशन डेटा सेट बनाने/संपादित करने के लिए उपयोग किया जाता है)। यदि संभव हो, तो मैं दो मॉडल अलग रखने में सक्षम होना चाहता हूं। – Aneel

+1

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

+1

ठीक है, मैंने मॉडल को अलग रखने के लिए सुझाव देने का भी प्रयास किया। यह भी काम करता है! ऐसा लगता है कि मेरी समस्या का मूल यह था कि प्रोग्रामेटिक रूप से ManagedObjectModel addEntities के साथ कॉन्फ़िगरेशन को परिभाषित करना: कॉन्फ़िगरेशन के लिए: काम नहीं करता है। जब आप एमओएम को इसकी कॉन्फ़िगरेशन के लिए पूछते हैं तो वे दिखाते हैं, लेकिन वास्तव में वे पीएससी द्वारा सही तरीके से उपयोग नहीं करते हैं। एक्सकोड में कॉन्फ़िगरेशन बनाना दृश्यों के पीछे और अधिक करना चाहिए। – Aneel

संबंधित मुद्दे