0
votes

I am trying to perform a migration between two versions of CoreData that differ fundamentally to the fact that the new version has two configurations so I can save entities in two different sqlite file (one read-only in Main Bundle and one, the old sqlite, used now only for user data). I also added a model mapping to map the differences, especially to reset relationships between the entities that are lost due to multiple configurations. The app works properly without crash if installed from scratch and new records are inserted in user data sqlite in application documents directory as expected. The problem is when I try a migration from previous Core Data version: the app start without crash but on first executeFetchRequest it crash at coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: "Userdata", URL: urlUser, options: optionsUser, error: &errorUser) (viewed with debug) and console return this log:

2015-02-23 18:48:24.052 MedAbility[21480:585606] CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///Volumes/Documenti/Users/andrea/Library/Developer/CoreSimulator/Devices/301801BE-4B6A-4371-BE66-3E71557B0897/data/Containers/Data/Application/FBEC0124-1D74-4F94-99F2-6F492281AA8E/Documents/MedAbility.sqlite options:{ NSInferMappingModelAutomaticallyOption = 1; NSMigratePersistentStoresAutomaticallyOption = 1; } ... returned error Error Domain=NSCocoaErrorDomain Code=134080 "The operation couldn’t be completed. (Cocoa error 134080.)" UserInfo=0x7fb50ae481d0 {NSUnderlyingException=Can't add the same store twice} with userInfo dictionary { NSUnderlyingException = "Can't add the same store twice"; } 2015-02-23 18:48:24.061 MedAbility[21480:585606] CoreData: error: -addPersistentStoreWithType:SQLite configuration:Userdata URL:file:///Volumes/Documenti/Users/andrea/Library/Developer/CoreSimulator/Devices/301801BE-4B6A-4371-BE66-3E71557B0897/data/Containers/Data/Application/FBEC0124-1D74-4F94-99F2-6F492281AA8E/Documents/MedAbility.sqlite options:{ NSInferMappingModelAutomaticallyOption = 1; NSMigratePersistentStoresAutomaticallyOption = 1; } ... returned error Error Domain=NSCocoaErrorDomain Code=134080 "The operation couldn’t be completed. (Cocoa error 134080.)" UserInfo=0x7fb50ae481d0 {NSUnderlyingException=Can't add the same store twice} with userInfo dictionary { NSUnderlyingException = "Can't add the same store twice"; }

This is my code:

Old version PersistentStoreCoordinator:

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        // Create the coordinator and store
        var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("MedAbility.sqlite")
        var error: NSError? = nil
        var failureReason = "There was an error creating or loading the application's saved data."
        // Set options for migrations
        let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
            coordinator = nil
            // Report any error we got.
            let dict = NSMutableDictionary()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = failureReason
            dict[NSUnderlyingErrorKey] = error
            error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)

            NSLog("Unresolved error \(error), \(error!.userInfo)")
        }

        // Exclude db from backup
        Util.addSkipBackupAttributeToItemAtURL(url)

        return coordinator
        }()

New version PersistentStoreCoordinator:

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
        // Create the coordinator and store
        var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

        let url = NSBundle.mainBundle().URLForResource("MedAbilityDomande", withExtension: "sqlite")
        var error: NSError? = nil
        var failureReason = "There was an error creating or loading the application's saved data."
        // Set questions sqlite as read-only
        let options = [NSReadOnlyPersistentStoreOption: true]
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: "Domande", URL: url, options: options, error: &error) == nil {
            coordinator = nil
            // Report any error we got.
            let dict = NSMutableDictionary()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = failureReason
            dict[NSUnderlyingErrorKey] = error
            error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)

            NSLog("Unresolved error \(error), \(error!.userInfo)")
        }

        let urlUser = self.applicationDocumentsDirectory.URLByAppendingPathComponent("MedAbility.sqlite")
        var errorUser: NSError? = nil
        var failureReasonUser = "There was an error creating or loading the application's saved data."
        // Set migration options
        let optionsUser = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: "Userdata", URL: urlUser, options: optionsUser, error: &errorUser) == nil {
            coordinator = nil
            // Report any error we got.
            let dict = NSMutableDictionary()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = failureReasonUser
            dict[NSUnderlyingErrorKey] = errorUser
            errorUser = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)

            NSLog("Unresolved error \(errorUser), \(errorUser!.userInfo)")
        }

        return coordinator
        }()

Someone know how can I resolve this issue?

Thanks for the help!

EDIT

I did some test and I found that commenting coordinator!.addPersistentStoreWithType (NSSQLiteStoreType, configuration: "Questions", URL: url, options: options, error: & error) for the first database, the application starts without issues, obviously without the content of the database not added. If I reverse the addition of the two database the app crashes with same log except for "URL: file:[...]" that it's called on the ex-first now-second database ("MedAbilityDomande.sqlite"); in practice it's the addition of the second database the problem and not a specific database. It seems that migrating the old database to the new one used for user data actually doesn't migrate configurations, so remains the old configuration that goes to overlap the entities with the new read-only database inserted into the mainBundle. As I have previously said if the app start from scratch (without migration) works perfectly.

Do you have any idea?

Thank you so much again!

1

1 Answers

0
votes

I finally found the solution! I created the database MedAbilityDomande.sqlite based on the database that after I wanted to migrate to use for user data. This brought to have two databases with same UUID generating the error "Can't add the same store twice". It was enough to change the UUID of the database in the application bundle (MedAbilityDomande.sqlite) and everything worked great.

Until next time!