Опубликован: 13.09.2006 | Уровень: для всех | Доступ: свободно
Лекция 6:

Объекты 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.

Ольга Гафарова
Ольга Гафарова
Непонятен ход решения задачи
Серегй Лушников
Серегй Лушников
Может ли объект Recordset быть потомком объекта Record?
Геннадий Шестаков
Геннадий Шестаков
Беларусь, Орша
Светлана Ведяева
Светлана Ведяева
Россия, Саратов