MagicalRecord: несколько баз данных

У меня есть приложение, которое использует MagicalRecord, и я предварительно заполняю базу данных большим количеством данных, которые используются для справки. В пределах той же модели данных у меня есть определяемая пользователем информация, относящаяся к вещам, которые пользователь может делать в приложении.

Приложение было отклонено, поскольку предварительно заполненные данные должны быть помечены как "не делать резервные копии". Таким образом, я хотел бы иметь эти данные в отдельном хранилище данных, чтобы сохранить данные пользователя как резервные.

Есть ли способ иметь два отдельных хранилища данных с помощью MagicalRecord?

Ответ 1

Я думаю, что это возможно, но не слишком легко. Как вы знаете, для работы с несколькими базами данных вы должны внести некоторые изменения в свой PersistentStoreCoordinator, поэтому у него будет два PersistentStores. После этого вы создадите стек Core Data следующим образом: enter image description here

Другим способом является создание двух отдельных PersistentStoreCoordinators, каждый из которых имеет один магазин.

В Magical Record существует несколько методов класса для добавления хранилищ в NSPersistentStoreCoordinator + MagicalRecord.h.

  • (NSPersistentStore *) MR_addInMemoryStore;
  • (NSPersistentStore *) MR_addAutoMigratingSqliteStoreNamed: (NSString *) storeFileName;
  • (NSPersistentStore *) MR_addSqliteStoreNamed: (id) storeFileName withOptions: (__ autoreleasing NSDictionary *) options;

Я думаю, что это то место, где вы могли бы сделать то, что хотите.

Также я должен упомянуть, что весь процесс настройки стека идет в MagicalRecord + Setup.h

+ (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName

Итак, вы можете добавить свои магазины и координаторы. Я никогда не справлялся с этим сам, это было просто краткое исследование возможного решения.

Ответ 2

Мне удалось решить эту проблему, используя конфигурации. Поскольку Magical Record всегда отправляет null для параметра конфигурации, я разломал setupCoreDataStackWithAutoMigratingSqliteStoreNamed и заменил его на метод, поддерживающий несколько конфигураций.

Поскольку Magical Record отлично справляется с обработкой автоматических миграций, я сначала вызываю setupCoreDataStackWithAutoMigratingSqliteStoreNamed, затем очистка, а затем я предоставляю свой код замены.

У меня есть одна объектная модель с моими объектами семенных данных, которым назначена конфигурация "Семя" и пользовательские объекты, назначенные для конфигурации "Пользователь". Магическая запись уже была инициализирована, поэтому при необходимости может автоматически мигрировать.

+(void) RB_setupMultipleStores:(NSString *) seedStoreName userStore:(NSString *) userStoreName
/* change persistent store to one with multiple configurations. Assumes Magical Record is initialized. */
{
NSError * error= nil;

[MagicalRecord cleanUp];

NSManagedObjectModel * model = [NSManagedObjectModel MR_defaultManagedObjectModel];

NSURL *seedURL = [NSPersistentStore MR_urlForStoreName:[seedStoreName stringByAppendingString:@".sqlite"]];

NSPersistentStoreCoordinator * coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                         [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                         nil];

NSPersistentStore * seedStore =[coordinator
                                  addPersistentStoreWithType:NSSQLiteStoreType
                                  configuration:@"Seed"
                                  URL:seedURL
                                  options:options
                                  error:&error];
if (!seedStore || error)
{
    NSLog(@"Error setting up seed store:%@ for %@", [error localizedDescription], seedURL);
    exit(-1);
}

NSURL *userURL = [NSPersistentStore MR_urlForStoreName:[userStoreName stringByAppendingString:@".sqlite"]];

NSPersistentStore * userStore = [coordinator
                                 addPersistentStoreWithType:NSSQLiteStoreType
                                 configuration:@"User"
                                 URL:userURL
                                 options:options
                                 error:&error];

if (!userStore || error)
{
    NSLog(@"Error setting up user store:%@ for %@", [error localizedDescription], userURL);
    exit (-1);
}
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:coordinator];

[NSManagedObjectContext MR_initializeDefaultContextWithCoordinator:coordinator];
}

Кроме того, MR 3.0 имеет одновременные стеки, которые могут решить проблему после ее завершения.

Ответ 3

Сохранение данных для разных объектов Core Data в разных файлах хранилища хорошо поддерживается и довольно просто. Тем не менее, MagicalRecrd не предоставляет никаких удобных методов для настройки вашего пакета Core Data таким образом. Вам просто нужно выделить свой стек вручную и сообщить MagicalRecord, чтобы использовать созданный NSPersistentStoreCoordinator. Вот как я сделал это быстро:

import Foundation
import CoreData
import MagicalRecord

class CoreDataSetup {
    static func setupAutoMigratingStack(withContentConfigurationName contentConfigurationName: String, userConfirgurationNameName: String) {
        MagicalRecord.cleanUp()

        let managedObjectModel = NSManagedObjectModel.MR_defaultManagedObjectModel()
        let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel!)

        let contentURL = NSPersistentStore.MR_urlForStoreName(contentConfigurationName + ".sqlite")
        let userURL = NSPersistentStore.MR_urlForStoreName(userConfirgurationNameName + ".sqlite")
        let options = [
            NSMigratePersistentStoresAutomaticallyOption : true,
            NSInferMappingModelAutomaticallyOption: true,
            NSSQLitePragmasOption: ["journal_mode": "DELETE"]
        ]
        do {
            try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: contentConfigurationName, URL: contentURL, options: options)
            try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: userConfirgurationNameName, URL: userURL, options: options)

            NSPersistentStoreCoordinator.MR_setDefaultStoreCoordinator(persistentStoreCoordinator)
            NSManagedObjectContext.MR_initializeDefaultContextWithCoordinator(persistentStoreCoordinator)
        } catch {
            print("Error adding persistent store to coordinator: \(error) ")
        }
    }
}

Обратите внимание, что в моем коде я имею в виду вашу концепцию "семенного" хранилища как "контент" и определяемое пользователем хранилище как "пользователь".

Чтобы выполнить второй аспект вашего вопроса, настроив хранилище содержимого, чтобы он не был скопирован, вам просто нужно поиграть с URL-адресами, в которых вы храните каждый магазин, помещая хранилище содержимого в резервный временный каталог без резервной копии, и копировать его в это место до запуска из вашего пакета приложений, если он не существует.