C# 更新sql返回0行后,插入sql中立即发生违反主键约束的错误

C# 更新sql返回0行后,插入sql中立即发生违反主键约束的错误,c#,sql,sql-server,C#,Sql,Sql Server,我有这样的代码 if (***Adapter.UpdateRow(memberID, Type) == 0) { ***Adapter.InsertRow(memberID, Type); } 但是我在InsertRow中得到了违反主键约束的错误。 表中的主键是memberID和Type,下面是SQL: InsertRow string sql = @" INSERT INTO TB

我有这样的代码

        if (***Adapter.UpdateRow(memberID, Type) == 0)
        {
            ***Adapter.InsertRow(memberID, Type);
        }
但是我在InsertRow中得到了违反主键约束的错误。 表中的主键是memberID和Type,下面是SQL:

InsertRow

        string sql = @"
            INSERT INTO TBL***** ( 
                   MemberID
                 , Type
                 , DateTime
                   ) 
            VALUES ( 
                   @MemberID 
                 , @Type 
                 , GETDATE() 
                   )
        ";

        var cm = new SqlCommand(sql.ToString());
        cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
        cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;

        return this.ExecuteNonQuery(cm);
            string sql = @"
            UPDATE TBL****
               SET DateTime = GETDATE()
             WHERE MemberID = @MemberID
               AND Type = @Type
        ";

        var cm = new SqlCommand(sql.ToString());
        cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
        cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;

        return this.ExecuteNonQuery(cm);
UpdateRow

        string sql = @"
            INSERT INTO TBL***** ( 
                   MemberID
                 , Type
                 , DateTime
                   ) 
            VALUES ( 
                   @MemberID 
                 , @Type 
                 , GETDATE() 
                   )
        ";

        var cm = new SqlCommand(sql.ToString());
        cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
        cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;

        return this.ExecuteNonQuery(cm);
            string sql = @"
            UPDATE TBL****
               SET DateTime = GETDATE()
             WHERE MemberID = @MemberID
               AND Type = @Type
        ";

        var cm = new SqlCommand(sql.ToString());
        cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
        cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;

        return this.ExecuteNonQuery(cm);
我现在真的很想知道它发生的原因(就在更新之后)


谢谢大家的评论。 我认为可能有两个线程相互冲突,然后第一个线程成功插入,但第二个线程失败

我在我的网站的用户注册中有这样的逻辑,当用户点击注册邮件中的激活链接时就会发生。
我认为用户可能会(以高速)双击链接,然后出现错误。

违反主键约束意味着您试图插入一条记录,该记录将在主键字段上创建重复项

检查表定义并注意主键中的字段

如果您可以将问题中的表定义发布给其他读者,效果会更好:)

添加评论后编辑

如果您的主键同时包含MemberId和Type,则更新中可能存在逻辑错误,或者存在更新中不返回结果的情况

您应该按照建议使用upsert(更新或插入)

逻辑如下:

  • 检查记录是否存在
  • 如果存在更新或插入新记录

  • 您通常不会执行更新来检查记录是否存在,因为在某些情况下,更新可能不会执行任何更改。

    您的代码依赖于执行DML后返回的行数。这不一定会发生,因为这取决于设置。当“设置无计数”处于启用状态时 返回的行数始终为0,与实际更新的行数无关。返回的行数是
    ExecuteNonQuery()
    返回的

    您可以检查并确保SETNOCOUNT已关闭,但这仍然是一个失败的原因。您提出的代码在并发性方面存在根本性缺陷:多个客户端应用程序可以同时运行更新,并且所有客户端应用程序都认为应该插入,然后只有一个客户端应用程序会成功。正确的方法是使用以下语句:

    MERGE INTO TBL**** as t
    USING (VALUES (GETDATE(), @MemberId, @Type)) AS s (date, MemberID, Type)
      ON t.MemberID =s.MemberID and t.Type = s.Type
    WHEN MATCHED  THEN
      UPDATE SET t.DateTime = s.date
    WHEN NOT MATCHED BY TARGET
      INSERT (MemberID, Type, DateTime) VALUES (s.MemberID, s.Type, s.DateTime);
    

    这是一条语句,它确实会使插入或更新失效,而不会产生并发风险。

    主键是什么?是否尝试运行Sql Server Profiler跟踪?是否检查日志等以查看更新是否返回错误?在显示代码逻辑的情况下,如果更新有错误并返回0行更新,则将尝试插入。您可能需要重新考虑一下。将两个查询合并为一个“UpdateOrInsert”,并使用“IF EXISTS”检查是否要更新或插入。感谢您的回答。这是我的表定义,来自脚本工具(键的一部分)ALTER table[dbo]。[TBLLogin]ADD CONSTRAINT[PK_TBLLogin]主键集群([MemberID]ASC,[Type]ASC)(PAD_INDEX=OFF,STATISTICS_norecocomputer=OFF,SORT_IN_TEMPDB=OFF,IGNORE_DUP_KEY=OFF,ONLINE=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)打开[主]GO