.NET MAUI中EF Core增改表时迁移异常问题求助
.NET MAUI + EF Core SQLite 跨平台迁移解决方案(Windows/Android)
核心问题分析
你遇到的"表未找到"异常,本质是未正确应用EF Core迁移:
EnsureCreated()仅能创建数据库和表,但不会生成/应用迁移记录,后续修改表结构时无法同步更新现有数据库Migrate()需要提前生成迁移文件,而EF Core CLI工具仅在Windows平台支持完整操作,需先在Windows生成迁移再移植到多平台
步骤1:在Windows平台生成迁移文件
所有迁移文件必须先在Windows环境生成,再同步到MAUI项目中:
- 打开Windows PowerShell,进入MAUI项目根目录
- 若未安装EF Core工具,执行:
dotnet tool install --global dotnet-ef - 生成初始迁移(对应现有数据库结构):
dotnet ef migrations add InitialCreate --project YourMauiProjectName - 后续修改表结构(新增/重命名表)后,生成新迁移:
dotnet ef migrations add AddNewTable_Or_RenameTable - 确认项目中生成的
Migrations文件夹及所有迁移文件已被包含在MAUI项目中(默认会自动包含,可检查.csproj文件确认)
步骤2:修正DbContext配置(避免映射错误)
你的DbContext中存在大小写不一致的DbSet命名(如itemComboResponses),EF Core默认会映射到同名小写表,容易引发"表未找到"问题,建议统一为PascalCase并添加Fluent API明确映射:
namespace bluelotus360.Com.MauiSupports.LocalDB { public class LocalDatabaseContext : DbContext { // 统一DbSet命名为PascalCase,与实体类保持一致 public DbSet<IncomingStrings> IncomingStrings { get; set; } public DbSet<ItemComboResponses> ItemComboResponses { get; set; } public DbSet<RequestQueueItem> RequestQueueItems { get; set; } public DbSet<StockAsAt> StockAsAts { get; set; } public DbSet<AddressMasterModel> AddressMasterModels { get; set; } public DbSet<ItemMasterModel> ItemMasterModels { get; set; } public DbSet<UserMessageObject> UserMessageObjects { get; set; } public DbSet<PrintQueueItem> PrintQueueItems { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { string connectionDb = $"Filename={DBPath.GetPath("erp_dbase_v1.db")}"; optionsBuilder.UseSqlite(connectionDb); } } // 用Fluent API明确表名映射,避免EF默认规则冲突 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<ItemComboResponses>().ToTable("ItemComboResponses"); modelBuilder.Entity<PrintQueueItem>().ToTable("PrintQueueItems"); // 其他实体可按需添加 } } }
步骤3:正确执行迁移的启动代码
替换原有的EnsureCreated()/直接new DbContext的代码,改用依赖注入执行迁移,确保跨平台兼容性:
// 注册DbContext,统一配置连接字符串 builder.Services.AddDbContext<LocalDatabaseContext>(options => { string connectionDb = $"Filename={DBPath.GetPath("erp_dbase_v1.db")}"; options.UseSqlite(connectionDb); }); // 创建服务作用域,执行迁移 using var scope = builder.Services.BuildServiceProvider().CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<LocalDatabaseContext>(); try { // Migrate()会自动创建数据库(若不存在)并应用所有未执行的迁移 dbContext.Database.Migrate(); } catch (Exception ex) { // 开发环境可添加日志或调试输出 System.Diagnostics.Debug.WriteLine($"迁移执行失败:{ex.Message}"); // 极端情况(如旧数据库损坏)可删除重建(仅开发环境使用) // dbContext.Database.EnsureDeleted(); // dbContext.Database.EnsureCreated(); }
步骤4:Android平台特殊配置
- 数据库路径验证:确保
DBPath.GetPath()返回Android私有存储路径,示例实现:public static class DBPath { public static string GetPath(string dbName) { return DeviceInfo.Platform switch { DevicePlatform.Android => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), dbName), DevicePlatform.WinUI => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), dbName), _ => throw new NotSupportedException("当前平台未支持") }; } } - 清除旧数据:测试Android时,建议卸载旧应用再安装,避免残留的旧数据库文件导致迁移冲突
额外排查点(解决"表未找到")
- 重命名表需手动修改迁移文件:EF Core不会自动生成重命名表的代码,需手动修改迁移文件的
Up()/Down()方法:protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.RenameTable( name: "OldTableName", newName: "NewTableName"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.RenameTable( name: "NewTableName", newName: "OldTableName"); } - 禁止混合使用EnsureCreated()和Migrate():
EnsureCreated()会跳过迁移表__EFMigrationsHistory的创建,导致后续Migrate()无法识别数据库版本,引发结构不匹配
内容的提问来源于stack exchange,提问作者Gayantha
相关产品推荐
相关产品推荐

