Juri Shutenko Personal Homepage. Visual FoxPro.

CursorAdapter. Часть III. Создание CursorAdapter'а программно (ODBC)

Ну а теперь поработаем ручками.

Default settings that has been set by Createobject() function Честно говоря, большого смысла начинать описания с работы курсор-адаптера с родными курсорами VFP я не нахожу, так как в большей степени он предназначен для работы с источниками данных, отличающихся и по природе, и по технологии от курсоров и таблиц VFP. Поэтому вернемся, для начала, к MySQL, достаточно быстро развивающемуся серверу и уже прочно укрепившемуся в Интернет, как чуть-ли не основная база для приложений.
 
Так как работать мы будем через ODBC, нам необходим хэндл (handle) соединения с базой данных MySQL. Можно заготовить заранее DSN в панели мэнеджера ODBC, можно прописать строку соединения ручками. Поскольку все решили делать ручками, так пусть они и поработают.
 
Замечание: при написании этих статей использовались:

  • Apache Server /2.0.49 установленный на Windows 2000 Professional
  • MySQL Server 4.0.18-nt там же
  • База данных - реальная рабочая база данных "maardu"
Для начала пропишем строку соединения:
lcDSN="DRIVER=MySQL ODBC 3.51 Driver;"+;
   "UID=root;"+;
   "STMT=;"+;
   "OPTION=16;"+;
   "PASSWORD=;"+;
   "SERVER=localhost;"+;
   "DATABASE=maardu;"+;
   "DESC="
и получим хэндл соединения:
lnConnHandle=SQLSTRINGCONNECT(lcDSN)
Создадим объект - инстанцию класса CursorAdapter -используя стандартную функцию CREATEOBJECT().

lo_CA=CREATEOBJECT("CursorAdapter")
На скриншоте справа показаны все свойства по умолчанию, которые созданы при простой инициализации субстанции класса.
 
Прежде всего установим алиас для курсора который создаст Visual FoxPro в объекте CursorAdapter.
lo_CA.Alias="cTestMySQL"
Поскольку мы используем тип источника данных "ODBC", то и присвоим соответствущему свойству DataSourceType объекта указанный тип:
lo_CA.DataSourceType="ODBC"
Далее, необходимо передать полученный хэндл соединения объекту CursorAdapter. Это делается с помощью свойства DataSource, которому в данном случае мы присваиваем имя переменной памяти, в котором хэндл хранится.
lo_CA.DataSource=lnConnHandle
Теперь самое важное - что мы желаем получить из нашей базы - пусть это будут наимванования автобусных маршрутов, обслуживающих город. Они хранятся в поле "blnames" таблицы "buslines". Для выборки используется простая команда:
"Select blnames FROM buslines"
Эту команду мы должны поместить в свойство SelectCmd нашего объекта на базе класса CursorAdapter.
lo_CA.SelectCmd="Select blnames FROM buslines"
Ну вот, вроде все и подготовлено, осталось только как-то вытащить данные из таблицы в курсор, который нам создаст объект CursorAdapter. Для этого используется метод CursorFill этого объекта.
lo_CA.CursorFill
Теперь соберем все до кучи, откроем новый программный файл, скопируем полученный листинг (естественно, что имена баз, таблиц и полей вы должны использовать из своего сервера) и запустим. Я надеюсь, что последние три команды не нуждаются в комментарии:
lcDSN="DRIVER=MySQL ODBC 3.51 Driver;"+;
   "UID=root;"+;
   "STMT=;"+;
   "OPTION=16;"+;
   "PASSWORD=;"+;
   "SERVER=localhost;"+;
   "DATABASE=maardu;"+;
   "DESC="
lnConnHandle=SQLSTRINGCONNECT(lcDSN)

lo_CA=CREATEOBJECT("CursorAdapter")
lo_CA.Alias="Curfrommysql"
lo_CA.DataSourceType="ODBC"
lo_CA.DataSource=lnConnHandle
lo_CA.SelectCmd="Select blnames FROM buslines"
lo_CA.CursorFill
BROWSE
RELEASE lo_CA
SQLDISCONNECT(lnConnHandle)
И что же мы имеем в итоге? Такой вот результат.

Result for mentioned listing  execution

То есть для просмотра таблиц хватает. Однако надобно и добавлять, и удалять и обновлять.
 
Для начала займемся обновлением.
 
