Как определить дублирование первичного ключа из кода ошибки SQL Server 2008?

Я хочу знать, как мы идентифицируем ошибку дублирования первичного ключа из кода ошибки SQL Server в С#.

В качестве примера у меня есть форма С# для ввода данных в базу данных SQL Server, когда во время ввода данных возникает ошибка, как я могу определить причину ошибки из исключения?

Ответ 1

Если вы поймаете SqlException, то увидите его номер, число 2627 будет означать нарушение уникального ограничения (включая первичный ключ),

try
{
    // insertion code
}
catch (SqlException ex)
{
    if (ex.Number == 2627)
    {
        //Violation of primary key. Handle Exception
    }
    else throw;
}

MSSQL_ENG002627

Это общая ошибка, которая может быть поднята независимо от того, база данных реплицируется. В реплицированных базах данных ошибка обычно возникает из-за того, что первичные ключи не управляются надлежащим образом по топологии.

Ответ 2

Это старый поток, но я думаю, стоит отметить, что с С# 6 вы можете:

try
{
    await command.ExecuteNonQueryAsync(cancellation);
}
catch (SqlException ex) when (ex.Number == 2627)
{
    // Handle unique key violation
}

И с С# 7 и исключение обертки (например, Entity Framework Core):

try
{
    await _context.SaveChangesAsync(cancellation);
}
catch (DbUpdateException ex) 
   when ((ex.InnerException as SqlException)?.Number == 2627)
{
    // Handle unique key violation
}

Самое большое преимущество этого подхода по сравнению с принятым ответом:

В случае, если номер ошибки не равен 2627 и, следовательно, это не уникальное нарушение ключа, исключение не будет обнаружено.

Без фильтра исключений (when) вам лучше запомнить повторное бросание этого исключения, если вы не сможете его обработать. И в идеале не забывать использовать ExceptionDispatchInfo, чтобы исходный стек не потерялся.

Ответ 3

В случае Entity Framework принятый ответ не будет работать, и ошибка не будет обнаружена. Вот тестовый код, будет обработан только оператор catch catch или, конечно же, общее исключение, если инструкция сущности была удалена:

try
{
    db.InsertProcedureCall(id);
}
catch (SqlException e0)
{
   // Won't catch
}
catch (EntityCommandExecutionException e1)
{
    // Will catch
    var se = e1.InnerException as SqlException;
    var code = se.Number;
}
catch (Exception e2)
{
   // if the Entity catch is removed, this will work too
    var se = e2.InnerException as SqlException;
    var code = se.Number;
}

Ответ 4

Рабочий код для фильтра только дубликат исключения первичного ключа исключения

using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
.........

 try{
    abc...
    }
    catch (DbUpdateException ex)
                {
                    if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601)
                    {
                        return ex.ToString();
                    }
                    else
                    {
                        throw;
                    }
                }

Обратите внимание, что detial: - ex.InnerException.InnerException, а не ex.InnerException