You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SCOPE_IDENTITY时SQL出现重复记录的C#桌面应用问题

问题:调用存储过程获取SCOPE_IDENTITY时出现重复插入记录

我在开发C#桌面应用时,尝试通过SQL的SCOPE_IDENTITY()获取新增记录的ID,但数据库里出现了重复记录。以下是我的相关代码:

SQL存储过程

ALTER PROCEDURE [dbo].[ztSinifEgitimiEkle] 
@islev NVARCHAR(MAX), 
@ztSinifEgitimiDurumAtamaID INT, 
@ztSinifEgitimiDurumKisiID NVARCHAR(30), 
@ztSinifEgitimiDurumKisiTipiID TINYINT , 
@ztSinifEgitimiDurumKatilim BIT, 
@ztSinifEgitimiEgitimAdi VARCHAR(50), 
@ztSinifEgitimiAtamaEgitimID int, 
@ztSinifEgitimiAtamaEgitmenID CHAR(30), 
@ztSinifEgitimiAtamaKisiTipiID TINYINT, 
@ztSinifEgitimiAtamaTarihSaat DATETIME, 
@ztSinifEgitimiAtamaSüre varchar(50), 
@ztSinifEgitimiAtamaKategoriID INT, 
@ztSinifEgitimiAtamaEgitimTipi Smallint 
AS 
/* İşlev 0 ise : ztSinifEgitimiDurum2 tablosuna Insert Eder 
İşlev 1 ise : ztSinifEgitimi2 tablosuna Insert Eder 
İşlev 2 ise : ztSinifEgitimiAtama2 tablosuna Insert Eder */ 
IF @islev='0' 
BEGIN 
INSERT INTO [dbo].[ztSinifEgitimiDurum2] ( AtamaID, KisiID , KisiTipiID , Katilim ) 
VALUES ( @ztSinifEgitimiDurumAtamaID , @ztSinifEgitimiDurumKisiID , @ztSinifEgitimiDurumKisiTipiID , @ztSinifEgitimiDurumKatilim ) 
END 
IF @islev='1' 
BEGIN 
INSERT INTO [dbo].[ztSinifEgitimi2] ( [EgitimAdi] ) 
VALUES (@ztSinifEgitimiEgitimAdi ) 
SELECT SCOPE_IDENTITY() -- Son Kaydın IDsi 
END 
IF @islev='2' 
BEGIN 
INSERT INTO [dbo].[ztSinifEgitimiAtama2] ([EgitimID] ,[EgitmenID] ,[KisiTipiID] ,[TarihSaat] ,[Süre] ,[KategoriID] ,[EgitimTipi]) 
VALUES ( @ztSinifEgitimiAtamaEgitimID , @ztSinifEgitimiAtamaEgitmenID , @ztSinifEgitimiAtamaKisiTipiID , @ztSinifEgitimiAtamaTarihSaat , @ztSinifEgitimiAtamaSüre , @ztSinifEgitimiAtamaKategoriID , @ztSinifEgitimiAtamaEgitimTipi ) 
END 

C#代码

private void button4_Click(object sender, EventArgs e) 
{ 
try 
{ 
if (egitimadi.Text.Length!=0) 
{ 
if (baglan.State == ConnectionState.Closed) baglan.Open(); 
SqlCommand sqlCmd = new SqlCommand("ztSinifEgitimiEkle", baglan); 
sqlCmd.CommandType = CommandType.StoredProcedure; 
sqlCmd.Parameters.AddWithValue("@islev", 1); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumAtamaID", 0); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiID", ""); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiTipiID", 8); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKatilim", 1); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiEgitimAdi", egitimadi.Text); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimID", 1); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitmenID", ""); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaKisiTipiID", 8); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaTarihSaat", "2017-01-01"); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaSüre", ""); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaKategoriID", 0); 
sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimTipi", 0); 
String LastID = sqlCmd.ExecuteScalar().ToString(); 
sqlCmd.ExecuteNonQuery(); 
SqlCommand sqlCmd2 = new SqlCommand("ztSinifEgitimiEkle", baglan); 
sqlCmd2.CommandType = CommandType.StoredProcedure; 
sqlCmd2.Parameters.AddWithValue("@islev", 2); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumAtamaID", 0); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiID", ""); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiTipiID", 8); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKatilim", 1); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiEgitimAdi", ""); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimID", LastID); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitmenID", ""); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaKisiTipiID", 8); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaTarihSaat", "2017-01-01"); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaSüre", ""); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaKategoriID", 0); 
sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimTipi", 0); 
sqlCmd2.ExecuteNonQuery(); 
button4.Enabled = false; 
yenile(); 
} 
else 
{ 
MessageBox.Show("Lütfen Tüm Bilgileri Doldurunuz."); 
} 
} 
catch (Exception ex) 
{ 
MessageBox.Show(ex.Message, "Hata Mesajı"); 
} 
finally 
{ 
baglan.Close(); 
} 
} 

