Данный текст является логичным продолжением статьи 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<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);
    }
});
...

}

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


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

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


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

Комментарии (0)