Адаптируйте свои курсоры к CursorAdapters

Дуг Хенниг

Класс CursorAdapter — одна из самых важных новых функций в VFP 8, поскольку он обеспечивает простой в использовании и согласованный интерфейс для удаленных данных. В статье этого месяца Дуг исследует CursorAdapters и то, как они работают. В следующем месяце мы рассмотрим некоторые дополнительные способы их использования.

Все больше и больше разработчиков VFP хранят свои данные не в таблицах VFP, а в SQL Server или Oracle. Этому есть множество причин, в том числе хрупкость таблиц VFP (как предполагаемых, так и реальных), безопасность, размер базы данных и корпоративные стандарты. Microsoft упрощала доступ к данным, не относящимся к VFP, с каждым выпуском и даже поощряла это, включив MSDE (Microsoft Data Engine, бесплатную урезанную версию SQL Server) на компакт-диске VFP 7.
Однако доступ к серверной базе данных никогда не был таким простым, как использование таблиц VFP. Кроме того, для этого можно использовать различные механизмы:
  • Удаленные представления, основанные на соединениях ODBC.
  • Функции транзита SQL (SPT), такие как SQLCONNECT(), SQLEXEC() и SQLDISCONNECT(), которые также основаны на соединениях ODBC.
  • Объекты данных ActiveX или ADO, которые предоставляют объектно-ориентированный интерфейс для поставщиков OLE DB для механизмов баз данных.
  • XML, который представляет собой облегченный, независимый от платформы механизм передачи данных.
Если вы когда-нибудь работали с этими механизмами, вы, вероятно, заметили, что каждый из них полностью отличается от других. Это означает, что у вас есть новая кривая обучения с каждым из них, и преобразование существующего приложения с одного механизма на другой — нетривиальная задача.
VFP 8 делает доступ к удаленным данным намного проще, чем в более ранних версиях, благодаря новому базовому классу: CursorAdapter. На мой взгляд, CursorAdapter — одна из самых больших новых функций в VFP 8. Причины, по которым я думаю, что это так круто:
  • Это упрощает использование ODBC, ADO или XML, даже если вы не очень хорошо знакомы с этими технологиями.
  • Он обеспечивает согласованный интерфейс для удаленных данных независимо от выбранного вами механизма.
  • Это позволяет легко переключаться с одного механизма на другой.
Вот пример последнего пункта. Предположим, у вас есть приложение, которое использует ODBC с CursorAdapters для доступа к данным SQL Server, и по какой-то причине вы хотите перейти на использование ADO.
Все, что вам нужно сделать, это изменить свойство DataSourceType CursorAdapters и изменить подключение к серверной базе данных, и все готово. Остальные компоненты приложения об этом не знают и не заботятся; они по-прежнему видят один и тот же курсор независимо от механизма, используемого для доступа к данным.
PEM
Давайте начнем изучение CursorAdapter с рассмотрения его свойств, событий и методов (PEM). Мы не будем обсуждать здесь все PEM, а только наиболее важные. Полный список см. в документации VFP 8.

DataSourceType - Тип источника данных
Это важное свойство: оно определяет поведение класса и типы значений, которые следует вводить в некоторые другие свойства. Допустимые варианты: «Native», что означает, что вы используете собственные таблицы, или «ODBC», «ADO» или «XML», что означает, что вы используете соответствующий механизм для доступа к данным.

DataSource - Источник данных
Это средство доступа к данным. VFP игнорирует это свойство, если для DataSourceType задано значение «Native» или «XML». Для ODBC установите для DataSource допустимый дескриптор соединения ODBC (это означает, что вы должны сами управлять соединением). В случае ADO DataSource должен быть набором записей ADO, в котором объект ActiveConnection установлен на открытый объект соединения ADO (опять же, вы должны управлять этим самостоятельно).

UseDEDataSource - использовать источник данных из DataEnvironment
Если для этого свойства задано значение .T. (по умолчанию .F.), вы можете оставить свойства DataSourceType и DataSource в покое, так как вместо этого CursorAdapter будет использовать свойства DataEnvironment (VFP 8 также добавляет DataSourceType и DataSource в класс DataEnvironment). Пример, когда вы установили бы это в .T. это когда вы хотите, чтобы все CursorAdapters в DataEnvironment использовали одно и то же соединение ODBC.

