Entity Framework with pre-installed DB in your .NET MAUI application

This text is a logical continuation of the article Entity Framework with Code-First Migrations for .NET MAUI. It told how to connect and use, perhaps, already familiar to you from working with the API technology of working with the Entity Framework DB now in your mobile application.

This article clearly requires a sequel for practical use: when you already have some pre-populated database and need to release it along with the application.

So, let's say that during the development process we filled the DB with the values ​​you need and now you want them to be available to all users. Let's show you an example.

Place your database file in Resources/Raw/Db/app.db3 — Build Action: MauiAsset. Great, the file is already with us.

Now, to actually use it when running the application, you need to move the file from the resources to the folder of the application that has already been deployed after installation.

We register our context like this (MauiProgram.cs):

private static object _lockDb = new(); //не нужны лишние проблемы

public static MauiApp CreateMauiApp(){

...
services.AddTransient<LocalDatabase>((services) =>
{
    lock (_lockDb)
    {
        var filenameDb = Path.Combine(FileSystem.AppDataDirectory, "app.db3");
        if (!File.Exists(filenameDb))
        {
            using var stream = FileSystem.OpenAppPackageFileAsync("ML/app.db3").GetAwaiter().GetResult();
            using (var memoryStream = new MemoryStream())
            {
                stream.CopyTo(memoryStream);
                File.WriteAllBytes(filenameDb, memoryStream.ToArray());
            }
        }
        return new LocalDatabase(filenameDb);
    }
});
...

}

Great, now our pre-populated database is always with us in production. We checked if the db file is deployed in the folder and closed the issue. At the same time, we use a lock to avoid simultaneous attempts to initialize the db from different threads.

Finally, let's remember who she was LocalDatabase:

public class LocalDatabase : DbContext
{
 #region CONSTRUCTOR

 //parameterless constructor must be above the others,
 //as it seems that EF Tools migrator just takes the .First() of them

 /// <summary>
 /// Constructor for creating migrations
 /// </summary>
 public LocalDatabase()
 {
     File = Path.Combine("../", "UsedByMigratorOnly1.db3");
     Initialize();
 }

 /// <summary>
 /// Constructor for mobile app
 /// </summary>
 /// <param name="filenameWithPath"></param>
 public LocalDatabase(string filenameWithPath)
 {
     File = filenameWithPath;
     Initialize();
 }
 void Initialize()
 {
     if (!Initialized)
     {
         Initialized = true;

         SQLitePCL.Batteries_V2.Init();

         //Database.EnsureDeleted(); //use in dev process when needed

         Database.Migrate();
     }
 }
 public static async Task<LocalDatabase> CreateAsync(string filenameWithPath)
 {
     var instance = new LocalDatabase(filenameWithPath);
     await instance.InitializeAsync();
     return instance;
 }
 private async Task InitializeAsync()
 {
     if (!Initialized)
     {
         Initialized = true;

         SQLitePCL.Batteries_V2.Init();

         await Database.MigrateAsync();
     }
 }

 public static string File { get; protected set; }
 public static bool Initialized { get; protected set; }

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
     optionsBuilder
         .UseSqlite($"Filename={File}");
 }

 #endregion

 public void Reload()
 {
     Database.CloseConnection();
     Database.OpenConnection();
 }
}

Don't forget to check out the previous article: Entity Framework with Code-First Migrations for .NET MAUI

I hope this material was useful to you, see you on the shores of MAUI!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *