采用数据库优先方式时,EF Core中时态表的实现问题咨询
数据库优先模式下EF使用时态表的解决方案
针对你提到的两个疑问,给出具体解决办法:
问题1:仅在OnModelCreating中指定时态表,如何同步物理数据库变更?
数据库优先模式下,EF不会像代码优先那样自动通过迁移生成时态表结构,需要先手动完成数据库端的配置,再在代码中映射:
- 手动在SQL Server中将目标表改为时态表:
- 给表添加
SysStartTime(datetime2类型,默认值sysutcdatetime())和SysEndTime(datetime2类型,默认值'9999-12-31 23:59:59.9999999')两个字段; - 启用系统版本控制,可让SQL自动创建历史表,示例SQL脚本:
ALTER TABLE Customers ADD PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime); ALTER TABLE Customers SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.CustomersHistory));
- 给表添加
- 完成数据库配置后,在
OnModelCreating中添加时态表映射,确保EF能识别并使用时态表功能。 - 若需要批量同步结构,推荐使用SQL Server Data Tools(SSDT)管理数据库项目,通过发布功能同步结构变更,比手动脚本更可控。
问题2:OnModelCreating的修改在重新搭建数据库时被覆盖怎么办?
自动生成的DbContext文件在重新执行Scaffold-DbContext时会被完全覆盖,不能直接在自动生成的OnModelCreating里写配置,推荐两种方案:
方案1:使用分部类扩展DbContext
自动生成的DbContext默认是分部类,新建一个独立的分部类文件(比如MyDbContext.TemporalConfig.cs),在里面实现自动生成的DbContext中声明的OnModelCreatingPartial方法:
public partial class MyDbContext : DbContext { partial void OnModelCreatingPartial(ModelBuilder modelBuilder) { modelBuilder.Entity<Customer>().ToTable("Customers", b => b.IsTemporal()); modelBuilder.Entity<Product>().ToTable("Products", b => b.IsTemporal()); modelBuilder.Entity<Order>().ToTable("Orders", b => b.IsTemporal()); } }
重新Scaffold时只会覆盖自动生成的DbContext文件,这个分部类里的配置不会受影响。
方案2:使用实体配置类
创建单独的实体配置类实现IEntityTypeConfiguration<T>接口,把时态表配置封装进去:
public class CustomerConfiguration : IEntityTypeConfiguration<Customer> { public void Configure(EntityTypeBuilder<Customer> builder) { builder.ToTable("Customers", b => b.IsTemporal()); } } // 同理创建ProductConfiguration、OrderConfiguration
然后在分部类的OnModelCreatingPartial中批量应用配置:
partial void OnModelCreatingPartial(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(System.Reflection.Assembly.GetExecutingAssembly()); }
这种方式更模块化,后续新增实体的时态配置也只需添加新的配置类,同样不会被Scaffold操作覆盖。
内容的提问来源于stack exchange,提问作者Danie Spreeth
相关产品推荐
相关产品推荐

