来自Microsoft Store的 WinUI 3 MSIX应用无法创建SQLite数据表,但在调试或本地构建时可以正常工作
我有一个WinUI 3 / .NET 8应用打包为MSIX,并通过Microsoft Store发布。
该应用使用EF Core 8与 SQLite。启动时我通过迁移初始化数据库:
using var db = Services
.GetRequiredService<IDbContextFactory<AppDbContext>>()
.CreateDbContext();
DatabaseMigrationService.Migrate(db);
本地从Visual Studio / Debug运行时应用工作正常。然而,在安装了Microsoft Store版本后,一些页面保持空白或加载数据失败。在1.1.0.0版本中,任务页面卡在加载指示器上。加入try/finally包围加载逻辑后,加载指示器消失,但数据库似乎仍然缺少表,添加新任务也失败。
应用把错误写入 errors.log。从商店安装的版本我得到:
[2026-05-31 16:38:35] Unhandled: SQLite Error 1: 'no such table: pomodoro_table'.
[2026-05-31 16:38:35] Unhandled: SQLite Error 1: 'no such table: pomodoro_table'.
[2026-05-31 16:38:35] Unhandled: SQLite Error 1: 'no such table: task_table'.
在之后的商店更新之后:
[2026-05-31 23:53:46] Unhandled: SQLite Error 1: 'no such table: pomodoro_table'.
[2026-05-31 23:53:46] Unhandled: SQLite Error 1: 'no such table: pomodoro_table'.
[2026-05-31 23:53:49] Unhandled: An error occurred while saving the entity changes. See the inner exception for details.
我的项目文件在非调试构建中开启了修剪:
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
我怀疑Microsoft Store / Release MSIX构建的行为有所不同,因为 PublishTrimmed=True,并且EF Core的迁移可能并非完全对修剪安全。
在最新尝试修复之前相关的迁移启动代码:
public static void Migrate(AppDbContext db)
{
var connection = db.Database.GetDbConnection();
db.Database.OpenConnection();
try
{
if (TableExists(connection, "task_table"))
{
EnsureHistoryTable(connection);
EnsureLegacySchema(connection);
EnsureBaselineHistory(connection);
if (ColumnExists(connection, "pomodoro_table", "pomodoro_review"))
EnsureMigrationHistory(connection, PomodoroReviewMigrationId);
}
db.Database.Migrate();
}
finally
{
db.Database.CloseConnection();
}
}
问题在于从商店安装后,看起来 db.Database.Migrate() 要么失败,要么在没有创建预期表的情况下完成。应用随后继续运行,后续查询因为没有这样的表而失败。
问题
PublishTrimmed=True是否会破坏WinUI 3的 MSIX应用中EF Core SQLite的迁移?- EF Core的修剪是否应在商店/发布构建中禁用?
- 在打包的WinUI 3应用中,是否有推荐的初始化或修复EF Core SQLite数据库的方法?
- 我应该使用
Database.Migrate()、EnsureCreated(),还是为此类打包应用使用手动架构回退?
我考虑把项目改为:
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">False</PublishTrimmed>
并添加一个迁移后架构验证/回退,当 Migrate() 不存在时创建缺失的表。
这是正确的做法吗,还是有更适合商店安全的方式来处理WinUI 3中的EF Core SQLite迁移?
解决方案
我找到了并解决了这个问题(感谢在我的问题下的有益评论)。
SQLite文件在应用的LocalState文件夹中已正确创建,因此这不是文件路径或权限问题。
当我检查由Microsoft Store版本创建的损坏数据库时,数据库文件是有效的:
PRAGMA quick_check = ok
但架构不完整。里面唯一的表是:
__EFMigrationsHistory
并且没有任何行。应用程序表丢失:
task_table
pomodoro_table
note_table
todo_table
原因在于我的Release/MSIX发布配置。 我开启了修剪:
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
这与EF Core 8的运行时迁移是一个糟糕的组合。EF Core在运行时元数据/反射方面高度依赖,修剪可能会移除运行时需要的内容。我的调试/本地构建之所以能工作,是因为它们使用的商店包并未进行同样的修剪。
修复方法是:
1.为 Store/Release包禁用修剪:
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">False</PublishTrimmed>
2.在启动迁移后添加一个防御性架构验证步骤:
我在启动迁移后添加了一个防御性的架构验证/修复步骤。之前应用程序基本上信任EF的迁移。现在,在打开数据库并运行迁移后,应用会显式地验证所需表是否存在,如缺失则创建/修复架构。
概念上:
using var db = dbContextFactory.CreateDbContext();
try
{
db.Database.Migrate();
// New: do not trust that Migrate() actually produced a complete schema.
EnsureCurrentSchema(db.Database.GetDbConnection());
}
catch
{
// New: if migration fails, still try to create/repair the required SQLite schema.
EnsureCurrentSchema(db.Database.GetDbConnection());
throw;
}
EnsureCurrentSchema会检查/创建所需的SQLite表,如task_table、pomodoro_table、note_table和 todo_table,并确保迁移历史基线存在。
这很重要,因为损坏的Store版本已经创建了一个仅包含 __EFMigrationsHistory而没有应用程序表的有效SQLite文件。普通的全新数据库检查并不足以解决问题;应用还必须处理“数据库文件存在但架构不完整”的情况。
将此修复作为1.1.2版本发布后,我测试了两种情况:
- 更新损坏的Microsoft Store版本。
- 从Microsoft Store卸载并重新安装。
两种情况现在都能正确工作。应用会创建数据库架构,任务页面不再卡住或因以下错误失败:
SQLite Error 1: 'no such table: pomodoro_table'
SQLite Error 1: 'no such table: task_table'
因此最后的教训是:如果你在WinUI 3/MSIX Store应用中使用EF Core的运行时迁移,请对PublishTrimmed非常小心。同时记录并验证实际的SQLite数据库路径和架构,而不仅仅是.db文件是否存在。