ExecuteScalar 返回 null 并不表示插入失败,而是SQL未返回值或返回非标量结果;正确写法需用INSERT+SELECT SCOPE_IDENTITY()单语句,且须处理DBNull.Value及类型转换。
ExecuteScalar 返回 null 是不是没插进去?
不是。只要 sql 语句执行成功,
就会返回结果——哪怕你写的是
但没加
,它就真返回
(或
)。
c#
不会自动“猜”你要 id,必须显式要求。
常见错误现象:
返回
或抛出
,实际数据已写入数据库
根本原因:SQL 语句没返回值,或者返回了非标量结果(比如忘了用
,只写了
)
正确写法必须是单语句、单列、单行,例如:
比
安全,它只取当前作用域的最后自增 ID,不会被触发器干扰
为什么用 ExecuteScalar 而不是 ExecuteNonQuery + SELECT?
因为要避免两次往返数据库,也防止并发时 ID 被其他连接抢走。一次执行、原子获取,是最小安全窗口的做法。
只返回影响行数(-1 表示不可用),完全不提供 ID
如果拆成两步:
插入 → 再查
,在高并发下大概率拿错 ID(别人刚插了一条)
SQL Server 支持语句拼接,但注意:不能用分号隔开两条独立语句再传给
(会报错),必须让第二句是第一句的延续结果
PostgreSQL 用户请改用
(如:
)
类型转换失败:int.Parse(ExecuteScalar()) 报错
返回的是
,可能为
或
,直接强转或
必崩。
错误现象:
或
安全写法:先判断是否为
,再用
(它能处理
和
)
更推荐:用可空类型接收,例如
,然后判空
别用
—— 这种强制解包对
直接炸
异步场景下该用 ExecuteScalarAsync 还是 QuerySingleAsync?
如果你用的是原生 ADO.NET,就用
;如果用了 Dapper,优先用
,语义更清晰、异常更明确。
C知道
CSDN推出的一款AI技术问答工具
下载
仍返回
,类型检查和转换逻辑得自己写
Dapper 的
会自动做类型验证,ID 为空时直接抛
注意:Dapper 默认不支持多语句(除非开启
),SQL Server 需确保连接字符串含
才稳
EF Core 用户请直接用
后读取实体的 ID 属性,不用手动调
事情说清了就结束。最常漏掉的是
判定和多语句执行时的连接配置,这两处一错,ID 就永远拿不到。
executescalarinsert into ...select scope_identity()nulldbnull.valueExecuteScalar()nullInvalidCastExceptionSELECTINSERTINSERT INTO Users (Name) VALUES (@name); SELECT SCOPE_IDENTITY();SCOPE_IDENTITY()@@IDENTITYExecuteNonQueryExecuteNonQueryMAX(Id)ExecuteScalarRETURNING idINSERT INTO users (name) VALUES (@name) RETURNING idExecuteScalar()objectnullDBNull.Valueint.ParseSystem.InvalidCastExceptionSystem.ArgumentNullExceptionDBNull.ValueConvert.ToInt32()nullDBNullvar id = cmd.ExecuteScalar() as int?;(int)cmd.ExecuteScalar()DBNullExecuteScalarAsyncQuerySingleAsyncExecuteScalarAsyncobjectQuerySingleAsync("INSERT ...; SELECT SCOPE_IDENTITY();") NoRowsAffectedExceptionCommandBehavior.SequentialAccessMultipleActiveResultSets=TrueSaveChanges()ExecuteScalarDBNull.Value