簡體   English   中英

將多對多關系遷移到Core Data中的連接表

[英]Migrating a many-to-many relationship to a join table in Core Data

我有一個iPhone應用程序,它使用多對多關系將標簽和注釋鏈接在一起。 我目前正在使用Core Data的“關系”功能來完成此任務,但我想遷移到使用連接表。

這是我的挑戰:我想從舊模型遷移到連接表模型,我需要弄清楚如何執行數據遷移。

有什么好的例子說明如何做到這一點?

更新:我在這里澄清我的問題,以幫助解決這里發生的事情:我想嘗試使用Simperium來支持我們的應用程序,但是Simperium不支持多對多關系(!)。

作為我正在嘗試做的一個例子,讓我們以iPhoneCoreDataRecipes應用程序為例。

以下是我的核心數據方案目前的類似內容: 在此輸入圖像描述

......這就是我要過渡到的地方: 在此輸入圖像描述

我如何從一個到另一個,並帶來數據?

Apple的Core Data Migration文檔非常稀疏,我沒有看到任何有用的演練來使用NSEntityMapping或NSMigrationManager子類來完成工作。

這是基本過程:

  1. 創建數據模型的版本化副本。 (選擇模型,然后選擇編輯器 - >添加模型版本)

  2. 對數據模型的新副本進行更改

  3. 將新數據模型的副本標記為當前版本。 (單擊頂級xcdatamodel項,然后在文件檢查器中將“Versioned Data Model”部分下的“Current”條目設置為您在步驟1中創建的新數據模型。

  4. 更新模型對象以添加RecipeIngredient實體。 同時使用您在步驟2中為RecipeIngredient實體創建的新關系替換配方和成分實體上的成分和配方關系。 (兩個實體都添加了這種關系。我稱之為recipeIngredients)顯然,無論你在舊代碼中創建從成分到配方的關系,你現在都需要創建一個RecipeIngredient對象..但這超出了這個答案的范圍。

  5. 在模型之間添加一個新的映射(文件 - >新文件...->(核心數據部分) - >映射模型。這將為您自動生成幾個映射.RecipeToRecipe,IngredientToIngredient和RecipeIngredient。

  6. 刪除RecipeIngredient映射。 同時刪除它為RecipeToRecipe和IngredientToRecipe(或在步驟2中稱為它們的任何內容)提供的recipeIngredient關系映射。

  7. 將RecipeToRecipe Mapping拖動到映射規則列表中的最后一個。 (這很重要,因此我們確保在食譜之前遷移成分,以便我們可以在遷移食譜時將它們鏈接起來。)遷移將按遷移規則列表的順序進行。

  8. 為RecipeToRecipe映射設置自定義策略“DDCDRecipeMigrationPolicy”(這將覆蓋Recipes對象的自動遷移,並為我們提供一個可以執行映射邏輯的鈎子。

  9. 通過為配方子類化NSEntityMigrationPolicy創建DDCDRecipeMigrationPolicy以覆蓋createDestinationInstancesForSourceInstance(請參閱下面的代碼)。 這將為每個食譜調用一次,這將讓我們創建食譜對象,以及將它鏈接到成分的相關RecipeIngredient對象。 我們將在步驟5中通過Xcode自動為我們創建的映射規則自動遷移Ingredient。

  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

* 覆蓋DDCDRecipeMigrationPolicy.m中的createDestinationInstancesForSourceInstance *

- (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,模擬器彈跳或上述所有工作。

正如我在問題的評論中所建議的那樣,您可能不想更改數據模型,而是在模型和不理解多對多關系的庫之間建立橋梁。

您要創建的連接表實際上已經存在,您只需要另一種方法將數據呈現給此庫。

這是否可行,取決於此庫如何查看您的模型。 它有多種方法可以查詢實體的屬性,或者可能是您指定要復制哪些屬性/關系的方法。

很難給出真正的答案,沒有關於所有這些的任何細節,但總體思路是:

你有一些托管對象,標題看起來像:

// Recipe.h

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

現在你使用一個類別向這個對象添加一些額外的方法:

// Recipe+fakejoin.h

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

以及此方法的Recipe+fakejoin.m中的實現,它返回帶有RecipeIngredients對象的NSSet

但正如我所說,這是一個懸而未決的問題,如果這個庫允許你這樣玩,而不會破壞東西。 如果這一切聽起來都是新的,那么最好找到另一種解決方案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM