EF传递double值生成SQL查询出错致SaveChanges失败求助
EF保存double字段失败:逗号小数分隔符导致SQL执行错误
问题描述
填充C#实体类(含double?类型的rate_exchange字段),该字段对应数据库的float类型,调用EF的SaveChanges()时提示返回0条记录。通过SQL Profiler捕获到生成的SQL语句中,double值被格式化为带逗号的小数(如@4=0,0132374518222941),导致SQL Server无法解析参数,执行失败。
实体类代码:
public partial class Rate : IRate { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Column(Order = 0)] public int Id { get; set; } [StringLength(3)] public string source_currency { get; set; } [StringLength(3)] public string target_currency { get; set; } public DateTime? date_l { get; set; } public double? rate_exchange { get; set; } [Key] [Column(Order = 1)] public DateTime CreatedOn { get; set; } }
生成的SQL语句:
exec sp_executesql N'INSERT [dbo].[Rates]([CreatedOn], [source_currency], [target_currency], [date_l], [rate_exchange]) VALUES (@0, @1, @2, @3, @4) SELECT [Id] FROM [dbo].[Rates] WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity() AND [CreatedOn] = @0',N'@0 datetime2(7),@1 varchar(3),@2 varchar(3),@3 datetime2(7),@4 float',@0='2023-02-08 15:58:58.0231618',@1='RUB',@2='EUR',@3='2023-02-01 00:00:00',@4=0,0132374518222941
原因
EF生成SQL参数时,默认使用当前线程的区域设置(Culture)。如果程序运行环境使用逗号作为小数分隔符(如法语、德语等欧洲地区的区域文化),double值就会被格式化为带逗号的字符串。而SQL Server默认以小数点作为小数分隔符,无法解析这种格式的参数,最终导致SQL执行失败,返回0条受影响记录。
解决办法
1. 全局设置程序使用小数点分隔符的区域文化
在程序启动时,强制设置全局区域为使用小数点的文化(例如en-US),确保所有线程格式化数字时统一用小数点:
- .NET Framework:在
Global.asax.cs的Application_Start方法中添加:System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); - .NET Core/.NET 5+:在
Program.cs中添加:var cultureInfo = new System.Globalization.CultureInfo("en-US"); System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cultureInfo; System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
2. 仅针对EF上下文设置区域文化
如果不想全局修改区域,可以在DbContext的构造函数中临时设置当前线程的文化,保证EF生成参数时使用正确格式:
public class YourDbContext : DbContext { public YourDbContext(DbContextOptions<YourDbContext> options) : base(options) { var enUsCulture = new System.Globalization.CultureInfo("en-US"); System.Threading.Thread.CurrentThread.CurrentCulture = enUsCulture; System.Threading.Thread.CurrentThread.CurrentUICulture = enUsCulture; } public DbSet<Rate> Rates { get; set; } }
3. 更换字段类型为Decimal(推荐)
汇率这类对精度要求高的场景,double浮点数容易出现精度丢失问题。可以将C#实体的double?改为decimal?,数据库字段对应decimal类型(例如decimal(18,10)):
修改后的实体类字段:
public decimal? rate_exchange { get; set; }
Decimal类型的格式化逻辑更稳定,受区域设置影响更小,同时能避免浮点数精度误差,更适合金融类数据存储。
内容的提问来源于stack exchange,提问作者Thierry Verhaegen
相关产品推荐
相关产品推荐