Для того, чтобы мы могли обновить данные в исходной таблице нам нужно указать значения для ряда свойств объекта CursorAdapter, a именно:

Вот здесь есть один нюанс. Если посмотреть на описание UpdateCmdDataSource, то там недвусмысленно сказано, что это может быть символьный тип даных, и в принципе, если используется машинный источник данных, то мы можем присвоить этому свойству строку с командой SQL - sqlstringconnect([dsn=MySQL2CA;]), где и укажем этот DSN. Предлагаемый построитель VFP для объекта CursorAdapter так и делает.
Далее сказано, что это может быть пустая строка или .Null. и в этом случае CursorAdapter будет использовать источник данных из свойства DataSource..
 
Вот она - тонкость. Если мы сделаем это, и не оставим значения этого свойства по умолчанию, а возьмем и явно присвоим пустую строку или .Null.,

lo_CA.UpdateCmdDataSource=""/.Null.

то при попытке обновления данных мы получим сообщение об ошибке ("Connection handle is invalid").

Для того, чтобы все это заработало есть два варианта:

  • мы вообще не упоминаем в коде ни UpdateCmdDataSource, ни UpdateCmdDataSourceType!
  • используем в коде оба свойства и присваиваем в обязательном порядке свойству UpdateCmdDataSourceType значение "ODBC" и свойству UpdateCmdDataSource уже созданный хэндл соединения.
Пусть это будет так:
lo_CA.UpdateCmdDataSourceType="ODBC"
lo_CA.UpdateCmdDataSource=lnConnHandle

В итоге, для используемой мною базы данных и таблицы фрагмент кода, отвечающего за обновление данных может выглядеть так:

lo_CA.Tables="buslines"
lo_CA.KeyFieldList="ID"
lo_CA.UpdateNameList="ID  buslines.id,BLNAMES buslines.blnames"
lo_CA.UpdatableFieldList="id,blnames"
lo_CA.UpdateCmdDataSourceType="ODBC"
lo_CA.UpdateCmdDataSource=lnConnHandle

или так:

lo_CA.Tables="buslines"
lo_CA.KeyFieldList="ID"
lo_CA.UpdateNameList="ID  buslines.id,BLNAMES buslines.blnames"
lo_CA.UpdatableFieldList="id,blnames"

и это два рабочих варианта.
 
Поскольку при работе с CursorAdapter используется буфферизация, то необходимо позаботиться об установке SET MULTILOCKS и установить ее в ON

Новый листинг программы в предпочтительном варианте будет выглядеть так:

SET MULTILOCKS ON

lcDSN="DRIVER=MySQL ODBC 3.51 Driver;"+;
   "UID=root;"+;
   "STMT=;"+;
   "OPTION=16;"+;
   "PASSWORD=;"+;
   "SERVER=localhost;"+;
   "DATABASE=maardu;"+;
   "DESC="
lnConnHandle=SQLSTRINGCONNECT(lcDSN)
? lnConnHandle
* вставим также код проверки работы этой программы,
* при необходимости можно снять комментарий и посмотреть
* что имеем в результате
*!*SQLEXEC(lnConnHandle, "SELECT BUSLINES.* FROM BUSLINES")
*!*RETURN

lo_CA=CREATEOBJECT("CursorAdapter")
lo_CA.Alias="Curfrommysql"
lo_CA.DataSourceType="ODBC"
lo_CA.DataSource=lnConnHandle
lo_CA.SelectCmd="Select buslines.* from buslines"
lo_CA.Tables="buslines"
lo_CA.KeyFieldList="ID"
lo_CA.UpdateNameList="ID  buslines.id,BLNAMES buslines.blnames"
lo_CA.UpdatableFieldList="id,blnames"

llCursorFilled=lo_CA.CursorFill()
? "Is cursor filled? "
?? llCursorFilled
BROWSE
RELEASE lo_CA
SQLDISCONNECT(lnConnHandle)

А что же с удалением/вставкой? Измените явно тип обновления:

lo_CA.UpdateType=2

То есть данные должны обновляться через удаление/вставку.... Работает.
 
Стало быть для удаления записей и вставки новых больше ничего не надо? Именно так. В окне Browse пометьте запись на удаление. Запустите еще раз программу. Удалено. Запустите еще раз программу. Вставьте новую запись... Вставлена. То есть для операций над данными необходимо прописать только 4 свойства:

И это действительно так. Будет продолжено!!!

Селектор для быстрого перехода на сайты, связанные с Visual FoxPro.