SQL Server Decimal(30,18)字段EF更新值异常问题求助
我之前碰到过一模一样的问题,这个坑其实是Entity Framework模型里的decimal字段精度配置和数据库实际字段不匹配导致的——虽然你数据库里明确设了Decimal(30,18),但EF默认生成的实体模型会用更小的精度(比如默认是18位总长度、2位小数),当你更新数值时,EF在做类型转换时就会误判数值超出范围,抛出你看到的异常。
下面是一步步的解决办法:
1. 修正EF实体模型的字段精度配置
你需要明确告诉EF这个字段的精度和小数位数,有两种方式:
方式一:用数据注解直接标注实体属性
在你的Category实体类里,给Instrument_Entry_Cost加上[Column]注解:
public class Category { // 其他属性省略... [Column(TypeName = "decimal(30, 18)")] public decimal Instrument_Entry_Cost { get; set; } }
方式二:用Fluent API在DbContext里配置
如果你习惯用Fluent API而非注解,就在DbContext的OnModelCreating方法里添加配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Category>() .Property(c => c.Instrument_Entry_Cost) .HasPrecision(30, 18); }
2. 同步EF元数据和数据库(Code First模式)
如果你的项目用的是Code First,修改完模型后必须重新生成迁移脚本并更新数据库,否则EF的元数据还是旧的:
# 在Package Manager Console里执行 Add-Migration FixDecimalPrecisionForInstrumentCost Update-Database
这一步是让EF的内部映射规则和数据库的实际字段配置完全对齐。
3. 排除AutoMapper的潜在干扰
虽然你说手动赋值也报错,但还是可以临时注释掉AutoMapper的相关代码,只用纯手动赋值的逻辑测试一遍——确保不是映射过程中把数值精度给截断或者转成了其他类型。
4. 验证EF实体状态(可选排查步骤)
如果还是有问题,可以在SaveChanges()前打印实体的状态和字段值,确认EF拿到的数值是正确的:
var targetCategory = Product.Categories.FirstOrDefault(); targetCategory.Instrument_Entry_Cost = 3.4M; // 打印实体状态和当前值,排查是否有异常 var entry = DbContext.Entry(targetCategory); Console.WriteLine($"实体状态:{entry.State}"); Console.WriteLine($"当前字段值:{entry.Property(c => c.Instrument_Entry_Cost).CurrentValue}"); DbContext.SaveChanges();
为什么手动改SQL没问题?
因为SQL Server本身的Decimal(30,18)完全支持这些数值,问题出在EF和数据库的中间映射层——EF默认的decimal精度配置比数据库的小,导致它在把.NET的decimal类型转换为数据库字段时,错误地认为数值超出了自己预设的范围,从而抛出异常。
内容的提问来源于stack exchange,提问作者DKar