SelectCmd - команда выборки
Во всех случаях, кроме XML, это команда SQL SELECT, используемая для извлечения данных. В случае XML это может быть допустимая строка XML, которую можно преобразовать в курсор (с помощью внутреннего вызова XMLTOCURSOR()), или выражение (такое как UDF), возвращающее допустимую строку XML.

CursorSchema - схема курсора
Это свойство содержит структуру курсора в том же формате, который вы использовали бы в команде CREATE CURSOR (все, что заключено в круглые скобки в такой команде). Вот пример: CUST_ID C(6), COMPANY C(30), CONTACT C(30), CITY C(25). Хотя можно оставить это поле пустым и указать CursorAdapter’у определить структуру при создании курсора, он работает лучше, если вы заполните CursorSchema. Во-первых, если CursorSchema пуста или неверна, вы либо получите ошибки при открытии DataEnvironment формы, иначе вы не сможете перетаскивать поля из CursorAdapter в форму для создания элементов управления. К счастью, CursorAdapter Builder, поставляемый с VFP, может автоматически заполнить это за вас.

AllowDelete, AllowInsert, AllowUpdate и SendUpdates - разрешить удаление, вставку, обновление и послать обновления
Эти свойства, которые по умолчанию имеют значение .T., определяют, могут ли выполняться операции удаления, вставки и обновления, а также отправляются ли изменения в источник данных.

KeyFieldList, Tables, UpdatableFieldList и UpdateNameList - список ключевых полей, таблицы, список обновляемых полей и список обновляемых имен
Эти свойства, которые служат той же цели, что и одноименные свойства CURSORSETPROP() для представлений, необходимы, если вы хотите, чтобы VFP автоматически обновлял источник данных изменениями, внесенными в курсор. KeyFieldList — это разделенный запятыми список полей (без псевдонимов), которые составляют первичный ключ для курсора. Tables — список таблиц, разделенных запятыми. UpdatableFieldList — это разделенный запятыми список полей (без псевдонимов), которые можно обновить. UpdateNameList — это список с разделителями-запятыми, в котором имена полей в курсоре сопоставляются с именами полей в таблице. Формат UpdateNameList следующий: CURSORFIELDNAME1 TABLE.FIELDNAME1, CURSORFIELDNAME2 TABLE.FIELDNAME2, ... Обратите внимание, что даже если UpdatableFieldList не содержит имя первичного ключа таблицы (поскольку вы не хотите, чтобы это поле обновлялось) , он все еще должен существовать в UpdateNameList, иначе обновления не будут работать.

*Cmd, *CmdDataSource, *CmdDataSourceType
Если вы хотите конкретно управлять тем, как VFP удаляет, вставляет или обновляет записи в источнике данных, вы можете назначить соответствующие значения этим наборам свойств (замените * выше на Delete, Insert и Update).

CursorFill(UseCursorSchema, NoData, Options, Source) - заполнить курсор данными
Этот метод создает курсор и заполняет его данными из источника данных (хотя вы можете передать .T. для параметра NoData, чтобы создать пустой курсор). Пройти .Т. чтобы первый параметр использовал схему, определенную в CursorSchema или .F. создать соответствующую структуру из источника данных (на мой взгляд, это обратное поведение). MULTILOCKS должен быть включен, иначе этот метод не сработает. Если CursorFill по какой-либо причине не работает, он возвращает .F. а не выдаёт ошибку; используйте AERROR(), чтобы определить, что пошло не так (хотя будьте готовы к некоторому копанию, поскольку сообщения об ошибках, которые вы часто получаете, недостаточно конкретны, чтобы точно сказать вам, в чем проблема).

CursorRefresh() - обновить курсор
Этот метод похож на функцию REQUERY(): он обновляет содержимое курсора.

Before*() и After*()
Почти у каждого метода и события есть до и после событий-перехватчиков, которые позволяют настроить поведение CursorAdapter. Например, в AfterCursorFill вы можете создавать индексы для курсора, чтобы они всегда были доступны. В случае событий «До» вы можете вернуть .F. чтобы предотвратить действие, которое его запускает (это похоже на события базы данных).

Пример

Вот пример (CursorAdapterExample.prg, включенный в загружаемые материалы для подписчиков этого месяца), который извлекает определенные поля для бразильских клиентов из таблицы Customers в базе данных Northwind, поставляемой с SQL Server. Курсор можно обновлять, поэтому, если вы внесете изменения в курсор, закроете его, а затем снова запустите программу, вы увидите, что ваши изменения были сохранены в бэкэнде.

    
  
local lcConnString, ;  
         loCursor as CursorAdapter, ;  
         laErrors[1]  
  lcConnString = 'driver=SQL Server;server=(local);' + ;  
         'database=Northwind;uid=sa;pwd=;trusted_connection=no'  
 * change password to appropriate value for your database  
  loCursor = createobject('CursorAdapter')  
  with loCursor  
         .Alias = 'Customers'  
         .DataSourceType = 'ODBC'  
         .DataSource = sqlstringconnect(lcConnString)  
         .SelectCmd = "select CUSTOMERID, " + ;  
               "COMPANYNAME, CONTACTNAME from CUSTOMERS " + ;  
               "where COUNTRY = 'Brazil'"  
         .KeyFieldList = 'CUSTOMERID'  
         .Tables = 'CUSTOMERS'  
         .UpdatableFieldList = 'CUSTOMERID, COMPANYNAME, ' + ;  
               'CONTACTNAME'  
         .UpdateNameList = ;  
               'CUSTOMERID CUSTOMERS.CUSTOMERID, ' + ;  
               'COMPANYNAME CUSTOMERS.COMPANYNAME, ' + ;  
               'CONTACTNAME CUSTOMERS.CONTACTNAME'  
         if .CursorFill()  
               browse  
         else  
               aerror(laErrors)  
               messagebox(laErrors[2])  
         endif .CursorFill()  
  endwith

DataEnvironment и изменения формы

Для поддержки нового класса CursorAdapter в классы DataEnvironment и Form и их конструкторы внесено несколько изменений.

Во-первых, как я упоминал ранее, класс DataEnvironment теперь имеет свойства DataSource и DataSourceType. Он не использует эти свойства сам по себе, но они используются любым членом CursorAdapter, для которого UseDEDataSource установлено в .T. Во-вторых, теперь вы можете визуально создавать подклассы DataEnvironment с помощью конструктора классов (ух ты!).

Что касается форм, теперь вы можете указать подкласс DataEnvironment для использования, установив новые свойства DEClass и DEClassLibrary. Если вы сделаете это, все, что вы сделали с существующей средой DataEnvironment (курсоры, код и т. д.), будет потеряно, но, по крайней мере, вас сначала предупредят. Интересная новая функция форм, которая в чем-то связана, — это свойство BindControls; установив это на .F. в окне свойств означает, что VFP не будет пытаться привязать данные к элементам управления во время инициализации, только если вы установите для BindControls значение .T. Для чего это нужно? Ну, сколько раз вы проклинали, что параметры передаются в Init, который срабатывает после того, как все элементы управления были инициализированы и привязаны к своим источникам управления? Что делать, если вы хотите передать параметр в форму, которая сообщает ей, какую таблицу открывать, или другие вещи, влияющие на ControlSource? Это новое свойство делает эту проблему проще простого.

Преимущества

Есть много веских причин использовать CursorAdapters вместо удаленных представлений, SPT, ADO или XML.

  • Каждый механизм имеет свой интерфейс. С удаленными представлениями вы открываете их с помощью команды USE. В SPT вы используете SQLCONNECT() и SQLEXEC() для создания курсора. С помощью ADO вы создаете объекты ADO Connection и RecordSet (и, возможно, объект Command, в зависимости от того, как вы извлекаете данные) и вызываете их методы Open. При использовании XML вы сначала откуда-то получаете строку XML (например, из компонента COM в многоуровневом приложении или из SQL Server через SQLXML), а затем используете XMLTOCURSOR() для преобразования ее в курсор VFP. Запись обновлений на серверную часть также отличается для каждого механизма. Таким образом, при переходе от одного механизма к другому у вас появляются новые методы для изучения, плюс вам, возможно, придется переписать большую часть существующего кода.

