ฉันพบสิ่งที่ Apple บอกเป็นนัยในเอกสารของพวกเขาแล้ว จริงๆแล้วมันง่ายมาก แต่ต้องไปอีกไกลก่อนที่มันจะชัดเจน ฉันจะอธิบายคำอธิบายพร้อมตัวอย่าง สถานการณ์เริ่มต้นคือ:
แบบจำลองข้อมูลเวอร์ชัน 1
เป็นแบบจำลองที่คุณจะได้รับเมื่อสร้างโครงการด้วยเทมเพลต "แอปที่ใช้การนำทางพร้อมที่เก็บข้อมูลหลัก" ฉันรวบรวมมันและทำการกดปุ่มอย่างหนักด้วยความช่วยเหลือของ for loop เพื่อสร้างรายการประมาณ 2k ทั้งหมดด้วยค่าที่แตกต่างกัน เราไปที่นั่น 2.000 เหตุการณ์ด้วยค่า NSDate
ตอนนี้เราเพิ่มรุ่นที่สองของโมเดลข้อมูลซึ่งมีลักษณะดังนี้:
แบบจำลองข้อมูลเวอร์ชัน 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
{
NSManagedObject *newObject =
[NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName]
inManagedObjectContext:[manager destinationContext]];
NSDate *date = [sInstance valueForKey:@"timeStamp"];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
[dateFormatter release];
[manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
return YES;
}
ขั้นตอนสุดท้าย: การโยกย้ายเอง
ฉันจะข้ามส่วนสำหรับการตั้งค่ารูปแบบการทำแผนที่ที่สองซึ่งเกือบจะเหมือนกันเพียงแค่ timeIntervalSince1970 ที่ใช้ในการแปลง 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
บันเดิล
ต้องมีการจัดเก็บปลายทางและไม่ควรเป็นร้านค้าต้นทาง หลังจากย้ายข้อมูลสำเร็จแล้วให้ลบไฟล์เก่าและเปลี่ยนชื่อใหม่
ฉันได้ทำการเปลี่ยนแปลงบางอย่างกับโมเดลข้อมูลหลังจากสร้างโมเดลการแม็ปซึ่งส่งผลให้เกิดข้อผิดพลาดเกี่ยวกับความเข้ากันได้ซึ่งฉันสามารถแก้ไขได้ด้วยการสร้างโมเดลการแมปใหม่เท่านั้น