Данный текст является логичным продолжением статьи 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
Надеюсь, этот материал был вам полезен, увидимся на берегах МАУИ!