Непонятен ход решения задачи |
Объекты ADO (продолжение)
Методы объекта Stream
Рассмотрим теперь методы объекта Stream:
- Sub Cancel(). Как и для других объектов ADO позволяет прервать выполнение асинхронных операций над объектом Stream.
- Sub Close(). Закрывает объект Stream.
- Sub CopyTo(DestStream As Stream, [CharNumber As Long = -1]). Позволяет создать копию потока. Объект, представляющий точку назначения, должен быть открыт. Уточню семантику. Метод копирует, начиная с текущей позиции, символы (байты), число которых задано вторым параметром. Если раньше встретится конец потока, то копирование идет от текущей точки до конца потока. Если в потоке назначения есть символы, то они остаются, следуя после скопированной части. Чтобы произвести их отсечение, следует вызвать метод SetEOS для потока назначения.
- Sub Flush(). Принуждает оставаться содержимому потока в ADO буфере того базового объекта, с которым ассоциирован объект Stream.
- Sub LoadFromFile(FileName As String), Sub SaveToFile(FileName As String, [Options As SaveOptionsEnum = adSaveCreateNotExist]). Эти методы позволяют загрузить содержимое файла в поток и сохранить поток в файле.
- Sub Open([Source], [Mode As ConnectModeEnum = adModeUnknown], [Options As StreamOpenOptionsEnum = adOpenStreamUnspecified], [UserName As String], [Password As String]). Один из основных методов, создающий поток. Первый параметр задает источник данных. Это может быть абсолютный URL-адрес, в этом случае параметр имеет следующий синтаксис "URL = scheme://server/folder". Адрес может задавать узел в структуре дерева каталогов файловой системы или системе электронной почты. Источник может быть ссылкой на открытый объект Record. Объект Stream ассоциируется с потоком по умолчанию этого объекта. В наших примерах использовался именно такой способ создания объекта Stream. Источник может и не указываться, тогда создается объект Stream, не ассоциированный с потоком другого объекта. Данные в него могут поступать, например, при загрузке из файла при вызове метода LoadFropmFile или при создании копии потока.
- Function Read([NumBytes As Long = -1]), Function ReadText([NumChars As Long = -1]) As String, Sub Write(Buffer), Sub WriteText(Data As String, [Options As StreamWriteEnum = adWriteChar]). Эта группа методов позволяет читать и писать в поток заданное число байтов (символов). Методы Read и Write, работающие с байтами, используют переменную типа Variant, а методы ReadText и WriteText используют переменную типа String. Заметьте, речь идет о потоке, поэтому все операции по чтению и записи идут только в одном направлении - от начала к концу потока. Если требуется несколько проходов, то следует заново переоткрывать поток.
- Sub SetEOS(). Метод устанавливает значение свойства EOS в True, а, главное, делает текущую позицию концом потока, отсекая все оставшиеся символы. Поскольку методы Write, WriteText, CopyTo не производят отсечения, то, чаще всего, они используются в комбинации с методом SetEOS.
- Sub SkipLine(). Позволяет пропустить одну строку при чтении текстового файла. Используется в цикле, когда нужно пропустить несколько строк.
Коллекция Fields и объект Field
Свойство Fields объектов Recordset и Record возвращает одноименную коллекцию, элементами которой являются объекты Field, представляющие содержательно поля записи или столбцы данных, пользуясь табличной терминологией. Об этих объектах уже было сказано немало, так что я постараюсь долго на них не останавливаться.
У коллекции Fields всего два традиционных для всех коллекций свойства - Count и Item, а вот методов гораздо больше. Наряду с методами, о которых я уже говорил при рассмотрении других объектов ADO, такими как Delete, Refresh, Update, CancelUpdate, имеется два специфических метода:
- Sub Append(Name As String, Type As DataTypeEnum, [DefinedSize As Long], [Attrib As FieldAttributeEnum = adFldUnspecified], [FieldValue]). Метод позволяет создать новое поле и присоединить его к коллекции. При определении поля задается необходимая информация - имя поля, его тип, определяемый размер данных, атрибуты и, возможно, значение, если речь идет об объекте Record. При работе с полями объекта Recordset они должны быть созданы при закрытом объекте Recordset, после этого объект можно открыть и присвоить значения созданным полям. Присоединять поля к объекту Recordset можно только в том случае, если он закрыт и для него не установлено свойство ActiveConnection. Поскольку в реальных ситуациях эти объекты появляются при выполнении метода Open или Execute, когда соединение с источником данных установлено, то присоединять новые поля к объекту Recordset таким способом не удается. Для изменения структуры базы данных используются обычно объекты ADOX, которые будут рассмотрены ниже. Так что, чаще всего, метод Append применяется при работе с полями объекта Record. Добавлять поле к этому объекту можно и тогда, когда он открыт, при добавлении можно указать и значение поля. После добавления поля следует вызвать метод Update, чтобы сохранить сделанные изменения.
- Sub Resync([ResyncValues As ResyncEnum = adResyncAllValues]). Позволяет обновить значения всех полей у записей, хранящихся в буфере.
Свойства объекта Field
Объект Field задает поле записи. С помощью его свойств можно определить характеристики поля - тип, значение, формат и установить эти значения при формировании новых полей, присоединяемых к записи. Рассмотрим все по порядку:
- Property Name As String. Задает имя поля.
- Property ActualSize As Long, Property DefinedSize As Long. Первое свойство позволяет определить фактический размер хранимого в поле значения. Оно имеет статус только для чтения. В случае, если ADO не может определить по каким либо причинам истинный размер значения, в качестве результата возвращается константа adUnknown. Второе свойство задает метаданные - размер поля, заданный в момент его определения. Его статус - "чтение/запись". Размер всегда задается в байтах.
- Property Precision As Byte. Для числовых полей указывает максимальное число цифр, используемых для представления значения.
- Property NumericScale As Byte. Для числовых полей указывает число цифр после запятой, используемых для представления значения.
- Property Type As DataTypeEnum. Задает тип поля. Приведу значения некоторых констант из перечисления: adInteger = 3, adVarWChar = 202 (для строковых полей), adCurrency = 6, adLongVarWChar = 203 (для поля Memo).
- Property DataFormat As Unknown. Это свойство, которое, судя по названию, должно задавать формат данных, отсутствует в версии ADO 2.6. Хотя оно присутствует в предыдущей версии 2.5, но возвращает в качестве результата ссылку на пустой объект, так что не стоит пытаться его использовать.
- Property Status As Long. Возвращает статус поля, позволяющий, например, определить, было ли поле нормально добавлено или удалено из записи. Значения свойства задаются константами из перечисления FieldStatusEnum. Вот некоторые значения констант: adFieldAlreadyExists, adFieldOK, adFieldPendingInsert, adFieldPendingDelete, adFieldCantCreate. Анализ статуса поля, позволяет определить, что произошло при выполнении операций над тем или иным полем.
- Property OriginalValue As Variant, Property UnderlyingValue As Variant, Property Value As Variant. Все эти свойства задают значение поля в разных его ипостасях - значение поля в записи до его изменений, значение поля в базе данных, текущее значение поля в записи.
- Property Attributes As Long. Свойство задает маску, определяющую характеристики поля. Значение представляет сумму констант из перечисления FieldAttributeEnum. Вот лишь некоторые значения этих констант: adFldKeyColumn, adFldLong, adFldIsChapter, adFldUpdatable.
- Property Properties As Properties. Возвращает коллекцию свойств поля.
Методы объекта Field
У этого объекта имеется всего два метода:
- Sub AppendChunk(Data). Этот метод позволяет формировать "длинные" значения полей, присоединяя очередную порцию данных к текстовому или двоичному значению поля. При первом вызове метода значение, заданное аргументом Data переписывается в поле и становится его значением, при последующих вызовах значение аргумента Data добавляется к значению, хранимому в поле. Метод не применим к полям объекта Record. Аргумент Data задается переменной типа Variant и содержит добавляемые данные. Заметьте, для того чтобы можно было использовать этот метод бит adFldLong в свойстве Attributes должен быть установлен - иметь значение True.
- Function GetChunk(Length As Long). Метод позволяет получить все значение или нужную порцию большого текста или двоичного кода, хранящегося в поле. Длина порции устанавливается параметром Length. Возвращаемый результат является переменной типа Variant.
Приведу теперь пример, в котором анализируются поля объекта Recordset. По изложенным выше причинам я не стал пытаться вводить новые поля и ограничился получением информации о свойствах уже существующих полей записи. Вот код соответствующей процедуры:
Public Sub CreateField() 'Процедура печатает информацию о существующих полях записи Dim fld As Field Dim df As Object 'Создать соединение CreateConnection 'Создать команду 'задание свойств объекта Command Cmd1.ActiveConnection = Con1 Cmd1.CommandText = "Select * From [Книги]" Cmd1.CommandType = adCmdText 'Открытие обновляемого объекта Recordset With Rst1 .Open Source:=Cmd1, CursorType:=adOpenDynamic, _ LockType:=adLockOptimistic .MoveFirst Do While Not .EOF 'Печать данных о полях записи набора If !Название = "Офисное программирование" Then For Each fld In .Fields With fld Debug.Print "Имя поля ", .Name Debug.Print "Фактический размер поля =", .ActualSize Debug.Print "Определяемый размер поля =", .DefinedSize Debug.Print "Точность", .Precision Debug.Print "Число цифр после запятой в числовых полях -", _ .NumericScale Debug.Print "Тип поля", .Type Set df = .DataFormat If df Is Nothing Then Debug.Print "объект - Формат данных -не определен " End If Debug.Print "Статус", .Status Debug.Print "Значение поля до его изменений ", .OriginalValue Debug.Print "Текущее значение в базе данных", .UnderlyingValue Debug.Print "Текущее значение поля в наборе", .Value Debug.Print "Атрибуты =", .Attributes Debug.Print "Число свойств =", .Properties.Count Debug.Print "Имя и значение первого свойства - ", _ .Properties(1).Name, .Properties(1).Value End With Next fld End If .MoveNext Loop 'попытка изменить характеристики полей 'закрываем объект Recordset .Close Set fld = .Fields("Год издания") With fld .DefinedSize = 8 .Type = adDecimal End With '.Fields.Update End With End Sub
Приведу краткий комментарий:
- Для выбранной записи из набора в окне отладки я печатаю значения всех характеристик для каждого поля записи.
- Свойство Data Format возвращает ссылку на пустой объект.
- Попытка изменить метаданные, путем изменения таких характеристик поля, как его тип или определяемый размер, не приводит к успеху. Хотя при закрытом объекте Recordset изменение значений этих характеристик возможно, но метод Fields.Update в данном контексте не работает, по этой причине он закомментирован.
Подведем теперь некоторые итоги. Вот что можно делать с объектом Field:
- Свойство Name позволяет вернуть имя поля, но не позволяет изменить это имя.
- Свойство Value позволяет не только получить значение поля, но и изменить его.
- Свойства Type, Precision, NumericScale, DefinedSize позволяют получить, но не изменить метаданные, задающие соответствующие характеристики поля.
- Свойство ActualSize позволяет определить фактический размер хранимого в поле значения.
- Определить, какой тип функциональности поддерживается данным полем, используя свойства Attributes и Properties.
- Работать с длинными полями, формируя или получая их значения порциями, используя методы AppendChunk и GetChunk.
- Все свойства, задающие метаданные, доступны для изменения при закрытом объекте Recordset, что может быть полезно при динамическом конструировании форм.
Коллекция Parameters и объект Parameter
Объект Command может определять запрос или хранимую процедуру с параметрами. А посему этот объект имеет свойство Parameters, возвращающее одноименную коллекцию, элементами которой являются объекты Parameter. Содержательно, каждый из этих объектов определяет параметр - входной или выходной, который передается или возвращается при вызове хранимой процедуры. Я уже приводил пример вызова запроса с параметром, где появлялись эти объекты.
Коллекция Parameters устроена достаточно просто. У нее всего два типичных свойства - Item и Count. У коллекции три метода, которые также появлялись в нашем рассмотрении. Вот эти методы:
- Sub Append(Object As Object). Метод позволяет присоединить объект Parameter, заданный аргументом, к коллекции. Обычно присоединяемый объект создается методом CreateParameter объекта Command. В процедуре CreateCommands, приведенной в предыдущей главе, продемонстрировано применение методов CreateParameter и Append.
- Sub Delete(Index). Метод позволяет удалить из коллекции параметр, по имени или порядковому номеру, указываемому в аргументе Index.
- Sub Refresh(). Позволяет обновить содержимое коллекции, получая информацию о параметрах из хранимой процедуры.
Свойства и методы объекта Parameter
Поскольку все свойства и методы объекта Parameter так или иначе уже появлялись в нашем описании, то я их только перечислю, не приводя подробного описания. Вот список свойств этого объекта: Attributes, Direction, Name, NumericScale, Precision, Properties, Size, Type, Value. Метод у этого объекта всего один - AppendChunk, - и он тоже был описан при рассмотрении объекта Field.
Используя свойства и методы коллекции и самого объекта Parameter можно делать следующее:
- Свойство Name позволяет устанавливать и возвращать имя параметра, а свойство Value - его значение.
- Свойства Attributes, Direction, Precision, NumericScale, Size и Type позволяют устанавливать и возвращать различные характеристики параметра.
- Свойство Direction позволяет указать, является ли параметр входным, выходным, входным-выходным или представляет возвращаемое процедурой значение. Поскольку не все Провайдеры могут установить направление передаваемых параметров, то в таких ситуациях необходимо программно устанавливать значение этого свойства перед тем, как вызывать хранимую процедуру или параметризованный запрос.
- Метод AppendChunk позволяет передавать параметру порции двоичных или символьных данных в случае длинных значений параметра.
- Получать доступ к специфическим для Провайдера атрибутам, вызывая свойство Properties.
- Зная свойства параметров, ассоциированных с хранимой процедурой создать параметр методом CreateParameter и присоединить его к коллекции, используя ее метод Append. Это позволяет избежать лишних вызовов метода Refresh для получения нужной информации от Провайдера и тем самым снизить нагрузку на передачу данных.
Коллекция Properties и объект Property
Многие из объектов ADO имеют свойство Properties, возвращающее одноименную коллекцию элементов Property. Поскольку каждый объект обладает набором свойств, то возникает естественный вопрос, зачем необходимо еще и свойство Properties, которое тоже задает свойства. Дело в том, что свойства разделяются на встроенные и динамические. Динамические свойства зависят от специфики Провайдера, - они то и составляют коллекцию Properties. Каждый объект этой коллекции описывает то или иное динамическое свойство объекта ADO, зависящее от специфики Провайдера и доступное, естественно, только тогда, когда объект открыт. Добавлять или удалять элементы этой коллекции невозможно, - это прерогатива Провайдера.
С объектной точки зрения коллекция Properties устроена очень просто - у нее всего два типичных свойства: Item, Count и один метод Refresh. Также просто устроен и объект Property - у него всего четыре свойства: Name, Type, Value, Attributes. Они задают имя, тип, значение и некоторые дополнительные характеристики. Примеры работы с этими объектами уже приводились.
На этом я завершаю утомительное описание объектов ADO. Но нам предстоит еще хотя бы вкратце познакомиться с объектами ADOX.