.NET6中OnModelCreating用HasData报错:无法在模型创建时使用DbContext
问题描述
在.NET6环境下尝试通过EF Core的HasData方法在应用启动前初始化测试数据,重写OnModelCreating方法时出现以下异常:
EntityType '((Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TestApp_40_xUnit_MVC_LibraryApp.Models.Book>)this.Books).EntityType' 引发了System.InvalidOperationException类型的异常,提示“尝试在模型创建过程中使用模型,DbContext实例不能在OnModelCreating中以任何使用正在创建的模型的方式使用”。
应用可正常运行,但测试数据并未插入数据库。相关代码如下:
DbContext代码
public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<Book> Books { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { var _books = new List<Book>() { new Book() { Id = Guid.NewGuid(), Title="Managing Oneself", Description="We live in an age of unprecedented opportunity: with ambition, drive, and talent, you can rise to the top of your chosen profession, regardless of where you started out...", Author= "Peter Drucker" } }; modelBuilder.Entity<Book>().HasData(_books); } }
Program.cs代码
builder.Services.AddDbContext<AppDbContext>(opt => opt.UseInMemoryDatabase("this-is-just-test")); builder.Services.AddTransient<IBookService, BookService>();
Book模型类
public class Book { public Guid Id { get; set; } [Required] public string Author { get; set; } [Required] public string Title { get; set; } public string Description { get; set; } }
问题原因
- 动态Guid触发模型构建冲突:
Guid.NewGuid()在OnModelCreating执行时动态生成,而HasData属于模型配置的一部分,EF Core在模型构建阶段会解析种子数据,动态生成的Guid会导致上下文尝试访问未完全构建的模型,进而抛出异常。 - 内存数据库未自动执行种子数据:内存数据库不会主动应用
HasData中的种子数据,需要显式触发数据库初始化操作才能完成数据插入。
解决方案
1. 替换动态Guid为固定值
HasData要求种子数据的主键是静态确定的值,不能在模型构建阶段动态生成。将Guid.NewGuid()替换为固定的Guid字符串:
修改后的OnModelCreating方法:
protected override void OnModelCreating(ModelBuilder modelBuilder) { var _books = new List<Book>() { new Book() { Id = Guid.Parse("d290f1ee-6c54-4b01-90e6-d701748f0851"), // 固定GUID Title="Managing Oneself", Description="We live in an age of unprecedented opportunity: with ambition, drive, and talent, you can rise to the top of your chosen profession, regardless of where you started out...", Author= "Peter Drucker" } }; modelBuilder.Entity<Book>().HasData(_books); }
2. 显式初始化数据库并应用种子数据
在Program.cs中添加数据库初始化逻辑,通过EnsureCreated()触发内存数据库创建并自动插入种子数据:
修改后的Program.cs:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<AppDbContext>(opt => opt.UseInMemoryDatabase("this-is-just-test")); builder.Services.AddTransient<IBookService, BookService>(); var app = builder.Build(); // 初始化数据库并插入种子数据 using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); dbContext.Database.EnsureCreated(); // 内存数据库会自动执行HasData中的种子数据插入 } // 其他中间件配置(如路由、授权等) // app.UseRouting(); // ... app.Run();
验证效果
启动应用后,内存数据库中会自动插入HasData定义的测试数据,同时模型构建阶段的异常会消失。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

