1

I have a situation where I have made changes to an SQLite database for the next release of my app, because of the changes to the SQLite database I have also made changes to some code that reads from it, primarily adding columns to the query method.

Because of the changes the next time the user updates the application they must have the new database for it to work. On the previous version of my app I have a database named File.sqlite, when the user downloads the application fresh that file gets saved to their documents folder. Now I have built the application with a new file but same name File.sqlite that has some more columns and such in it but when I update the application (not a fresh install) that new file does not replace the old.

How can I ensure that when the user updates the application the file will be replaced/updated?

As of right now I understand that I can use the following to get the path of the old file in documents directory:

//Reference the path to the documents directory.
NSString *documentDir =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//Get the path of old file.
NSString *filePath = [documentDir stringByAppendingPathComponent:@"File.sqlite"];

Does the new file have to have a different name and I just reference the new name in the code? That seems silly to me, I must be able to make a copy of the old and use the new version?

Also, I am not even sure if this is the best approach to do what I am trying to do so also if you know of a better way please advise.

Robert Saunders
  • 403
  • 8
  • 22
  • Surely your answer lies in [these search results](http://stackoverflow.com/search?q=%5Bios%5D+sqlite+schema+change). – rmaddy May 23 '16 at 01:10
  • @rmaddy I wouldn't have asked my question if I could find a solution, I have tried looking at those solution. – Robert Saunders May 23 '16 at 01:14
  • There's [this one](http://stackoverflow.com/questions/989558/best-practices-for-in-app-database-migration-for-sqlite?lq=1), [this one](http://stackoverflow.com/questions/10136256/updating-new-version-to-app-store-with-different-sqlite-db-structure), [this one](http://stackoverflow.com/questions/16284430/how-to-overwrite-a-sqlite-db-in-ios), and [this one](http://stackoverflow.com/questions/17369603/how-to-detect-that-the-app-version-has-changed/17375294?s=3|0.7471#17375294). – rmaddy May 23 '16 at 01:20
  • 1
    I have an app wherein I have a similar situation from time to time. What I do is use a flag in `NSUserDefaults` to track which version of the data file is currently being used. When a new one is needed, I change the file name of the current file (by appending `OLDddMMYYYY`), and then just copy over the new file. Works well. – Craig Smith May 23 '16 at 01:23
  • are u using core data at all? – Yuchen May 23 '16 at 01:51
  • Which is the best approach that you are referring to? What you have done here so far is to just show the path of your file and nothing more. – El Tomato May 23 '16 at 02:54
  • @ElTomato I was referring to the general technique of updating databases within the app not what I was doing. – Robert Saunders May 23 '16 at 12:30
  • @YuchenZhong I am using Core Data for the users data, however my application also relies on data the application should provide. – Robert Saunders May 23 '16 at 12:31
  • @CraigSmith thats a good suggestion, from answer I marked correct I think that is what I will be doing now. – Robert Saunders May 23 '16 at 12:34

2 Answers2

3

You can check if your application is a fresh install or an update from AppDelegate. However, it seems you are not saving your App Version in NSUserDefaults, it will be a bit tricky for you. You save your new version of File.sqlite in Resource and copy it to document directory.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
    NSString* curVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
    NSString* lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:@"LastVersion"];

    if ( lastVersion == nil ) 
    {
        //App Installed for the first time. In your case it might be an update because you do not store lastVersion value.

        //Reference the path to the documents directory.
        NSString *documentDir =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        //Get the path of old file.
        NSString *filePath = [documentDir stringByAppendingPathComponent:@"File.sqlite"];

       if([[NSFileManager defaultManager] fileExistsAtPath: filePath])
       {
          [fileManager removeItemAtPath:filePath error:&error] //Delete old file
       }
       //Copy New File.sqlite from Resource Bundle.
       NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"File" ofType:@"sqlite"];
       [fileManager copyItemAtPath:resourcePath toPath:filePath error:&error]; 
    } 
    else if (![lastVersion isEqual: curVersion]) 
    {
      // App is updated. For future Versions you can Update files from here! 
    } 

    [[NSUserDefaults standardUserDefaults] setObject:curVersion forKey:@"LastVersion"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Hope this helps!

eracube
  • 2,484
  • 2
  • 15
  • 18
2
NSArray *pathsToDocuments = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [pathsToDocuments objectAtIndex: 0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:@"File.sqlite"]; //File.sqlite old database

NSString *pathStr = [documentsDirectory stringByAppendingPathComponent:@"File1.sqlite"]; // New database file name
FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
[database open];
FMDatabase *database1 = [FMDatabase databaseWithPath:pathStr];
[database1 open];

NSString *str = @"select * from table_name"; // old database fire query for use data value fetch

FMResultSet *res=[database executeQuery:str];

//   Your old database value updated to update new database.
while ([res next]) {
    NSString *query= // Write update query for update column value
    [database1 executeUpdate:query];
}
[database1 close];
[database close];

// remove old database file 
if ([[NSFileManager defaultManager] isReadableFileAtPath: dbPath])
{
    if ([[NSFileManager defaultManager] removeItemAtPath:dbPath error: NULL] != YES)
        NSAssert2(0, @"Fail to copy database from %@ in %@", dbPath, pathStr);
}
Bhadresh Kathiriya
  • 3,147
  • 2
  • 21
  • 41