我正在开发一款使用Core Data管理其持久数据的应用。我们一直在进行足够复杂的架构更改,轻量级自动迁移不兼容,因此我们使用手动定义的模型迁移。
我的问题是,当我调用addPersistentStoreWithType:configuration:URL:options:error:设置了NSMigratePersistentStoresAutomaticallyOption时,它选择了错误的映射模型。如果我手动调用mappingModelFromBundles:forSourceModel:destinationModel:我会得到相同(不正确)的映射模型。
我们有三个版本的数据模型:1.0,1.1和1.1.1。 我们定义了三种映射模型:1.0-1.1,1.0-1.1.1和1.1-1.1.1。 应用程序中的数据版本为1.1 当前版本的数据是1.1.1 选择的映射模型是1.0-1.1.1。 这会导致在1.1中添加的表被删除并重新创建,从而丢失数据。
当我使用-com.apple.CoreData.MigrationDebug 1命令行选项时,它会打印出升级过程的调试信息。它显示当前数据集中的所有表(包括1.1中添加的表)及其哈希值。然后它显示1.0-1.1.1映射模型的源和目标哈希值,声明它是兼容的映射模型,并且从不检查任何其他模型。
如果我使用[NSMappingModel initWithContentsOfURL]专门选择1.1-1.1.1映射模型,我会得到所需的行为。
我有点茫然,因为在我看来它不应该愿意使用源哈希与当前数据集的哈希值不匹配的映射模型。
以下是一些选定的输出,显示正在重置的表位于数据库中,但不在映射模型中。我已经验证了1.1数据哈希和1.0数据哈希之间的唯一区别是1.1有一个附加表。
2014-07-03 23:03:20.547 XXX[50242:60b] CoreData: annotation: (migration) will attempt automatic schema migration
2014-07-03 23:03:21.212 XXX[50242:60b] CoreData: annotation: (migration) looking for mapping model with source hashes:
{
XXX = <77891dab a2acaff3 e52f71e3 0f8c3d5f eee99f43 f549e3fc 72eddd29 b2af83fd>;
XXX = <6049b4fb 7d8c4e5f 63149e35 5abfd274 1264c2f9 76d13cf3 cc69a23a e29edac8>;
XXX = <cf3bd61a 71c2838c 421c6e50 41abd013 b0c153cb b165a0e6 21d5c352 f29b5743>;
XXX = <fd8c6be5 b97b3827 455a620c 3e6ff6e9 e2e09afd 472b9cbf 07d11e29 d5a52159>;
XXX = <6cf5aac1 67ead46a fbaf8450 11c2c0b9 dcc1e2ae dd3bbf86 06d09b78 4d4b6bbe>;
XXX = <09942be7 56f82126 d48a90b2 e6cf08e7 1fe9c091 1ee7fec8 8d426ca4 a00af268>;
XXX = <40462ca4 098ae4d2 d3e8e7cf a55bc7df ca58c8c9 3aaf8d94 b681080c 63e5683b>;
XXX = <dce53740 e8aba89f ac8180b4 0f297821 d09734a1 8ea3c344 8cb9dd6c d3baf645>;
XXX = <c9f7a2e3 13518dac 5ae5209d 239d1c11 0fd3f11f 5366b7d4 fd3a97d3 3e3d41d1>;
XXX = <e5bf6c2f c0c9d818 e1b4e2cc 9b7a92e3 2cd6bed4 5a98e6c3 53619376 9b3951ef>;
XXX = <5431c046 d30e7f32 c2cc8099 58add1e7 579ad104 a3aa8fc4 846e97d7 af01cc79>;
XXX = <3aef2c65 c9647274 1302fe8a fdca7ce6 cb87c7df 2751a19f bd946707 c8244729>;
THIS_ONE = <1bb3a3b9 857bcdf2 ca573238 a86672b8 0486929e ed0357c8 72879022 e12efe37>;
XXX = <9f627411 6f8c0891 3693eab1 aa45cbd3 0143b28e 1e3584da e6ea2867 554a26ad>;
XXX = <9def8e9f 14dfb358 b5694bce 77759b7c c1901fe1 3e3a163b 80061b51 268089a8>;
XXX = <06d0b355 4fb4ff4b 0adf05d4 8ce0378c 4aa156e9 a09c8a16 a82d8376 1fd2f929>;
XXX = <fb9db76f 350ad944 88e1cf5d 15aaca9c 230355f9 13a2dace 62d5e4fb 0a2ecd7a>;
XXX = <715d9149 7aea98db fdb3a2fa e1682e12 dfe8f63a d09aac57 301be349 91fffd44>;
XXX = <002c8d92 8bc08e6c eb34fe0c a10ef78e ed050a8e 17a86e63 9911adb8 e2c36df1>;
XXX = <362ea015 28a5c834 47b125c1 c460dd62 f0172785 e024b8aa 17dc544f 66871077>;
XXX = <bd06507d f33ee72d d6bba2d5 c29eb8c5 1f87568b 186ab250 7312c0ec 6f2cd09c>;
XXX = <22ff0e46 f56dbc7a e8e92cf6 9090a451 742517ff 7d29838d 0cd41e9e a3615134>;
XXX = <ec7834a0 987c4c5f df40ade2 73075b11 e329a018 94fe47ca 08f7c9ed 95bb4da1>;
XXX = <c3feffd4 8d223692 d314720a 4496b787 871db7d0 31097cff e1225b9b 6275e613>;
XXX = <e5e3c8aa 5267d778 9fd62dc5 884ef416 5f836890 d82fed79 efd3796d bcb58503>;
XXX = <6705e1bf cac0c2ed b040b64f ca1f6e6e 74332890 907ec136 7a99606c e116a946>;
XXX = <856a10a5 18de663a 1860ea0d c0bd9295 769e4a42 99420fb5 02314b22 f39fe1a4>;
XXX = <35f6c30f a146166c 6e132297 bf463c59 756b8071 49aae2d7 ec6b6de8 fb7f7300>;
XXX = <ec2a9e60 6ae28042 a62429e4 b0ec5939 3734e0ac 9a919421 a9fbede2 031b0bf6>;
XXX = <b08fbebb 9100df77 5aba3640 c8237a5b 4ddbed50 fb6cb28c 439c7e37 9b2ccb4a>;
XXX = <95c8cfb8 a1aafabc 90a9231b 0ef15d85 10e30393 5cfd4921 4db4a12f 511c8977>;
XXX = <4e0fcdb8 4fbf9aa3 684875aa c54a4c5d c02020b2 d29212e4 587069d2 eed3aa31>;
XXX = <ad580044 b972d6ab df963bda ad071ba5 9c82aab5 4007f377 bf8858fe b9bc6274>;
XXX = <4fc9af50 0722da5d 18e0b755 63cf2a04 88e8b2d3 e8196ec2 375171b1 ce40fb4e>;
}
2014-07-03 23:03:21.231 XXX[50242:60b] CoreData: annotation: (migration) checking mapping model /Users/jonathan/Library/Application Support/iPhone Simulator/7.1/Applications/XXX/XXX.app/1.0-1.1.1.cdm
source hashes:
{(
<09942be7 56f82126 d48a90b2 e6cf08e7 1fe9c091 1ee7fec8 8d426ca4 a00af268>,
<40462ca4 098ae4d2 d3e8e7cf a55bc7df ca58c8c9 3aaf8d94 b681080c 63e5683b>,
<ec7834a0 987c4c5f df40ade2 73075b11 e329a018 94fe47ca 08f7c9ed 95bb4da1>,
<b08fbebb 9100df77 5aba3640 c8237a5b 4ddbed50 fb6cb28c 439c7e37 9b2ccb4a>,
<77891dab a2acaff3 e52f71e3 0f8c3d5f eee99f43 f549e3fc 72eddd29 b2af83fd>,
<e5e3c8aa 5267d778 9fd62dc5 884ef416 5f836890 d82fed79 efd3796d bcb58503>,
<4e0fcdb8 4fbf9aa3 684875aa c54a4c5d c02020b2 d29212e4 587069d2 eed3aa31>,
<bd06507d f33ee72d d6bba2d5 c29eb8c5 1f87568b 186ab250 7312c0ec 6f2cd09c>,
<5431c046 d30e7f32 c2cc8099 58add1e7 579ad104 a3aa8fc4 846e97d7 af01cc79>,
<ad580044 b972d6ab df963bda ad071ba5 9c82aab5 4007f377 bf8858fe b9bc6274>,
<c9f7a2e3 13518dac 5ae5209d 239d1c11 0fd3f11f 5366b7d4 fd3a97d3 3e3d41d1>,
<3aef2c65 c9647274 1302fe8a fdca7ce6 cb87c7df 2751a19f bd946707 c8244729>,
<6705e1bf cac0c2ed b040b64f ca1f6e6e 74332890 907ec136 7a99606c e116a946>,
<856a10a5 18de663a 1860ea0d c0bd9295 769e4a42 99420fb5 02314b22 f39fe1a4>,
<6049b4fb 7d8c4e5f 63149e35 5abfd274 1264c2f9 76d13cf3 cc69a23a e29edac8>,
<6cf5aac1 67ead46a fbaf8450 11c2c0b9 dcc1e2ae dd3bbf86 06d09b78 4d4b6bbe>,
<715d9149 7aea98db fdb3a2fa e1682e12 dfe8f63a d09aac57 301be349 91fffd44>,
<e5bf6c2f c0c9d818 e1b4e2cc 9b7a92e3 2cd6bed4 5a98e6c3 53619376 9b3951ef>,
<fb9db76f 350ad944 88e1cf5d 15aaca9c 230355f9 13a2dace 62d5e4fb 0a2ecd7a>,
<35f6c30f a146166c 6e132297 bf463c59 756b8071 49aae2d7 ec6b6de8 fb7f7300>,
<9def8e9f 14dfb358 b5694bce 77759b7c c1901fe1 3e3a163b 80061b51 268089a8>,
<9f627411 6f8c0891 3693eab1 aa45cbd3 0143b28e 1e3584da e6ea2867 554a26ad>,
<dce53740 e8aba89f ac8180b4 0f297821 d09734a1 8ea3c344 8cb9dd6c d3baf645>,
<95c8cfb8 a1aafabc 90a9231b 0ef15d85 10e30393 5cfd4921 4db4a12f 511c8977>,
<cf3bd61a 71c2838c 421c6e50 41abd013 b0c153cb b165a0e6 21d5c352 f29b5743>,
<ec2a9e60 6ae28042 a62429e4 b0ec5939 3734e0ac 9a919421 a9fbede2 031b0bf6>,
<c3feffd4 8d223692 d314720a 4496b787 871db7d0 31097cff e1225b9b 6275e613>,
<06d0b355 4fb4ff4b 0adf05d4 8ce0378c 4aa156e9 a09c8a16 a82d8376 1fd2f929>,
<4fc9af50 0722da5d 18e0b755 63cf2a04 88e8b2d3 e8196ec2 375171b1 ce40fb4e>,
<002c8d92 8bc08e6c eb34fe0c a10ef78e ed050a8e 17a86e63 9911adb8 e2c36df1>,
<fd8c6be5 b97b3827 455a620c 3e6ff6e9 e2e09afd 472b9cbf 07d11e29 d5a52159>,
<362ea015 28a5c834 47b125c1 c460dd62 f0172785 e024b8aa 17dc544f 66871077>,
<22ff0e46 f56dbc7a e8e92cf6 9090a451 742517ff 7d29838d 0cd41e9e a3615134>
)}
2014-07-03 23:03:21.233 XXX[50242:60b] CoreData: annotation: (migration) found compatible mapping model /Users/jonathan/Library/Application Support/iPhone Simulator/7.1/Applications/XXX/XXX.app/1.0-1.1.1.cdm
我使用的是iOS 7.1和Xcode 5.1.1。
如上所述,1.0和1.1之间的唯一变化似乎是添加了一个表。我猜他们使用的哈希比较函数不认为这是一个冲突?我的下一个尝试是在假设使用字母搜索的情况下重命名迁移,以便首先找到并检查1.1-1.1.1迁移。除此之外,我希望我必须添加某种手动逻辑(通过子类化?)来强制将附加表视为模式不匹配。
答案 0 :(得分:0)
这不是为什么自动选择映射模型失败的答案。正如我在评论中写的那样,我确实遇到了类似的问题,并编写了我自己的(手动)映射模型选择。
对于手动选择,我们需要知道用于创建当前商店的模型。 所有实体(表)都有版本哈希,因此该哈希可用于标识模型版本。
应用启动后,但在加载持久性存储之前,映射模型选择循环遍历可能的数据模型,即1.0.xcdatamodel,1.1.xcdatamodel和1.1.1.xcdatamodel
逻辑将实体THIS_ONE
的已知哈希与持久性存储中的找到的版本哈希进行比较。 已知版本哈希THIS_ONE
来自数据模型文件。如果数据模型用于创建存储,则哈希匹配。
因此,应用程序循环显示已知模型名称列表(即&#34; 1.0&#34;,&#34; 1.1&#34;和&#34; 1.1.1&#34;)并调用匹配方法isModel:forStore:
。如果返回YES
,那么我们找到匹配的模型。
现在我们知道源数据模型,我们可以识别映射模型。下一步是使用适当的映射文件来实现实际迁移
migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error:
以下是匹配版本哈希的方法:
-(BOOL)isModel:(NSString *)modelUsed forStore:(NSURL *)storeUrl {
NSString *modelFound = @"unknown Model";
NSDictionary *knownTHIS_ONEHashes = [self knownTHIS_ONEHashes];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL doesExistCurrentStore = [fileManager fileExistsAtPath:[storeUrl path]];
if (doesExistCurrentStore) {
NSError *error = nil;
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeUrl error:&error];
if (nil == storeMetadata) { // no source meta data => dont know if need to migrate
NSLog(@"sourceMetadata is nil");
} else {
NSLog(@"sourceMetadata is %@", storeMetadata);
NSDictionary *storeHashes = [storeMetadata objectForKey:@"NSStoreModelVersionHashes"];
NSData *curentTHIS_ONEHash = storeHashes[@"THIS_ONE"];
for (NSString *modelName in [knownTHIS_ONEHashes allKeys]) {
if ([knownTHIS_ONEHashes[modelName] isEqualToData:curentTHIS_ONEHash]) {
NSLog(@"found matching model: %@",modelName);
modelFound = modelName;
break;
}
}
}
} // else store does not exist so there is no need for a data migration
return ([modelUsed isEqualToString:modelFound]);
}
已知哈希值在运行时从包中存在的模型中读取。 _kModelNameVx
是硬编码的模型名称。
-(NSDictionary *)knownTHIS_ONEHashes {
NSMutableDictionary *returnDict = [NSMutableDictionary new];
NSArray *knowModelFiles = @[_kModelNameV1, _kModelNameV2, _kModelNameV3, _kModelNameV4];
NSString * destinationModelPath;
NSURL * destinationModelURL;
NSManagedObjectModel * destinationModel;
for (NSString *singleFile in knowModelFiles) {
destinationModelPath = [[NSBundle mainBundle] pathForResource:singleFile
ofType:@"mom"
inDirectory:@"<xcdatamodel_name>.momd"];
destinationModelURL = [NSURL fileURLWithPath:destinationModelPath];
destinationModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL];
NSDictionary *modelMetadata = [destinationModel entityVersionHashesByName];
NSData *THIS_ONEHash = [modelMetadata objectForKey:@"THIS_ONE"];
[returnDict setValue:THIS_ONEHash forKey:singleFile];
}
return returnDict;
}