Заметьте, число параметров в коллекции Parameters равно 2, а не 1, как должно было бы быть. Это связано с моей недоработкой и недоработкой Microsoft. Перед тем, как начать формировать коллекцию Parameters, я должен был очистить ее содержимое, вызвав метод Delete. Я не сделал этого, поскольку метод Delete не вызывается в данном контексте. По этой причине при повторном запуске процедуры произошло добавление параметра к уже имеющейся коллекции. В данном случае, когда выполняется запрос с одним параметром, это не приводит к ошибке, и я не стал усложнять уже и так довольно длинную процедуру. Но в принципе это серьезная ошибка, которая в другой ситуации может привести к неприятностям, например, если бы в следующей команде я попытался бы выполнить другой параметризованный запрос. Так что обратите внимание на эту ситуацию, и корректно работайте с коллекцией Parameters. Заметьте, проблемы исчезают для локально определенного объекта Command .
Этот объект представляет набор записей, возвращаемый в результате выполнения операции. В каждый момент можно работать только с одной выделенной записью набора, которая называется текущей записью. Естественно, есть методы, позволяющие перемещаться по записям набора. В предыдущем примере при работе с набором записей для этой цели использовались методы MoveFirst и MoveLast. При использовании ADO практически вся работа с данными ведется через этот объект. Он используется для того, чтобы читать записи из базы данных, изменять их содержимое, удалять и добавлять новые записи. Это самый сложный по своей организации объект ADO, - у него больше всего свойств, методов и событий. В предыдущем примере уже демонстрировалось применение этого объекта, где он создавался в результате выполнения команды, получающей результаты запроса к базе данных, затем полученные данные использовались для просмотра. Прежде чем обсудить все те возможности, которые предоставляет этот объект, давайте, как обычно, вначале рассмотрим его свойства, методы и события.
Объект Recordset имеет несколько десятков свойств. Попробуем разобраться в них:
Public Sub AllRecords() 'Две схемы прохода по набору записей With Rst1 'Схема1: От начала к концу набора .MoveFirst Do While Not .EOF 'Обработка текущей записи Debug.Print Rst1!Название .MoveNext Loop 'Схема2: От конца к началу набора .MoveLast Do 'Обработка текущей записи Debug.Print Rst1!Название .MovePrevious Loop Until .BOF End With End Sub
Когда открывается набор записей, то все записи имеют уникальные закладки. Сохранение закладок - дело рук программиста. Вы можете сохранить закладку в собственной переменной типа Variant, используя значение свойства Bookmark. В тот момент, когда значение этой переменной будет присвоено свойству Bookmark набора записей, автоматически текущей станет запись с указанной закладкой. Вот пример, иллюстрирующий работу с закладками:
Public Sub CreateBookmarks() 'Работа с закладкой Dim MyBookmark As Variant With Rst1 .MoveFirst Do While Not .EOF 'Обработка текущей записи If Rst1!Название = "Книжная лавка" Then 'Создаю закладку MyBookmark = .Bookmark End If .MoveNext Loop 'переход к записи с закладкой .Bookmark = MyBookmark Debug.Print Rst1!Название End With End Sub
Прежде чем продолжить рассмотрение свойств, есть смысл посвятить отдельный параграф курсору - важному понятию в модели ADO и при работе с базами данных. Курсор - это элемент базы данных, позволяющий управлять перемещением по записям, обновлением данных, видимостью изменений, сделанных другими пользователями.
В реляционных базах данных в результате запроса возвращается набор строк таблицы (записей). Приложению, работающему с этим набором в каждый текущий момент необходим не весь набор, а отдельная запись или небольшой блок из записей набора. Для работы с набором записей приложению необходим программный механизм, который будет управлять позициями записей в наборе при его изменении, скроллингом - перемещением вперед и назад по записям набора, разрешением конфликтов при одновременном доступе многих пользователей к одной и той же записи. Все эти службы и предоставляются совокупностью программных компонент, называемых курсорами. Они реализованы в виде библиотеки курсоров, являющейся, обычно, частью базы данных. Название "Курсор" связано с тем, что, так или иначе, курсор указывает на текущую запись в наборе.
Поскольку от решения вопросов, относящихся к курсорам, зависит эффективность работы с базой данных, и эти решения могут играть определяющую роль, то следует уметь правильно выбирать тип курсора, положение курсора и другие его характеристики. Тип курсора задает, как будет идти скроллинг, динамику изменения набора записей и многое другое. Положение курсора определяет, где будет идти основная работа с ним - на клиентской или серверной стороне. Рассмотрим возможные типы курсоров. Их четыре:
Поговорим теперь о такой важной характеристике курсора как его положение (Cursor Location). Константы adUseClient и adUseServer перечисления CursorLocationEnum задают положение курсора. В зависимости от установленного значения все необходимые ресурсы и сама работа с данными ведется на клиентской или серверной стороне. Достоинства работы на стороне клиента состоят в быстром отклике на обращение к записям, не требующим выхода в сеть. Когда работа с записями ведется в основном в режиме их чтения, то это положение курсора наиболее предпочтительно. Некоторым недостатком является то, что при больших наборах клиентскому компьютеру требуются большие ресурсы по памяти для хранения данных. Преимущества работы также теряются, когда интенсивно изменяется состав набора - записи удаляются, добавляются, так как эти изменения должны отражаться и на сервере. Если курсор расположен на серверной стороне, то объем передаваемых данных может быть существенно уменьшен, поскольку вся обработка ведется на сервере и клиенту передается только необходимые ему записи, а не весь набор. С другой стороны при большом числе активных пользователей каждому из них сервер должен выделить ресурсы, что может быть серьезной нагрузкой на сервер, с которой он может и не справиться. Еще одним недостатков курсора на серверной стороне является то, что в отличие от курсоров на клиентской стороне, не поддерживается работа в пакетном режиме (batch cursor), а возможна работа только с единственной записью.
Конечно, поддерживают работу на клиентской и серверной стороне разные библиотеки курсоров. При работе на стороне клиента для обеспечения работы с курсором ADO вызывает специальную службу - Microsoft Cursor Service for OLE DB, поддерживающую единую функциональность для различных Провайдеров.
Для того чтобы обеспечить целостность данных в СУБД имеются специальные механизмы, позволяющие временно закрыть доступ к записям базы другим пользователям, пока один из пользователей корректирует их содержание. С одной стороны, возможность закрытия доступа совершенно необходима в некоторых ситуациях, например, чтобы не продать один и тот же билет на самолет или поезд разным пассажирам. С другой стороны, когда, например, в интернете сотни тысяч пользователей обращаются одновременно к базе данных, то закрытие данных существенно снижает общую производительность системы. Система ADO позволяет указывать Провайдеру, какой тип закрытия данных следует применять при работе с объектами Recordset. Конкретный Провайдер может не поддерживать все типы закрытия, в этом случае он будет поддерживать возможный ближайший тип закрытия. Вернемся теперь к рассмотрению свойств объекта Recordset и продолжим это рассмотрение со свойств, связанных с курсором.