2011-08-11 82 views
5

我发现文档非常有限,我的问题解决方案无处可寻。核心数据版本控制和自定义策略迁移

我需要添加新的实体(与现有的关系)。还要添加和重命名现有实体的一些属性。

Lightweighted例如:

旧模型具有一个属性name一个实体Item

在新模型中,我想要Item有一个新属性dateAdded并将其重命名为nametitle。在这一点上,如果dateAdded将是可选的或给定的默认值,我可以使用轻量级迁移功能。纠正我,如果我错了。

但我也想增加新的List实体与title属性。并添加多对多关系。列表可以是空的或有许多项目。项目必须提及一个列表。

所以我很困惑我所做的一切和顺序。

  1. 禁用轻量级迁移功能(NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:NO], NSInferMappingModelAutomaticallyOption, nil];),启用迁移。

  2. 创建一个新版本的模型。在那里我做了我想要的改变。

  3. 创建一个新的映射模型。来源是旧模型,目标是新模型。在ItemToItem中,我将title设置为$source.name

除了Xcode仍在使用映射模型时崩溃,我不知道接下来要做什么。我认为我必须在上下文中创建List的一个实例,并根据关系策略将所有项引用到它。而我应该使用自定义NSEntityMigrationPolicy来做到这一点。任何帮助来完成这个挑战?

回答

9

嗯,我做到了...

我的前3个步骤是正确的。继续方案:

ADD4。做一个ItemToItemMigrationPolicyNSEntityMigrationPolicy的一个子类。替代:

- (BOOL)beginEntityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error 
{ 
    List* list = (List*)[NSEntityDescription insertNewObjectForEntityForName:@"List" inManagedObjectContext:[manager destinationContext]]; 
    list.name = @"Default list"; 

    return YES; 
} 

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error 
{ 
    Item* item = (Item*)[NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] inManagedObjectContext:[manager destinationContext]]; 
    item.dateAdded = [NSDate date]; 
    task.title = [sInstance valueForKey:@"name"]; 

    [manager associateSourceInstance:sInstance withDestinationInstance:item forEntityMapping:mapping]; 

    return YES; 
} 

- (BOOL)createRelationshipsForDestinationInstance:(NSManagedObject *)dInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error 
{ 

    NSFetchRequest* fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"List"]; 
    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"name LIKE 'Default list'"]; 
    fetchRequest.predicate = predicate; 

    NSError* fetchRequestError = nil; 
    NSArray* listsArray = [manager.destinationContext executeFetchRequest:fetchRequest error:&fetchRequestError]; 
    if (fetchRequestError) { 
     NSLog(@"%@", fetchRequestError.localizedDescription); 
    } 
    List* list = [listsArray lastObject]; 

    ((Item*)dInstance).list = list; 

    return YES; 
} 

ADD5。在映射模型中的Xcode中,将ItemToItem迁移策略设置为自定义ItemToItemMigrationPolicy值。

ADD6。使您的新模型版本保持最新并从新的或更改的实体生成(替换)类。

ADD7。对代码进行更改,例如item.name不再适用。现在它是item.title。清理项目并运行。

+0

为什么轻量级需要禁用重量级?它为我工作。所以我的梦想代码是错的?! – khunshan

1

如果您要添加新实体,则需要使用自定义映射模型并关闭轻量级迁移。

一件重要的事情。在使用迁移时,请确保您每次都从现有持久存储的新示例开始,特别是在发生崩溃时。如果你不这样做,你可以腐败商店,这会导致错误雪球。

+0

我正在进行我的移民计划。 AFAIK,您可以避免在尝试迁移之前检查并删除临时存储区的商店损坏问题。这还将确保您的应用程序不会在迁移无法进行用户干预,断电等情况下尝试使用已损坏的商店进行迁移。 – stephen