EF Core值转换器解决C#类型(如TimeOnly、枚举、JSON、自定义结构体)与数据库列不兼容问题,通过双向无副作用转换实现映射;例如将TimeOnly转TimeSpan存入time列,或Money转decimal存Amount。
EF Core值转换器能解决什么问题
当你的C#模型里有TimeOnly、DateOnly、枚举类、JSON对象(如Dictionary)、或自定义结构体(如Money)时,EF Core默认不支持直接映射到数据库列。值转换器(ValueConverter)就是用来在读写时自动做类型转换的——比如把TimeOnly转成TimeSpan存进time列,或把Money序列化为decimal或nvarchar。
如何注册一个基础的值转换器(以TimeOnly为例)
EF Core 6+原生支持TimeOnly和DateOnly,但如果你用的是老版本,或想自定义行为(比如统一转为datetime2列并忽略日期部分),就得手动配转换器。关键点是:转换必须双向、无副作用、线程安全。
常见做法是在OnModelCreating中为特定属性配置:
modelBuilder.Entity()
.Property(e => e.ShipTime)
.HasConversion(
timeOnly => timeOnly.ToTimeSpan(), // 写入时:TimeOnly → TimeSpan
timeSpan => TimeOnly.FromTimeSpan(timeSpan) // 读取时:TimeSpan → TimeOnly
);
注意:ToTimeSpan()会丢失毫秒精度(TimeOnly支持微秒,TimeSpan在SQL Server time列中只保留到100纳秒)。如果精度敏感,建议用string或long(ticks)做中间类型。
自定义结构体(如Money)怎么映射
假设你有不可变结构体Money,含Amount(decimal)和Currency(string),但只想存Amount到数据库一列(如Price),忽略货币单位:
- 必须提供无参构造函数或确保EF Core能实例化(否则读取失败)
- 转换逻辑不能依赖外部状态(比如不能调用
DateTime.Now) - 推荐用
ValueConverter,而非string,避免解析开销
示例: