Ошибка времени выполнения VBA для нарушения первичного ключа при вызове метода ADO RecordSet.MoveFirst

Я использую поставщика SQLOLEDB через ADODB для работы с базой данных SQLServer 2012R2 с использованием VBA, запущенной в Excel.

У меня нет проблем с навигацией по RecordSet, сгенерированному из инструкции SELECT, сгенерированной с помощью метода RecordSet.Open.

Недавно я начал получать RecordSet, возвращаемый из операторов INSERT, с помощью предложения OUTPUT для возврата идентификатора для вновь вставленной записи. Затем я вызываю метод Connection.Execute с оператором SQL и получаю из него RecordSet с новым значением идентификатора.

Если для таблицы, в которую была вставлена ​​новая запись, определены первичные ключи, то попытка вызвать RecordSet.MoveFirst для этого возвращенного RecordSet приводит к тому, что исключение нарушения первичного ключа вызывается как ошибка времени выполнения VBA. Если в таблице не определены ключи, я не получаю сообщение об ошибке.

Я получаю сообщение об ошибке в написанной мной универсальной функции, которая перебирает набор записей для извлечения данных в объект конкретного приложения.
Я использую метод RecordSet.MoveFirst перед циклом через RecordSet, чтобы убедиться, что я нахожусь в начале RecordSet, на тот случай, если RecordSet был затронут другим методом, который изменил положение курсора.

Я также вызываю метод MoveFirst в другой функции, которая получает количество записей в RecordSet, так как я не смог найти другой способ с курсором по умолчанию, чтобы узнать, сколько записей есть. Исключение возникает в любом из этих двух методов всякий раз, когда вызывается MoveFirst.

Я заметил, что RecordSet, возвращенный из предложения OUTPUT, имеет свойство.Source, установленное на полный оператор INSERT, который был первоначально выдан.

Свойство RecordSet.LockType равно adLockReadOnly, а.EditMode равно adEditNone.

Одна вещь, которую я не понимаю здесь, это то, почему MoveFirst может привести к такому поведению, когда он пытается повторить оператор INSERT только потому, что я перемещаю курсор. Я не думаю, что на самом деле это происходит, потому что, когда я пытаюсь сделать это на таблице без заданных ключей, я не получаю дополнительную дублирующую запись.

Совет? Возможно, есть лучший способ управлять позиционированием и повторением курсора через RecordSet?

Я полагаю, я мог бы попытаться поместить оператор "On Error Resume Next" перед вызовом MoveFirst, но это не кажется хорошим решением, даже если бы оно работало.

1 ответ

В конце концов я посмотрел на эффект курсора, который использовал. Я не особо разбирался в этом и просто использовал стандартный серверный курсор. Изменение свойства CursorLocation соединения с adUseClient позволило мне без проблем вызвать метод MoveFirst.

Вот небольшой объем кода, чтобы показать, как я теперь получаю RecordSet с указанием местоположения курсора как единственного изменения в том, что я делал:

Dim conn As ADODB.Connection
Dim adoRS As ADODB.RecordSet
Set conn = New ADODB.Connection

On Error GoTo Catch
**conn.CursorLocation = adUseClient**  //added this line
conn.Open (ConnectionString)

Set adoRS = conn.Execute(SQLStatement)
//RecordSet inherits the cursor type from the connection
//Calling adoRS.MoveFirst multiple times now does not generate an error. 

Но я так и не понял, почему серверный курсор имеет поведение, которое вызывает исключение или способ обойти его с помощью серверного курсора.

Другие вопросы по тегам