.NET 8 RC2中如何将脚手架生成的DbContext扩展为IdentityDbContext
核心思路
由于C#不支持多重继承,我们需要让自定义DbContext直接继承IdentityDbContext<AppUser>,同时将脚手架生成的AutoGeneratedDbContext中的实体集合和模型配置迁移过来,最终实现单DbContext同时包含业务实体与Identity认证实体。
步骤1:重构CustomDbContext继承关系
让CustomDbContext直接继承IdentityDbContext<AppUser>,并复制脚手架生成的AutoGeneratedDbContext中的所有DbSet属性:
public class CustomDbContext : IdentityDbContext<AppUser> { // 复制AutoGeneratedDbContext中所有业务实体的DbSet public DbSet<Product> Products { get; set; } public DbSet<Order> Orders { get; set; } // ... 其他脚手架生成的实体集合 public CustomDbContext() { } public CustomDbContext(DbContextOptions<CustomDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 先执行Identity的默认模型配置 base.OnModelCreating(modelBuilder); // 再执行脚手架生成的业务实体模型配置 AutoGeneratedDbContextModelConfig.Configure(modelBuilder); } }
步骤2:提取脚手架生成的模型配置
为了避免后续重新执行dotnet ef dbcontext scaffold时覆盖配置,将AutoGeneratedDbContext中OnModelCreating方法内的所有配置代码提取到一个独立的静态类中:
public static class AutoGeneratedDbContextModelConfig { public static void Configure(ModelBuilder modelBuilder) { // 复制AutoGeneratedDbContext中OnModelCreating内的所有配置代码 modelBuilder.Entity<Product>(entity => { entity.HasKey(e => e.Id); entity.Property(e => e.Name).IsRequired().HasMaxLength(100); // ... 其他实体配置 }); modelBuilder.Entity<Order>(entity => { entity.HasOne(o => o.Product).WithMany(p => p.Orders).HasForeignKey(o => o.ProductId); // ... 其他实体配置 }); // ... 剩余业务实体的配置 } }
可选优化:如果允许修改脚手架生成的AutoGeneratedDbContext,可以将其改为partial类并添加静态配置方法,后续重新scaffold时只需保留该方法:
public partial class AutoGeneratedDbContext : DbContext { // 脚手架生成的原有代码... public static void ConfigureModel(ModelBuilder modelBuilder) { // 原有OnModelCreating内的配置代码 } protected override void OnModelCreating(ModelBuilder modelBuilder) { ConfigureModel(modelBuilder); } }
此时CustomDbContext的OnModelCreating只需调用AutoGeneratedDbContext.ConfigureModel(modelBuilder);即可。
步骤3:注册单DbContext与Identity服务
在Program.cs中仅注册CustomDbContext,并让Identity使用该上下文作为存储:
// 注册CustomDbContext builder.Services.AddDbContext<CustomDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnectionString"))); // 配置Identity,指定使用CustomDbContext builder.Services.AddIdentityCore<AppUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<CustomDbContext>() .AddSignInManager() .AddDefaultTokenProviders();
步骤4:处理后续脚手架更新
后续需要重新生成实体时,执行以下命令避免覆盖自定义代码:
dotnet ef dbcontext scaffold "YourConnectionString" Microsoft.EntityFrameworkCore.SqlServer --context AutoGeneratedDbContext --context-dir ScaffoldContexts --output-dir Entities
--context AutoGeneratedDbContext:指定生成的上下文名称,避免与CustomDbContext冲突--context-dir:指定上下文生成目录,隔离自定义代码--output-dir:指定实体类生成目录
生成后,只需更新AutoGeneratedDbContextModelConfig中的配置代码(或更新partial类的ConfigureModel方法)即可。
内容的提问来源于stack exchange,提问作者Alisbha Khan

