В документации четко указано, что если вы откроете 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
Это сделало бы все это немного более надежным.
person
Renaud Bompuis
schedule
19.06.2009