ADO.NET 核心对象 SqlCommand 的常用执行方法详解
SqlCommand 基础与数据修改操作
在基于 SQL Server 的数据访问架构中,SqlCommand 负责封装发送至数据库引擎的执行指令。通过配置 CommandText 属性设定具体 T-SQL 脚本后,调用 ExecuteNonQuery 即可提交非查询类变更(INSERT、UPDATE、DELETE)。该方法执行完毕后,会返回一个整数,表示实际发生变动的记录数量。
以下为标准的插入操作实现,采用了更清晰的变量命名与作用域控制:
string modifyScript = "INSERT INTO SysMembers(MemberName, MemberPwd) VALUES ('demo_user', 'hashed_pass_99');";
using (var executeCmd = connection.CreateCommand())
{
executeCmd.CommandText = modifyScript;
int impactedRows = executeCmd.ExecuteNonQuery();
}
单值查询与标识符获取
当业务逻辑仅需提取单个标量结果(如统计总数、获取系统时间或新插入行的自增值)时,ExecuteScalar 能够跳过完整的字段解析过程,直接返回结果集第一行第一列的数据。由于返回类型为 object,开发者需在外部完成显式类型转换。
// 统计会员表总容量
scalarCmd.CommandText = "SELECT COUNT(0) FROM SysMembers;";
long memberCount = Convert.ToInt64(scalarCmd.ExecuteScalar());
// 捕获服务端当前时间戳
DateTime svcTime = Convert.ToDateTime(scalarCmd.CommandText = "SELECT GETUTCDATE();");
若需在插入后立刻拿到自增主键,可在同一批处理中将检索语句追加至末尾。现代 SQL Server 环境建议使用 SCOPE_IDENTITY() 以规避触发器上下文切换导致的定位偏移:
string identityFetch = @"
INSERT INTO SysMembers(MemberName, MemberPwd) VALUES ('autogen_test', 'init_pwd');
SELECT CAST(SCOPE_IDENTITY() AS INT);";
scalarCmd.CommandText = identityFetch;
int generatedPk = Convert.ToInt32(scalarCmd.ExecuteScalar());
流式读取多行结果集
面对大型结果集或内存敏感场景,ExecuteReader 配合 SqlDataReader 提供了一去不复返的同步枚举通道。通过持续调用 Read() 推进内部指针,该方法在成功抓取下一行时返回 true,此时读取器内部光标已精准定位至该记录。
scanCmd.CommandText = "SELECT UserID, UserName, RegDate FROM SysMembers WHERE Status = 1;";
using (var forwardReader = scanCmd.ExecuteReader())
{
// 摒弃硬编码列号,利用元数据动态映射索引
int userNameColIdx = forwardReader.GetOrdinal("UserName");
while (forwardReader.Read())
{
string currentUser = forwardReader.GetString(userNameColIdx);
System.Console.WriteLine(currentUser);
}
}
SqlDataReader 提供的强类型提取方法(如 GetString、GetInt32)均要求传入从零开始的列序数。结合 GetOrdinal 根据列名反向推导索引,可有效应对表结构变更引发的错位异常。
资源生命周期管控
C# 语言层面的 using 构造在脱离声明作用域时,会自动触发目标实体的 Dispose 钩子。底层框架对 SqlConnection 等连接的 Dispose 实现包含保护性判断:若检测到连接尚未终止,则优先执行物理通道的 Close 断开操作,随后再释放底层句柄。这种双层清理策略避免了因忘记手动关闭而导致的连接池耗尽问题。
各方法的行为契约明确:ExecuteNonQuery 交付受影响行数;ExecuteScalar 萃取首行列标量;ExecuteReader 抛出可逐条消费的流式接口。