Entity Framework 6 Decimal值保存异常:设为0时存为-1的原因咨询
问题背景
我已解决该问题,但想了解背后的具体原因,寻求专业解释。
定义的实体类如下:
public class Test : Entity<Test> { public decimal DecimalProp { get; private set; } }
对应的EF映射配置:
public class TestConfig : IEntityTypeConfiguration<Test> { public void Configure(EntityTypeBuilder<Test> builder) { builder .ToTable("Tests"); builder .Property(t => t.DecimalProp) .HasDefaultValue(-1) .HasColumnType("decimal(4,1)") .IsRequired(); } }
问题现象
通过EF添加DecimalProp为0的Test实例时,SQL中保存的值为-1;但设置为5等其他数值时,保存结果正常。
解决方法
在映射配置中添加ValueGeneratedNever()后解决了问题,修改后的配置如下:
public class TestConfig : IEntityTypeConfiguration<Test> { public void Configure(EntityTypeBuilder<Test> builder) { builder .ToTable("Tests"); builder .Property(t => t.DecimalProp) .HasColumnType("decimal(4,1)") .ValueGeneratedNever() .HasDefaultValue(-1) .IsRequired(); } }
核心原因解释
EF的默认值判断逻辑
当你给属性配置HasDefaultValue时,EF Core会默认将该属性标记为ValueGenerated.OnAdd类型。这意味着:添加实体时,如果属性值等于对应CLR类型的默认值(decimal的默认值是0),EF会判定你没有显式设置该属性的值,进而在生成SQL时跳过对这个字段的赋值,转而让数据库使用预先定义的默认值-1。
这里的关键是,EF把CLR默认值当成了“未赋值”的信号,而非业务上的有效值。所以当你设置DecimalProp为0时,EF认为这是未显式赋值的状态,就会触发数据库默认值;而设置为5时,因为5不等于decimal的默认值0,EF会将该值写入SQL,数据库也就保存5。
ValueGeneratedNever()的作用
这个配置会强制告诉EF:该属性的值永远不会由数据库生成,无论属性值是否为CLR默认值,只要代码中设置了值(哪怕是0),都要将该值传递给数据库。这就覆盖了EF的默认判断逻辑,让0这个有效值能正常被写入SQL,而不会被替换成数据库默认值。
关于设计合理性的说明
EF的这个默认逻辑是为了适配多数通用场景:很多开发者会用CLR默认值表示“未设置”,依赖数据库默认值填充字段。但如果你的业务场景中,CLR默认值(比如decimal的0)是合法的业务值,就必须显式添加ValueGeneratedNever()来修改EF的行为,避免它误判“未赋值”。
内容的提问来源于stack exchange,提问作者Felipe Alves

