更新实体模型后LINQ Where触发smallint算术溢出错误,求排查解决
解决Arithmetic overflow error for data type smallint的问题
问题根源分析
你遇到的核心问题是EF实体模型与数据库的类型映射不同步——虽然你把实体类里的GameTeamKey改成了int,但EF执行查询时仍在按照smallint类型处理数据库返回的结果,而数据库里的实际值早已超过smallint的上限(32767),最终触发了算术溢出。
具体可能的诱因有这几个:
- 数据库字段未真正修改:你更新实体模型时,可能只改了代码层面的类型,但数据库里
GameTeamPlayers表的GameTeamKey字段依然是smallint。 - EF映射元数据未同步:如果用EDMX设计器,存储模型(Storage Model)里对应的字段类型可能还是
smallint,EF仍按旧类型解析数据;如果是Code First,可能迁移脚本未正确执行,或者数据注解/Fluent API的类型配置没跟上。 - EF缓存残留:EF会缓存查询计划和模型元数据,即便你修改了实体类型,旧缓存可能还在生效,导致查询时类型不匹配。
分步解决方法
1. 先确认数据库字段的真实类型
这是最关键的第一步:
打开SSMS,找到GameTeamPlayers表,查看GameTeamKey字段的数据类型,确认它已经改为int。如果还是smallint,先执行ALTER语句修改:
ALTER TABLE GameTeamPlayers ALTER COLUMN GameTeamKey INT NOT NULL; -- 若字段允许为NULL,去掉NOT NULL
2. 同步EF实体模型的映射
- 如果使用EDMX:
右键EDMX文件 → 选择"Update Model from Database",重新从数据库导入表结构,确保存储模型和概念模型的GameTeamKey都是int类型。也可以手动打开EDMX的XML视图,找到对应字段的Type属性,改成int。 - 如果使用Code First:
检查实体类的GameTeamKey属性:
同时确认数据注解或Fluent API配置:public int? GameTeamKey { get; set; } // 确保是int/int?类型
重新生成迁移脚本并执行,确保数据库与模型完全同步。[Column(TypeName = "int")] public int? GameTeamKey { get; set; } // 或者用Fluent API modelBuilder.Entity<GameTeamPlayer>() .Property(p => p.GameTeamKey) .HasColumnType("int");
3. 清除EF的缓存
- 重启你的应用程序,清除应用层面的缓存;
- 如果是生产环境,可在查询前执行SQL命令清除查询计划缓存(谨慎使用,会影响全局查询性能):
db.Database.ExecuteSqlCommand("DBCC FREEPROCCACHE");
4. 验证查询的类型一致性
确认gameTeamKeys的类型确实是List<int>:
// 加一行调试代码确认类型 Console.WriteLine(gameTeamKeys.GetType().GetGenericArguments()[0].Name);
如果这里显示Int16(即smallint对应的.NET类型),说明gameTeams的数据源可能还是旧实体模型,需要同步gameTeams对应的实体类型。
临时应急方案(不推荐长期使用)
如果需要快速恢复运行,可以在查询里显式强制转换类型,规避EF的类型不匹配:
var foundGameTeamPlayers = db.GameTeamPlayers.AsNoTracking() .Where(i => i.IsActive == 1 && i.IsDeleted == 0 && gameTeamKeys.Contains(Convert.ToInt32(i.GameTeamKey.Value))) .ToList();
但这只是治标,一定要解决根源的映射问题。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

