SqlSugar查询字符串转成Int的问题

业务场景:点击事件触发vm的插入方法,vm的插入方法调用SqlSugar查询方法,查询当前ParamName的Sequence的最大值+1,再执行SqlSugar插入方法。

Sequence实体类字段为String,数据库表字段为varchar(密码的谁tm把有"排序"意义的东西搞成string的,所有值均为"Int "1-N这种)

被恶心了记录一下

错误代码

cs 复制代码
            int maxSequence = _db.Queryable<ConfGuide>()
                .Where(t => t.ParamName == currentParamName)
                .Select(t => t.Sequence)
                .Max(t => SqlFunc.ToInt32(t)) + 1;

查询一个一共只有1行的paramName的Sequence字段,连续点击页面,输出的maxSequence一直为2。

查询一个一共有12行的paramName的Sequence字段,连续点击页面,输出的maxSequence也一直为2。

基本确定是查询语句问题。

分析

cs 复制代码
int maxSequence = _db.Queryable<ConfGuide>()
    .Where(t => t.ParamName == currentParamName) // 筛选条件:匹配当前ParamName
    .Select(t => t.Sequence) // 提取Sequence字段(string类型)
    .Max(t => SqlFunc.ToInt32(t)) + 1; // 对提取的string序列转换为int后取最大值,再加1
  1. 筛选(Where) :从ConfGuide表中筛选出ParamName等于currentParamName的所有记录(例如ParamName=测试的 12 条记录)。
  2. 提取字段(Select) :从筛选结果中仅提取Sequence字段,得到一个字符串类型的序列 (例如["1","2","3",...,"12"])。
  3. 取最大值(Max) :对这个字符串序列中的每个元素,通过SqlFunc.ToInt32(t)转换为 int,再取最大值。
  4. 计算新值(+1) :将最大值加 1,作为新记录的Sequence。
核心问题:转换时机错误,导致按 "字符串规则" 取最大值

这段代码的致命问题是:先提取字符串类型的 Sequence ,再尝试转换为 int 取最大值。

但 SqlSugar 在解析这种查询时,会在数据库层面先对字符串类型的 Sequence 取最大值 (按字符串排序),再执行转换,而非 "先转换为 int 再取最大值"。

  • 字符串排序规则:比较字符的 ASCII 码,例如"12"的第一个字符是'1',"2"的第一个字符是'2',因此"12" < "2"(字符串层面)。
  • 最终结果:数据库中ParamName=测试的Sequence字符串最大值是"2",转换为 int 后是2,加 1 后得到3(但你的实际场景中甚至直接返回2,说明转换逻辑未生效)。

修改代码1:

cs 复制代码
int maxSequence = _db.Queryable<ConfGuide>()
    .Where(t => t.ParamName == currentParamName) // 筛选条件:匹配当前ParamName
    .Max(t => SqlFunc.ToInt32(t.Sequence)); // 关键:直接对每条记录的Sequence先转换为int,再取最大值

可见执行成功

分析:

  1. 筛选(Where) :同第一段,筛选出ParamName=currentParamName的所有记录。
  2. 直接取最大值(Max) :对筛选出的每条记录,先通过SqlFunc.ToInt32(t.Sequence)Sequence(string)转换为 int(例如"12"12"2"2),再对转换后的 int 值取最大值。
解决问题的核心:转换时机提前,按 "数字规则" 取最大值

这段代码的关键是将 "转换为 int" 的操作嵌入到Max方法的表达式中,SqlSugar 会生成正确的 SQL,在数据库层面执行:

  • 先将每条记录的Sequence(string)转换为 int(例如CAST(Sequence AS INT));
  • 再对转换后的 int 值按 "数字规则" 取最大值(例如12112中的最大值)。

最终得到正确的最大 int 值(如12),后续加 1 后即可生成递增的新Sequence(如13)。

两段代码的本质差异

