如果只是简单的改变模型,比如给一个实体添加一个新属性, Core Data 可以自动进行数据迁移,也就是指轻量级迁移。轻量级迁移基本上和普通迁移是一样的,不过不需要提供映射模型,(在映射概况中有介绍),Core Data自行推断新模型和目标模型的差异。
轻量级迁移在应用开发的早期阶段使用非常方便,当你频繁的改变对象模型,但是又不想重新生成测试数据的时候。你可以迁移已存在的数据,不需要为每个模型重新创建一个映射模型,用来创建迁移需要的store。
另一个好处是,当你使用推测模型(inferred model)和 SQLite 存储时,Core Data 可以执行就地(in situ)迁移,严格讲,直接生成并执行 SQL 语句。因为没有载入任何数据,所以能很多程度上提升性能。因此,推荐你尽可能的使用推测模型,即使需要创建映射模型。
Core Data 必须能推测出映射关系
执行自动化迁移,Core Data 需要能够在运行时找到源和目标的映射关系,一般我们将数据模型存放在 bundles文件夹中(使用 NSBundle 的 allBundles 和 allFrameworks 方法获得)Core Data可以找到并发现它,如果放在别的地方,需要按照 “Use a Migration Manager if Models Cannot Be Found Automatically .” 中说的步骤操作。Core Data 随后自动分析现有表和字段的变化,自动产生推测的映射模型(inferred mapping model)。
以下几种情况,Core Data 可以自动推测出:
-
添加新属性/字段
-
删除属性/字段
-
必填属性/字段改为可选属性/字段
-
可选属性/字段改为必填属性/字段,并设置默认值
-
重命名实体/表或属性/字段
如果要重命名,需要将新版本中新实体/属性的“重命名标识符”(renaming identifier)的值设置为原来的实体名或属性名。具体方法:Xcode Data Modeling 工具->属性查看器(property inspector)。
比如你可以:
重命名一个 Car 实体为Automobile
重命名一个Car的color属性为paintColor
可以想象,这样做以后,如一个属性的名字在三次修改中都变化了,且都标记了重命名标识符,这样不管是从 version 2 到 version 3 还是从 version 1 到 version 3 都可以无错误的迁移。
另外,Core Data 还可以自动猜测出:
-
增加关系(relationship)和 改变关系类型
-
增加新关系,删除现有关系
-
重命名关系名称 (同样设置重命名标识符,同重命名属性一样)
-
改变关系由对一到对多,或者a non-ordered to-many to ordered (反之亦然)
-
-
改变实体/表的体系结构
-
增加、删除、重命名实体/表
-
增加新的父、子实体/表,移动属性/字段的顺序
-
将实体/表移出体系
注意,不能整合(merge)两个实体体系(如果两个实体在原模型中不是共享一个父类实体,那么目标模型中也不能共享一个父类实体)
-
使用选项字典(Options Dictionary)请求自动迁移(Automatic Migration)
通过定义选项字典请求自动轻量级迁移,将 NSMigratePersistentStoresAutomaticallyOption 和 NSInferMappingModelAutomaticallyOption 两个键值设置为YES,然后调用 addPersistentStoreWithType:configuration:URL:options:error:
You request automatic lightweight migration using the options dictionary you pass inaddPersistentStoreWithType:configuration:URL:options:error:
, by setting values corresponding to both the NSMigratePersistentStoresAutomaticallyOption
and theNSInferMappingModelAutomaticallyOption
keys to YES
:
NSError *error = nil; |
NSURL *storeURL = <#The URL of a persistent store#>; |
NSPersistentStoreCoordinator *psc = <#The coordinator#>; |
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: |
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, |
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; |
|
BOOL success = [psc addPersistentStoreWithType:<#Store type#> |
configuration:<#Configuration or nil#> URL:storeURL |
options:options error:&error]; |
if (!success) { |
// Handle the error. |
} |
可以使用 NSMappingModel 的 inferredMappingModelForSourceModel:destinationModel:error: 方法,获取推测的映射模型,如果可以推测出返回,如果不可以,返回 nil。
如果不能自动找到模型,则使用迁移管理器(Migration Manager)
- (BOOL)migrateStore:(NSURL *)storeURL toVersionTwoStore:(NSURL *)dstStoreURL error:(NSError **)outError { |
|
// Try to get an inferred mapping model. |
NSMappingModel *mappingModel = |
[NSMappingModel inferredMappingModelForSourceModel:[self sourceModel] |
destinationModel:[self destinationModel] error:outError]; |
|
// If Core Data cannot create an inferred mapping model, return NO. |
if (!mappingModel) { |
return NO; |
} |
|
// Create a migration manager to perform the migration. |
NSMigrationManager *manager = [[NSMigrationManager alloc] |
initWithSourceModel:[self sourceModel] destinationModel:[self destinationModel]]; |
|
BOOL success = [manager migrateStoreFromURL:storeURL type:NSSQLiteStoreType |
options:nil withMappingModel:mappingModel toDestinationURL:dstStoreURL |
destinationType:NSSQLiteStoreType destinationOptions:nil error:outError]; |
|
return success; |
} |
Note: OS X v10.7 and iOS 4之前,需要使用 store-specific migration manager执行轻量化迁移,你通过已存在的 persistent store来获得 migration manager,使用migrationManagerClass
,如下面示例展示的
- (BOOL)migrateStore:(NSURL *)storeURL toVersionTwoStore:(NSURL *)dstStoreURL error:(NSError **)outError { |
|
// Try to get an inferred mapping model. |
NSMappingModel *mappingModel = |
[NSMappingModel inferredMappingModelForSourceModel:[self sourceModel] |
destinationModel:[self destinationModel] error:outError]; |
|
// If Core Data cannot create an inferred mapping model, return NO. |
if (!mappingModel) { |
return NO; |
} |
|
// Get the migration manager class to perform the migration. |
NSValue *classValue = |
[[NSPersistentStoreCoordinator registeredStoreTypes] objectForKey:NSSQLiteStoreType]; |
Class sqliteStoreClass = (Class)[classValue pointerValue]; |
Class sqliteStoreMigrationManagerClass = [sqliteStoreClass migrationManagerClass]; |
|
NSMigrationManager *manager = [[sqliteStoreMigrationManagerClass alloc] |
initWithSourceModel:[self sourceModel] destinationModel:[self destinationModel]]; |
|
BOOL success = [manager migrateStoreFromURL:storeURL type:NSSQLiteStoreType |
options:nil withMappingModel:mappingModel toDestinationURL:dstStoreURL |
destinationType:NSSQLiteStoreType destinationOptions:nil error:outError]; |
|
return success; |
} |