В документации четко указано, что если вы откроете Recordset
, у которого нет записей:
BOF
будет верно
EOF
будет правдой
RecordCount
будет 0
Для непустых Recordset
ни BOF
, ни EOF
не верны, пока вы не выйдете за пределы первой или последней записи.
Может быть, время от времени кто-то другой мог добавить / удалить запись в одну из таблиц в наборе записей, которую вы только что открыли, и изменить результирующий набор?
Это может быть результатом состояния гонки.
Вместо использования BOF
или EOF
вы можете проверить на Recordcount
: всегда 0
, если набор записей пуст.
Если набор записей не пустой, он обычно возвращает 1
сразу после того, как набор записей был открыт; Recordcount
в этом случае не дорогая операция.
Единственный способ действительно вернуть фактическое количество записей - это выдать MoveLast
перед вызовом Recordcount
, чтобы принудительно загрузить все записи.
Обычно, если мне нужно перебрать набор результатов только для чтения:
Dim db as DAO.Database
Dim rs as DAO.RecordSet
Set db = CurrentDB()
Set rs = db.OpenRecordSet("...", dbOpenForwardOnly)
If Not (rs Is Nothing) Then
With rs
Do While Not .EOF
' Do stuff '
.MoveNext
Loop
.Close
End With
Set rs = Nothing
End If
Set db = Nothing
Если мне не нужно перебирать записи, а просто проверять, было ли что-либо возвращено:
Set rs = db.OpenRecordSet("...", dbOpenForwardOnly)
If Not (rs Is Nothing) Then
With rs
If .RecordCount > 0 Then
' We have a result '
Else
' Empty resultset '
End If
.Close
End With
Set rs = Nothing
End If
Set db = Nothing
Это довольно оборонительно, и вы должны приспосабливаться к вашим обстоятельствам, но каждый раз работает правильно.
Что касается вашего второго вопроса, тестирование (BOF
или EOF
) после открытия набора записей должно быть более надежным, чем версия And
, хотя я бы сам использовал Recordcount
.
Отредактируйте после вашего исправленного вопроса:
Из фрагмента кода, который вы добавили в свой вопрос, я вижу пару проблем, основной из которых является отсутствие вашего оператора SQL и предложение ORDER BY
.
Проблема в том, что вы ожидаете, что результирующий набор будет в последовательности Begin Order
, за которой следует последовательность End Order
, но ваш оператор SQL не гарантирует вам этого.
В большинстве случаев, поскольку вы используете автоинкремент в качестве идентификатора, ядро базы данных будет возвращать данные в таком естественном порядке, но нет гарантии, что:
- Так будет всегда
- Исходные данные были сохранены в ожидаемой последовательности, в результате чего идентификаторы были в «неправильном» порядке.
Поэтому, когда у вас есть ожидания относительно последовательности набора результатов, вы должны явно упорядочить его.
Я бы также переработал этот бит кода:
' ids are autoincrement long integers '
SQLString = "select * from Orders where type = OrderBegin or type = OrderEnd"
Dim OrderOpen as Boolean
OrderOpen = False
Set rs = db.Openrecordset(SQLString)
If rs.bof <> True And rs.eof <> True Then
myrec.movelast
If rs.fields("type").value = BeginOrder Then
OrderOpen = True
End If
End If
В отдельную функцию, похожую на:
' Returns true if the given CustID has a Open Order, '
' false if they are all closed.'
Public Function IsOrderOpen(CustID as Long) As Boolean
Dim result as Boolean
result = False
Dim sql as String
' Here I assume that the Orders table has a OrderDateTime field that '
' allows us to sort the order in the proper chronological sequence '
' To avoid loading the complete recordset, we sort the results in a way '
' that will return the last used order type as the first record.'
sql = sql & "SELECT Type "
sql = sql & "FROM Orders "
sql = sql & "WHERE ((type = OrderBegin) OR (type = OrderEnd)) "
sql = sql & " AND (CustID=" & CustID & ")"
sql = sql & "ORDER BY OrderDateTime DESC, Type DESC;"
Dim db as DAO.Database
Dim rs as DAO.Recordset
Set db = CurrentDB()
Set rs = db.Openrecordset(sql, dbOpenForwardOnly)
If Not (rs Is Nothing) Then
If rs.RecordCount > 0 Then
result = (rs!type = BeginOrder)
End If
rs.Close
End If
Set rs = Nothing
Set db = Nothing
IsOrderOpen = result
End Function
Это сделало бы все это более надежным.