问题根源

看你的C#代码,在执行sqlCmd.ExecuteScalar()获取新增记录ID之后,又额外调用了sqlCmd.ExecuteNonQuery()——这相当于两次执行了同一个存储过程的islev=1分支!第一次ExecuteScalar已经完成了插入操作并返回了ID,第二次ExecuteNonQuery再次触发插入,直接导致数据库里多出了一条重复记录。

另外还有个小问题:SCOPE_IDENTITY()返回的是decimal类型,你直接转成string再作为参数传给下一个存储过程,可能会引发类型不匹配的潜在问题。

修复方案

  1. 移除多余的ExecuteNonQuery()调用:只保留ExecuteScalar()来执行存储过程并获取返回的ID。
  2. 正确转换ID类型:把返回的结果转换成int类型,再传入下一个存储过程。
  3. 使用using语句管理资源:确保SqlCommand和连接资源能被正确释放,避免连接泄漏。

修改后的C#代码

private void button4_Click(object sender, EventArgs e) 
{ 
    try 
    { 
        if (!string.IsNullOrEmpty(egitimadi.Text)) 
        { 
            using (var baglan = new SqlConnection("你的连接字符串")) // 建议在这里初始化连接,用using自动释放
            {
                baglan.Open(); 
                // 第一次调用:插入ztSinifEgitimi2并获取ID
                using (SqlCommand sqlCmd = new SqlCommand("ztSinifEgitimiEkle", baglan)) 
                { 
                    sqlCmd.CommandType = CommandType.StoredProcedure; 
                    sqlCmd.Parameters.AddWithValue("@islev", 1); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumAtamaID", 0); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiID", ""); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiTipiID", 8); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiDurumKatilim", 1); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiEgitimAdi", egitimadi.Text); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimID", 1); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitmenID", ""); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaKisiTipiID", 8); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaTarihSaat", new DateTime(2017,1,1)); // 用DateTime类型而非字符串
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaSüre", ""); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaKategoriID", 0); 
                    sqlCmd.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimTipi", 0); 

                    // 正确转换SCOPE_IDENTITY的返回值
                    int lastID = Convert.ToInt32(sqlCmd.ExecuteScalar()); 

                    // 第二次调用:插入ztSinifEgitimiAtama2
                    using (SqlCommand sqlCmd2 = new SqlCommand("ztSinifEgitimiEkle", baglan)) 
                    { 
                        sqlCmd2.CommandType = CommandType.StoredProcedure; 
                        sqlCmd2.Parameters.AddWithValue("@islev", 2); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumAtamaID", 0); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiID", ""); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKisiTipiID", 8); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiDurumKatilim", 1); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiEgitimAdi", ""); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimID", lastID); // 传入int类型的ID
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitmenID", ""); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaKisiTipiID", 8); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaTarihSaat", new DateTime(2017,1,1)); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaSüre", ""); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaKategoriID", 0); 
                        sqlCmd2.Parameters.AddWithValue("@ztSinifEgitimiAtamaEgitimTipi", 0); 

                        sqlCmd2.ExecuteNonQuery(); 
                    } 

                    button4.Enabled = false; 
                    yenile(); 
                }
            }
        } 
        else 
        { 
            MessageBox.Show("Lütfen Tüm Bilgileri Doldurunuz."); 
        } 
    } 
    catch (Exception ex) 
    { 
        MessageBox.Show(ex.Message, "Hata Mesajı"); 
    } 
} 

额外建议

  • 存储过程里的@islev参数是NVARCHAR(MAX),但你传入的是整数,建议把@islev改成INT类型,这样更严谨,避免类型转换问题。
  • 尽量不要用AddWithValue,因为它会自动推断参数类型,可能引发性能或类型匹配问题,建议用SqlParameter指定明确的类型和长度,比如:
    sqlCmd.Parameters.Add("@ztSinifEgitimiEgitimAdi", SqlDbType.VarChar, 50).Value = egitimadi.Text;
    

内容的提问来源于stack exchange,提问作者Yunus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:29:18