CursorAdapter’ы имеют согласованный интерфейс независимо от того, какой механизм вы используете для извлечения данных. Вы устанавливаете различные свойства объекта и вызываете метод CursorFill для извлечения данных, работаете с курсором, как с любым другим курсором VFP, а затем вызываете TABLEUPDATE() (или позволяете VFP обрабатывать его автоматически), чтобы записать изменения обратно.

  • В среде разработки часто требуется открыть курсор из командного окна, чтобы просмотреть его содержимое. Это легко для удаленных представлений (просто USE представление), но гораздо больше работы для SPT, ADO и XML.

В зависимости от того, как он настроен (например, если он полностью автономен), открытие курсора из подкласса CursorAdapter может быть почти таким же простым, как открытие удаленного представления: вы просто создаете экземпляр подкласса и вызываете метод CursorFill. Вы даже можете вызвать это из Init, чтобы сделать это одноэтапной операцией.

  • Увеличение существующего приложения может быть относительно простым с удаленными представлениями: вы заменяете существующие объекты Cursor, которые указывают на локальные таблицы или представления в DataEnvironment, на те, которые вместо этого ссылаются на удаленные представления. При использовании SPT, ADO и XML вам придется полностью переоснастить свои схемы доступа к данным.

Увеличить размер существующего приложения для использования CursorAdapters так же просто, как и с удаленными представлениями; вместо этого вы просто заменяете объекты Cursor объектами CursorAdapter.

  • С удаленными представлениями легко работать в дизайнерах форм и отчетов. Вы можете добавить его в DataEnvironment, а затем воспользоваться преимуществами визуальной поддержки, предоставляемой DataEnvironment: перетаскиванием полей для автоматического создания элементов управления, простой привязкой элемента управления к полю путем выбора его из поля со списком в окне свойств и т.д. SPT, ADO и XML не имеют такой визуальной поддержки.

CursorAdapters имеют ту же поддержку в DataEnvironment, что и удаленные представления.

  • Удаленные представления легко создавать с помощью дизайнера представлений. Хотя в прошлом у него были серьезные ограничения, особенно при работе с представлениями, объединяющими более двух таблиц, VFP 8 устраняет большинство этих проблем и добавляет гораздо больше возможностей, таких как двустороннее редактирование: вы можете изменить код в окне SQL и увидеть эти изменения, отраженные в визуальной части дизайнера представлений. С SPT, ADO и XML это требует больше работы, так как вам нужно кодировать все: создание и закрытие соединения, выполнение операторов SQL SELECT и так далее.

VFP 8 включает в себя CursorAdapter Builder, который быстро устанавливает свойства, необходимые для извлечения и обновления данных. Он даже включает построитель SelectCmd, который, хотя и не так нагляден, как View Designer, позволяет вам выбирать, какие поля следует извлекать из удаленных таблиц, используя элемент управления «перемещение».

  • Базу данных бэкэнда легко обновлять с помощью изменений, сделанных в удаленных представлениях и наборах записей ADO. Предполагая, что свойства представления настроены правильно, вы просто вызываете TABLEUPDATE(). В случае ADO вы вызываете RecordSet.Update() или UpdateBatch(). С SPT и XML у вас есть куча ручной работы, чтобы передать обновления обратно.

Как мы видели ранее, выполнение обновлений с помощью CursorAdapter может быть таким же простым, как установка нескольких свойств, чтобы VFP выполнял всю работу, или вы можете иметь большую гибкость, указав, как обрабатываются удаления, вставки и обновления.

  • Поскольку результирующий набор, созданный удаленными представлениями и SPT, представляет собой курсоры VFP, их можно использовать где угодно в VFP: в GRID, отчете, обработке в цикле SCAN и т. д. ADO и XML, с другой стороны, должны быть преобразованы в курсоры, прежде чем их можно будет использовать таким образом, что усложняет и увеличивает время обработки вашего приложения.

Результирующий набор CursorAdapter представляет собой курсор VFP, поэтому он имеет те же преимущества, что и удаленные представления и SPT. Более того, вы получаете курсор VFP, даже если источником данных являются ADO и XML, потому что CursorAdapter автоматически позаботится о преобразовании в курсор и из него.

  • Поскольку оператор SQL SELECT удаленного представления определен заранее, вы не можете изменить его на лету. Хотя это нормально для обычной формы ввода данных, это может быть проблемой для запросов и отчетов. Возможно, вам придется создать несколько представлений из одного и того же набора данных, каждое из которых отличается выбранными полями, структурой предложения WHERE и т. д. Это не проблема с SPT, ADO или XML.

