我正在创建一个 .NET MAUI Android 应用程序,它使用内置的本地 SQLite 数据库文件、CommunityMVVMToolKit 只是因为它很棒,而 EntityFramework Core 用于将对象映射到数据库记录,反之亦然。
我是这个框架的新手,并且不确定应该如何处理数据库文件,我决定将一个包含所有表模式的新数据库放在
Resources/Raw
文件夹中,并且没有记录作为原始资源。启动后,应用程序会检查数据库文件应存在的预定位置,如果不存在,则会在所述位置创建新数据库文件的副本。原因是(据我在互联网上找到的)与应用程序捆绑的资产是只读的,包括数据库文件,因此必须将它们提取出来才能修改。
应用程序与文件通信良好,其中的数据在应用程序启动之间保留下来,但在尝试实现重置功能时遇到了一个小问题。
我编写了下面的代码片段用于测试目的,看看
DatabaseFile
方法是否正常工作:
[RelayCommand]
void PerformDatabaseFileTests()
{
ClearText();
try
{
//After starting the app the DB should already be there, check for it
AppendText($"DATABASE FILE EXISTS: {DatabaseFile.Exists()}");
//Delete it and check if it deleted
AppendText("DELETING DB FILE...");
DatabaseFile.Delete();
AppendText($"DATABASE FILE EXISTS: {DatabaseFile.Exists()}");
//Create it again
AppendText("CREATING DB FILE...");
MainThread.InvokeOnMainThreadAsync(DatabaseFile.Create);
AppendText($"DATABASE FILE EXISTS: {DatabaseFile.Exists()}");
}
catch (Exception ex)
{
AppendText("EXCEPTION WAS THROWN!");
AppendText(ex.ToString());
AppendText(ex.Message);
}
}
调试页面视图模型中包含的此方法执行以下操作:
检查该位置是否存在数据库文件
尝试删除DB文件并检查是否存在
创建一个新副本并检查它是否存在
言归正传,问题是当我修改数据库中的记录(添加、更新、删除)时,执行上述DB文件测试方法并尝试读取数据库文件的内容,修改仍然存在。在一个应该被删除并从新模板文件重建的文件中。
底层
File.Exists()
方法确实报告数据库文件在删除之前存在,删除后不存在,创建后又存在。
另外,值得一提的是,执行数据库文件测试方法,关闭应用程序然后重新打开而不查询任何数据,似乎可以正确重置数据库文件。虽然此解决方法确实有效,但我真的希望无需重新启动应用程序即可完成重置。
以下是DatabaseFile类的内容:
public static class DatabaseFile
{
public static string FullPath =>
Path.Combine(FileSystem.Current.AppDataDirectory, Filename);
public static async Task Create()
{
using Stream inputStream = await FileSystem.Current.OpenAppPackageFileAsync(Filename);
using FileStream outputStream = File.Create(FullPath);
await inputStream.CopyToAsync(outputStream);
}
public static void Delete()
{
if (Exists())
File.Delete(FullPath);
}
public static bool Exists() =>
File.Exists(FullPath);
}
也许数据库文件根本不应该像任何其他 MauiAsset 一样处理。有没有更好的方法来发布带有内置本地数据库的 Android 应用程序?
编辑: 每次创建新的 DbContext 实例时,都会建立与我的数据库文件的连接。以下是我的 DatabaseContext 类中的
OnConfiguring()
方法的内容,该方法派生了 DbContext:
public partial class DatabaseContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
SqliteConnectionStringBuilder builder = new SqliteConnectionStringBuilder()
{
DataSource = Path.Combine(FileSystem.Current.AppDataDirectory, DatabaseFile.Filename),
Mode = SqliteOpenMode.ReadWriteCreate,
ForeignKeys = true
};
optionsBuilder.UseSqlite(builder.ToString());
}
}
我是否错误地假设在释放 DbContext 实例时连接会自动关闭?
我搞砸了,终于找到了解决方案,这就是我所做的:
将
DatabaseFile.Delete
方法更改为以下内容:
公共静态异步任务删除() { 使用 var context = new DatabaseContext(); 等待 context.Database.EnsureDeletedAsync(); }
EnsureDeleted
是我一直在寻找的基本方法。为了确定起见,我还将 DatabaseFile.Delete
方法更改为异步方法并在调用时等待。
执行稍微改变的测试方法后,修改不再保留在新数据库中。该方法唯一的变化是等待
DatabaseFile.Delete
方法:
AppendText("正在删除数据库文件..."); 等待DatabaseFile.Delete(); AppendText($"数据库文件存在:{DatabaseFile.Exists()}");