维度 第一段代码(错误) 第二段代码(正确)
转换与取最大值的顺序 先取字符串的最大值,再转换为 int 先将每个字符串转换为 int,再取 int 的最大值
数据库执行逻辑 按字符串排序取最大值(如"2"["1","12",...]的最大值) 按数字排序取最大值(如12[1,2,...,12]的最大值)
适用场景 仅适用于Sequence为字符串且按字符串排序符合预期的场景 适用于Sequence为字符串但存储数字,需按数字排序的场景

总结

业务场景中,Sequence是 "存储数字的字符串",需要按数字规则排序取最大值。第一段代码因 "先取字符串最大值再转换" 导致结果错误;第二段代码通过 "先转换为数字再取最大值",符合业务逻辑,最终解决了Sequence不递增的问题。

修改代码2:

在第一段代码的结构基础上(先Select提取字段,再对结果取最大值),要实现 "先将Sequence转换为 int,再取最大值",核心是Select阶段就完成类型转换 ,确保后续Max操作是针对 "int 类型的序列",而非 "string 类型的序列"。

具体修改(保持第一段代码的链式结构):

csharp

cs 复制代码
int maxSequence = _db.Queryable<ConfGuide>()
    .Where(t => t.ParamName == currentParamName) // 1. 筛选指定ParamName的记录
    .Select(t => SqlFunc.ToInt32(t.Sequence)) // 2. 提取时直接转换为int(关键修改)
    .Max() + 1; // 3. 对转换后的int序列取最大值,再加1

逻辑解析:

  1. 筛选(Where) :和原代码一致,筛选出ParamName匹配的记录(如ParamName=测试的 12 条记录)。
  2. 提取并转换(Select) :原代码的Select(t => t.Sequence)提取的是string类型的Sequence(如"1","2",..."12");修改后通过Select(t => SqlFunc.ToInt32(t.Sequence)),在提取时直接将每条记录的Sequence转换为 int 类型(如"12"12"2"2),此时查询结果变为int 类型的序列[1,2,3,...,12])。
  3. 取最大值(Max) :由于Select后已是 int 序列,直接调用Max()即可得到 int 类型的最大值(如12),加 1 后得到新的Sequence(如13)。

为什么这样能解决问题?

  • 原第一段代码的问题是:Select提取的是 string 序列,Max阶段的转换无法改变 "数据库先按字符串排序取最大值" 的逻辑;
  • 修改后:Select阶段就将序列转换为 int 类型,Max操作直接对 int 序列生效,数据库会按 "数字排序" 取最大值(如121-12中的最大值),符合业务预期。

和第二段代码的区别(仅结构差异):

  • 第二段代码是Where后直接用Max(t => 转换逻辑),属于 "直接对原始实体字段计算最大值";
  • 此修改方案是Where→Select(转换)→Max(),属于 "先转换为目标类型序列,再取最大值",结构上更贴近你最初的代码习惯,但效果完全一致。
相关推荐
ytttr8731 小时前
C#实现海康威视智能车牌识别
开发语言·c#
bubiyoushang8882 小时前
C#开发的TCP/UDP网络调试助手
tcp/ip·udp·c#
PfCoder4 小时前
C# 中的定时器 System.Threading.Timer用法
开发语言·c#
缺点内向4 小时前
Word 自动化处理:如何用 C# 让指定段落“隐身”?
开发语言·c#·自动化·word·.net
KvPiter4 小时前
Clawdbot 中文汉化版 接入微信、飞书
人工智能·c#
曹牧5 小时前
C#:重载窗体构造函数
开发语言·c#
mudtools5 小时前
飞书多应用开发:如何实现企业多应用的“系统集成引擎“
c#·.net·飞书
暮疯不疯1 天前
C#常见术语表格
开发语言·c#
JQLvopkk1 天前
VS2015使用C#连接KepserverEX并操作读写节点
开发语言·c#
流水线上的指令侠1 天前
补充说明——针对《C#:从 0 到 1 创建基于 NUnit + FlaUI 的 WPF UI 自动化测试项目》
功能测试·ui·c#·自动化·wpf