CursorAdapters не страдают от этой проблемы: вы можете легко изменить свойство SelectCmd, чтобы изменить, какие данные извлекаются и как.

  • Вы не можете вызвать хранимую процедуру из удаленного представления, поэтому удаленному представлению необходим прямой доступ к базовым таблицам. Это может быть проблема с администраторами базы данных вашего приложения; некоторые администраторы баз данных считают, что доступ к данным должен осуществляться только через хранимые процедуры из соображений безопасности и по другим причинам. Кроме того, поскольку они предварительно скомпилированы на сервере, хранимые процедуры часто выполняются значительно быстрее, чем операторы SQL SELECT. С помощью SPT, ADO и XML вы можете при необходимости вызывать хранимые процедуры.

CursorAdapters также может использовать хранимые процедуры, просто установив SelectCmd по мере необходимости.

  • Удаленные представления живут в контейнере базы данных, так что это еще один набор файлов, которые вам нужно поддерживать и устанавливать в системе клиента. Кроме того, когда вы открываете представление, VFP пытается заблокировать записи представления в DBC, даже если это ненадолго. Это может вызвать конкуренцию в загруженных приложениях, когда несколько пользователей могут одновременно пытаться открыть форму. Несмотря на то, что существуют обходные пути (копирование DBC на локальную рабочую станцию и использование ее, или, в VFP 7 и более поздних версиях, использование SET REPROCESS SYSTEM для увеличения времени ожидания блокировки), это то, что вам нужно запланировать. Еще одна проблема: если вы используете представление SELECT * для извлечения всех полей из определенной таблицы, а структура этой таблицы на сервере изменяется, представление недействительно и должно быть создано заново. Поскольку они не имеют ничего общего с DBC, ни одна из них не является проблемой для SPT, ADO и XML.

Поскольку они не живут в DBC, CursorAdapters также не имеют этих проблем.

  • Поскольку они работают только с ODBC, удаленные представления и SPT застряли в модели прямого подключения данных «клиент-сервер». ADO и XML — предпочтительные механизмы для передачи данных между уровнями в многоуровневом приложении.

Поскольку CursorAdapters может создавать курсоры VFP из ADO или XML, они идеально подходят для использования на уровне пользовательского интерфейса многоуровневого приложения.

Резюме

Я думаю, что CursorAdapter — одно из самых больших и захватывающих улучшений в VFP 8, потому что он обеспечивает согласованный и простой в использовании интерфейс для удаленных данных, а также, как мы увидим в следующих статьях, он позволяет нам создавать повторно используемые классы данных.  В следующем месяце мы рассмотрим особенности доступа к исходным или удаленным данным с помощью ODBC, ADO и XML. В следующем месяце мы рассмотрим создание повторно используемых классов данных и обсудим, как использовать CursorAdapters в отчетах.

 

Дуг Хенниг является партнером Stonefield Systems Group Inc. Он является автором отмеченных наградами инструментов Stonefield Database Toolkit (SDT) и Stonefield Query, соавтором книг «Что нового в Visual FoxPro 7.0» и «Руководства хакера по Visual FoxPro». 7.0», как от Hentzenwerke Publishing, так и от автора «Словаря данных Visual FoxPro» в серии Pros Talk Visual FoxPro от Pinnacle Publishing. Он был техническим редактором «Руководства хакера по Visual FoxPro 6.0» и «Основы» издательства Hentzenwerke Publishing. Дуг выступал на каждой конференции разработчиков Microsoft FoxPro (DevCon) с 1997 года, а также на пользовательских группах и конференциях разработчиков по всей Северной Америке. Он является Microsoft Most Valuable Professional (MVP) и Certified Professional (MCP). Интернет: www.stonefield.com и www.stonefieldquery.com Электронная почта: dhennig@stonefield.com

(Автор перевода Михаил Леменев)

Автор публикации

не в сети 2 дня

Михаил Леменёв

Комментарии: 0Публикации: 2Регистрация: 02-10-2022
Метки:
Материалы по теме
Авторизация
*
*
Генерация пароля