Как избежать исключения дубликатов ключей
Я использую TableAdapter для вставки записей в таблицу в цикле.
foreach(....)
{
....
....
teamsTableAdapter.Insert(_teamid, _teamname);
....
}
Где TeamID - это первичный ключ в таблице, а _teamID вставляет его. На самом деле я извлекаю данные из XML-файла, который содержит уникальный teamId
После первого запуска этого цикла вставка создает исключение "Дублированный первичный ключ". Чтобы справиться с этим, я сделал это
foreach(....)
{
....
....
try
{
_teamsTableAdapter.Insert(_teamid, _teamname);
}
catch (System.Data.SqlClient.SqlException e)
{
if (e.Number != 2627)
MessageBox.Show(e.Message);
}
....
....
}
Но использование оператора try catch стоит дорого, как избежать этого исключения. Я работаю в VS2010 и INSERT ... ON DUPLICATE KEY UPDATE
не работает.
Я хочу избегать операторов try catch и обрабатывать их без использования операторов try catch.
3 ответа
Исходя из ваших комментариев к другим ответам, я бы предложил изменить TeamID с первичного ключа (если это возможно) и установить новый столбец Idx в качестве первичного ключа. Затем вы можете установить триггер в вашей БД, который при вставке новой записи с дубликатом TeamID обновит исходную запись и удалит новую.
Если это невозможно, я бы изменил хранимую процедуру, которая вставляет запись, чтобы вместо простой вставки сначала проверять дубликат TeamID. Если дублирующего идентификатора нет, запись может быть вставлена, в противном случае она просто выберет "0".
Пример псевдокода:
Declare @Count int
Set @Count = (Select Count(TeamId) From [Table] where TeamId = @TeamId)
If(@Count > 0)
Begin
Select 0
End
Else
--Insert Logic Here
Тогда ваш метод вставки в коде может вместо ExecuteNonQuery() быть ExecuteScalar(). Ваш код будет обрабатывать это таким образом
If(_teams.TableAdapter.Insert(_teamId, _teamName) == 0)
{
_teams.TableAdapter.Update(_teamId, _teamName)
}
В качестве альтернативы, если вы просто хотите обработать все это в SQL (чтобы ваш код C# не менялся), вы можете сделать что-то вроде этого:
Declare @Count int
Set @Count = Select Count(TeamId) from [Table] Where TeamId = @TeamId
If(@Count > 0)
Begin
//Update Logic
End
Else
Begin
//Insert Logic
End
Но, опять же, я бы просто изменил таблицу, если это вариант.
Есть ли у используемой таблицы первичный ключ? Если нет, вы должны создать его, так как это предотвратит дублирование записей и может упростить доступ к ключам для других частей вашей программы.
Обычно это делается с помощью столбца идентификаторов или чего-то подобного. (Что, похоже, у вас уже есть с точки зрения TeamID, в этом случае вам нужно всего лишь изменить его на первичный ключ в SQL-MS или VS2010).
Редактировать: чтобы назначить первичный ключ как столбец идентификаторов (teamID в вашем примере) с помощью Visual Studio:
Зайдите в обозреватель серверов. Перейдите к соответствующей таблице. Щелкните правой кнопкой мыши "Open Table Definition". Нажмите на столбец первичного ключа. Прокручивайте окно свойств, пока не дойдете до "спецификации личности". Измените это на "да" (вы можете установить инкремент / начальное значение на то, что вы хотите. Обычно 1,1 хорошо). Теперь все, что вам нужно сделать, это вставить имя команды в таблицу, и TeamID будет создан автоматически.
В ваших данных явно есть дубликаты. Либо вам нужно сначала устранить их, либо использовать какой-либо тип слияния, чтобы выполнить проверку, если новая, или обновление, если не новое.
Чтобы увидеть, какие данные являются причиной проблемы, запустите профилировщик, пока вы запускаете цикл из своего приложения, и посмотрите, какие статистические данные действительно отправляются. Это должно указать вам на то, какие записи дублируются.
Если это большой файл, массовая вставка (после очистки дубликатов) будет выполняться быстрее, чем построчная обработка.