Search code examples
c#entity-frameworksqliteuwpentity-framework-core-migrations

uwp sqlite add-migration crashes when updated to a new project


I have SQLite database in my uwp project (with entity framework) as per this documentation.

I had a uwp project targetting Anniversary update so at that time this documentation was old and I had to add the database code and stuff within my uwp project (and not in a .Net standard project) so that project got installed by a lot of user over the store and they all obviously now have a database created on their devices, let's say Db1.db.

After a year I updated my app and retargeted it to creators update and I did this in a new project because I had to make some major changes to my app so I wanted a clean project to start with, I added my features and also added the database stuff the same way as previous project with same database name Db1.db and then I published it to store as well.

Problem

Now when I published my second package it crashed on DBContext.Migrate() method which is supposed to be in constructor of app.xaml.cs I understand it crashed because the name of the database was same and both projects had only 1 migration known as MyFirstMigration and somehow that conflicted and crashed the application. I can confirm it because soon after I made an update to my 2nd package (which targets creators update) and changed the database name to Db2.db and now I didn't get a crash because now the app is ignoring the old database on user's device and just creating and using the new database, which is not the best way because my existing user's can't access the data they had in Db1 although the new users won't be affected as they have all their data only in Db2.

Here is the situation right now:

User Group 1 these users have their old data in db1 and new data in db2

User Group 2 these users have all of their data in db2

I probably will keep making new projects from scratch to target newer SDKs, because I like to make newer major updates from scratch which helps me refactoring whole app easily. So how can I use the same database name in my newer projects without crashing the app ? I am not changing my model, my model will remain the same and I want to keep using only 1 database file no matter how many new projects I publish to the store, the app should always talk to that 1 database file. would this be possible if I just copied the Migrations folder from my older project and paste it new project and keep that migrations folder consistent across my newer versions? or is there any other way?

Also note that now in my newer projects my min target will be fall creators update so I will use a .net standard library to keep my db stuff there as mentioned in the docs I mentioned above, so I would like to keep using db2.db in my new projects as well.


Solution

  • This seems an issue about user data synchronization. As what I understand, you can use the db2.db in your new fall creators update UWP app(We will call it New Version), but after user upgrade your app to New Version and launch your app at the first time, you can check whether there exist a db1.db in your project, if it existed, you can copy the data from the db1.db to the new db2.db.

    This way looks like to backup and restore, but in uwp app, update will not delete your db1.db, you just need to "restore" or copy the data to your new db2.db which is created by using the new feature of using EF Core UWP app, then you can just operate the db2.db to store the user data later and you no longer need to use the db1.db again.

    ---Update---

    are you saing everytime I create a new project I should copy data from previous database? means I cannot use same database file?

    Actually, you just need copy once from db1.db to db2.db, because you have transformed your project to using EF Core. In the later version, since you have used the EF Core, if you create a new project update, you can use the db2.db directly without any issue in my test.

    how can I check if old db exists?

    As you have known the db file name and the file location, you can check whether the old db exist by checking whether the db file exist.

    private async Task<bool> IsFileExisted(string fileName)
    {
        var result= await ApplicationData.Current.LocalFolder.TryGetItemAsync(fileName);
        if (result == null)
        {
            return false;
        }
        return true;
    }
    

    As the document you provide, it seems the Migrate method is call in the App's Constructor, this will cause to use an async method toughly. So you can put the code of Migrate in App's OnLaunched event handler.

     protected async override void OnLaunched(LaunchActivatedEventArgs e)
     {
         using (var db = new BloggingContext())
         {
             //db.Database.EnsureCreated();
             bool isExist = await IsFileExisted("db1.db");
             if (!isExist)
             {
                 db.Database.Migrate();
             }
    
         }
    
         Frame rootFrame = Window.Current.Content as Frame;
    
         // Do not repeat app initialization when the Window already has content,
         // just ensure that the window is active
         if (rootFrame == null)
         {
             // Create a Frame to act as the navigation context and navigate to the first page
             rootFrame = new Frame();
    
             rootFrame.NavigationFailed += OnNavigationFailed;
    
             if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
             {
                 //TODO: Load state from previously suspended application
             }
    
             // Place the frame in the current Window
             Window.Current.Content = rootFrame;
         }
    
         ...
    }
    

    If you use this scenario, you will not need to create the db2.db, you can just use the db1.db in your New Version project.

    right now my latest project uses db2 so can I connect to db1 from this project without calling migrate function? (because migrate function crashes the app.) and then just copy data from db1 to db2.

    The migrate function applies any pending migrations for the context to the database and will create the database if it does not already exist. You need to use the migrate function to create the database if it doesn't exist. Of course, if the db1.db exists, you can connect to db1 to get the data without calling the migrate function.

    To implement it, you can follow the document to create a NewBloggingContext class to inherit DbContext in the Model Library to connect to db1.db and copy the data.