C# SqlCommand实现数据不存在时插入的异常问题排查
解决BetEntities表避免重复插入的问题
先排查核心语法问题
你之前的错误大概率是SQL语法结构写错了——INSERT语句本身不支持直接跟WHERE NOT EXISTS,必须用IF NOT EXISTS块包裹INSERT逻辑。
错误写法(会导致语法报错):
INSERT INTO BetEntities (Col1, Col2) VALUES (@Val1, @Val2) WHERE NOT EXISTS (...)
正确的单条插入判断语法:
IF NOT EXISTS (SELECT 1 FROM BetEntities WHERE [唯一标识列] = @标识值) BEGIN INSERT INTO BetEntities (Col1, Col2, ...) VALUES (@Val1, @Val2, ...) END
这里的[唯一标识列]要换成你表中用来判断重复的字段(比如Id、订单号这类唯一值)。
优化你的异步实现方案
方案1:修正循环构建的参数化SQL
不要直接拼接字符串(容易出语法错误+SQL注入风险),改用参数化查询:
public async Task SaveBetEntityAsync(List<BetEntity> betEntities) { var connectionString = "你的数据库连接字符串"; using var conn = new SqlConnection(connectionString); await conn.OpenAsync(); foreach (var entity in betEntities) { // 构建带判断的参数化SQL var sql = @" IF NOT EXISTS (SELECT 1 FROM BetEntities WHERE Id = @Id) BEGIN INSERT INTO BetEntities (Id, BetAmount, CreateTime) VALUES (@Id, @BetAmount, @CreateTime) END"; using var cmd = new SqlCommand(sql, conn); // 添加参数 cmd.Parameters.AddWithValue("@Id", entity.Id); cmd.Parameters.AddWithValue("@BetAmount", entity.BetAmount); cmd.Parameters.AddWithValue("@CreateTime", entity.CreateTime); await cmd.ExecuteNonQueryAsync(); } }
方案2:批量处理(更高效,推荐)
循环单条插入效率低,尤其数据量大时,用表值参数+MERGE语句一次性处理整个DataTable:
- 先在SQL Server创建用户定义表类型:
CREATE TYPE dbo.BetEntityTableType AS TABLE ( Id INT PRIMARY KEY, -- 唯一标识列,用来判断重复 BetAmount DECIMAL(18,2), CreateTime DATETIME )
- C#异步实现代码:
public async Task SaveBetEntityBatchAsync(DataTable betDataTable) { var connectionString = "你的数据库连接字符串"; using var conn = new SqlConnection(connectionString); await conn.OpenAsync(); var sql = @" MERGE INTO BetEntities AS Target USING @BetEntities AS Source ON Target.Id = Source.Id -- 这里的匹配条件就是判断重复的规则 WHEN NOT MATCHED THEN INSERT (Id, BetAmount, CreateTime) VALUES (Source.Id, Source.BetAmount, Source.CreateTime);"; using var cmd = new SqlCommand(sql, conn); // 添加表值参数 var tvpParam = cmd.Parameters.AddWithValue("@BetEntities", betDataTable); tvpParam.SqlDbType = SqlDbType.Structured; tvpParam.TypeName = "dbo.BetEntityTableType"; await cmd.ExecuteNonQueryAsync(); }
额外注意事项
- 确保你用来判断重复的字段(比如Id)在数据库表上有唯一约束,即使SQL逻辑有疏漏,数据库层面也能拦截重复数据。
- 避免直接拼接SQL字符串,参数化查询不仅能避免语法错误,还能防止SQL注入。
内容的提问来源于stack exchange,提问作者Nourhat
相关产品推荐
相关产品推荐

