在迁移核心数据多到多关系到一个连接表(Migrating a many-to-many relati

2019-06-25 16:58发布

我已经得到了使用许多一对多关系链接标签和注释在一起的iPhone应用程序。 我目前使用的核心数据的“关系”功能来做到这一点,但想迁移到使用一个连接表来代替。

这里是我的挑战:我想从旧模式向加盟表模型迁移,以及我需要弄清楚如何执行数据迁移。

是否有一个如何做到这一点任何很好的例子?

更新:我在这里澄清,我的问题,以帮助什么是怎么回事:我想用尽量Simperium来支持我们的应用程序,但Simperium不支持许多一对多的关系(!)。

至于是什么,我试图做一个例子,让我们使用iPhoneCoreDataRecipes应用作为例子。

下面是我的核心数据方案目前类似:

...这里就是我过渡到:

我如何从一个到另一个,和我一起把数据?

苹果的核心数据迁移文档是出了名的稀疏,我看不出任何有用的演练了使用NSEntityMapping或NSMigrationManager子类来完成这项工作。

Answer 1:

这里的基本过程是:

  1. 创建数据模型的版本副本。 (选择型号,然后编辑 - >添加示范文本)

  2. 进行更改数据模型的新副本

  3. 标志着新的数据模型的副本作为当前版本。 (点击顶级xcdatamodel项目,然后在文件检查器中设置下“版本的数据模型”部分的“当前”进入您在步骤1中创建新的数据模型。

  4. 更新你的模型对象添加RecipeIngredient实体。 同时更换原料和配方上的食谱关系,并与您在步骤2到RecipeIngredient实体创建新的关系成分的实体。 (这两个实体获得这种关系增加。我打电话给我recipeIngredients)显然,无论你在旧代码创建成分配方的关系,你现在需要创建一个RecipeIngredient对象..但已经超出了这个答案的范围。

  5. 添加车型之间的新映射(文件 - >新建文件...->(核心数据段) - >映射模型这将自动为您生成几个映射RecipeToRecipe,IngredientToIngredient和RecipeIngredient。

  6. 删除RecipeIngredient映射。 还删除recipeIngredient关系映射它给你RecipeToRecipe和IngredientToRecipe(或任何你叫他们在步骤2中)。

  7. 拖动RecipeToRecipe映射是最后的映射规则列表中。 (因此,我们相信该成分的配方之前迁移,使我们可以当我们迁移的食谱他们连接起来这是非常重要的 。)迁移将在迁移规则列表的顺序去。

  8. 设置自定义策略的RecipeToRecipe映射“DDCDRecipeMigrationPolicy”(这将覆盖配方对象的自动迁移,并给我们一个钩子,我们可以执行映射逻辑。

  9. 通过继承NSEntityMigrationPolicy食谱覆盖createDestinationInstancesForSourceInstance创建DDCDRecipeMigrationPolicy(见下面的代码)。 这一次,每个配方被调用,这将让我们创建配方对象,同时也将其链接的相关RecipeIngredient对象成分。 我们只要让成分被自动通过Xcode的汽车在第5步中为我们创建的映射规则迁移。

  10. 无论你创建你的持久化对象存储(可能的AppDelegate),确保您设置的用户词典自动迁移数据模型:

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
      configuration:nil 
      URL:storeURL 
      options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,  nil] 
      error:&error])
{
}

子类NSEntityMigrationPolicy食谱

#import <CoreData/CoreData.h>
@interface DDCDRecipeMigrationPolicy : NSEntityMigrationPolicy
@end

* 覆盖createDestinationInstancesForSourceInstance在DDCDRecipeMigrationPolicy.m *

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
{

    NSLog(@"createDestinationInstancesForSourceInstance : %@", sInstance.entity.name);

   //We have to create the recipe since we overrode this method. 
   //It's called once for each Recipe.  
    NSManagedObject *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:[manager destinationContext]];
    [newRecipe setValue:[sInstance valueForKey:@"name"] forKey:@"name"];
    [newRecipe setValue:[sInstance valueForKey:@"overview"] forKey:@"overview"];
    [newRecipe setValue:[sInstance valueForKey:@"instructions"] forKey:@"instructions"];

    for (NSManagedObject *oldIngredient in (NSSet *) [sInstance valueForKey:@"ingredients"])
    {
        NSFetchRequest *fetchByIngredientName = [NSFetchRequest fetchRequestWithEntityName:@"Ingredient"];
        fetchByIngredientName.predicate = [NSPredicate predicateWithFormat:@"name = %@",[oldIngredient valueForKey:@"name"]];

        //Find the Ingredient in the new Datamodel.  NOTE!!!  This only works if this is the second entity migrated.
         NSArray *newIngredientArray = [[manager destinationContext] executeFetchRequest:fetchByIngredientName error:error];

        if (newIngredientArray.count == 1)
        {
             //Create an intersection record. 
            NSManagedObject *newIngredient = [newIngredientArray objectAtIndex:0];
            NSManagedObject *newRecipeIngredient = [NSEntityDescription insertNewObjectForEntityForName:@"RecipeIngredient" inManagedObjectContext:[manager destinationContext]];
            [newRecipeIngredient setValue:newIngredient forKey:@"ingredient"];
            [newRecipeIngredient setValue:newRecipe forKey:@"recipe"];
             NSLog(@"Adding migrated Ingredient : %@ to New Recipe %@", [newIngredient valueForKey:@"name"], [newRecipe valueForKey:@"name"]);
        }


    }

    return YES;
}

我会发布在Xcode中设置及样品Xcode项目的图片,但我似乎并没有对堆栈溢出还没有任何信誉分...所以它不会让我。 我会后这对我的博客也是如此。 bingosabi.wordpress.com/。

还要注意的是,Xcode的核心数据模型映射的东西是有点片状,偶尔需要一个“干净”的,良好的Xcode RESTER,模拟器反弹或以上所有的都搞不定。



Answer 2:

正如我在关于这一问题的意见建议,你可能不希望改变你的数据模型,而是创建模型和不理解许多一对多关系库之间的桥梁。

要创建的连接表,实际上是已经在那里,你只需要另一种方式来您的数据提供给该库。

这是否能正常工作,取决于这个库如何看待你的模型。 有它不同的方式来查询您的实体的属性,或者它可能是你是一个指定哪些属性/关系被复制。

这很难给出一个真正的答案,而对所有这一切的任何细节,但总的想法是:

你有头看起来像一些管理的对象:

// Recipe.h

@interface Recipe : NSManagedObject
@property (nonatomic,retain) NSSet *ingredients;
@end

现在你到这个对象的一些额外的方法,使用类别:

// Recipe+fakejoin.h

@interface Recipe (fakejoin)
-(NSSet*)recipeIngredients;
@end

和在一个实施Recipe+fakejoin.m此方法,它返回一个的NSSetRecipeIngredients对象。

但正如我所说,这是一个开放的问题,如果这个库可以让你玩这样不会破坏东西。 如果这一切听起来新的给你,还是另找一个解决方案...



文章来源: Migrating a many-to-many relationship to a join table in Core Data