Entity Framework c предустановленной БД в вашем приложении на .NET MAUI

ehduwt8sacqdcqa4wbbytf_1vkw.jpeg

Данный текст является логичным продолжением статьи Entity Framework c Code-First миграциями для .NET MAUI. В ней рассказывалось как подключить и использовать, возможно, уже привычную вам по работе с апи технологию работы с БД Entity Framework теперь в вашем мобильном приложении.

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

Итак, допустим, в процессе разработки мы заполнили БД нужными вам значениями и теперь вы хотите чтобы они были доступны всем пользователям. Покажем на примере.

Кладем ваш файл базы данных в Resources/Raw/Db/app.db3 — Build Action: MauiAsset. Замечательно, файл уже с нами.

Теперь, чтобы его реально использовать при исполнении приложения, надо переложить файл из ресурсов в папку уже развернутого после установки приложения.

Регистрируем наш контекст таким образом (MauiProgram.cs):

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

public static MauiApp CreateMauiApp(){

...
services.AddTransient((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);
    }
});
...

}

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

Напоследок, напомним, кто-такая была 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

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

 /// 
 /// Constructor for mobile app
 /// 
 /// 
 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 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();
 }
}

Не забудьте ознакомиться с предыдущей статьей: Entity Framework c Code-First миграциями для .NET MAUI

Надеюсь, этот материал был вам полезен, увидимся на берегах МАУИ!

© Habrahabr.ru