ASP.NET MVC执行Update-Database时,decimal类型小数插入验证失败
你猜的完全没错——这个问题确实和土耳其的区域设置直接相关!我来帮你拆解原因和解决办法:
问题根源
你的Price是decimal类型,但[RegularExpression]验证属性在执行时,会先把数值转换为字符串。由于你的系统使用土耳其区域(tr-TR),小数点的分隔符是逗号而非点号,所以4.99m会被转换成字符串"4,99"。而你写的正则表达式^[0-9]+(\.[0-9][0-9])?$只接受点号作为小数点分隔符,自然就触发了验证失败。
更关键的是:用正则表达式验证数值类型的格式本身就是个坑——数值类型的字符串表示会随区域文化变化,很容易出现这类跨区域问题。
推荐解决办法
方法1:移除正则验证,改用数据库层面的精度控制(最推荐)
既然Price是decimal类型,完全可以通过Entity Framework的Fluent API在数据库层面强制小数位数,彻底避开字符串转换的问题:
在你的DbContext的OnModelCreating方法中添加:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 设置Price字段总位数10,小数位2 modelBuilder.Entity<Product>() .Property(p => p.Price) .HasPrecision(10, 2); // 其他模型配置... }
然后移除Price属性上的[RegularExpression]特性,这样既保证了数据的精度,又避免了区域文化带来的验证问题。
方法2:自定义验证属性,强制使用不变文化
如果你一定要保留正则验证的逻辑,可以自定义一个验证属性,在转换数值为字符串时使用不变文化(InvariantCulture),确保始终用点号作为小数点:
首先创建自定义属性:
using System.Globalization; using System.Web.Mvc; public class TwoDecimalPlacesAttribute : RegularExpressionAttribute { public TwoDecimalPlacesAttribute() : base(@"^[0-9]+(\.[0-9]{2})?$") { ErrorMessage = "The price must be a number up to two decimal places"; } public override bool IsValid(object value) { if (value == null) return true; // 强制用不变文化转换为字符串,避免区域影响 string valueStr = Convert.ToString(value, CultureInfo.InvariantCulture); return base.IsValid(valueStr); } }
然后替换Price上的[RegularExpression]为这个自定义属性:
[Required(ErrorMessage = "The price cannot be blank.")] [Range(0.10, 10000, ErrorMessage = "Please enter a price between 0.10 and 10000.00")] [DataType(DataType.Currency)] [DisplayFormat(DataFormatString = "{0:c}")] [TwoDecimalPlaces] // 替换成自定义属性 public decimal Price { get; set; }
方法3:临时修改Seed方法的线程文化(仅临时解决Seed问题)
如果只是想快速解决Seed时的问题,可以在Seed方法开头临时切换线程文化:
protected override void Seed(BabyStore.Models.BabyStoreContext context) { // 临时设置为不变文化 System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; // 你的Seed数据插入逻辑... }
不过这个方法只解决Seed阶段的问题,网站前台用户输入价格时还是会遇到同样的验证问题,所以仅作为临时方案。
额外提示
以后尽量避免用[RegularExpression]验证数值类型——数值的格式应该通过区域化显示来处理,而不是用正则约束。数据库层面的精度控制或自定义验证属性是更可靠的方案。
内容的提问来源于stack exchange,提问作者Furkan Yurdakul

