FoxPro Club Главная

Конференция Решения Фотоальбом Сайт М.Дроздова Статьи Файловый архив Книга Visual FoxPro 9.0 Русский Help для Visual FoxPro
Пользователей: 9176
Вход

Web Services и MS Visual FoxPro Часть 2

В этой статье:


Новые методы разработки приложений.
Проблема.
Дизайн. Создание базы данных.

Новые методы разработки приложений.



Приступим к созданию более сложного примера, сделав который Вы получите необходимые навыки для применения технологии в повседневной жизни и не только. Мы постараемся рассказать Вам, как рекомендует Microsoft создавать приложения с нуля, условно разбив это путь на три основных части:


1) Идентифицировать проблему (или постановить задачи и найти ответы на вопросы: “ Что мы хотим сделать и что должно в итоге получиться?”, “Какие ограничения или другие условия влияют на проект?”)


2) Сделать основной дизайн (решить какие функции и возможности мы должны будем разработать в системе, чтобы решить стоящую перед нами задачу). Понять в общем как система будет работать, не вдаваясь в излишние детали.


3) Создать наше рабочее приложение (написать код и выполнить другие виды работ, которые позволят сделать наш проект рабочим).


Кроме того, в основе нашего приложения будет лежать идея многослойности (n-tier): слой базы данных, своеобразный слой бизнес – логики (эту роль будет играть Service) и презентационный слой (собственно клиентская часть – то что увидят наши клиенты). Идея, лежащая в основе многослойных приложений, проста - каждый слой можно разрабатывать и модернизировать в будущем по отдельности. Из набивших уже "оскомину" на ум сразу приходит пример - заменить базу данных FoxPro на базу данных MS SQL Server... Это, наверное, самый популярный пример, так как зарплата программистов со знанием этих SQL серверов почему-то намного выше нашей, хотя работать с последним намного легче, чем с родными базами FoxPro. Стрнно все это, куда катится наш мир?

К недостаткам данного подхода необходимо отнести его затратность: чтобы внести изменения в программу, надо их внести в несколько мест. Так, например, для сайта http://www.sergey.co.uk/ (да, этот сайт разработан как обычная программа ASP.NET и подхода n-tire) если я захочу изменить, например, форум , я должен буду внести измения в базу данных, хранимые процедуры, слой работы с данными, бизнес-слой и , наконец, в презентационный слой. Что и говорить, кошмары современного метода разработки приложений, или добро пожаловать в мир, где все борются с безработицей подобным странным образом.

Проблема.



Главная и основная задача - создать приложение, которое бы послужило базой для дальнейшей самостоятельной работы программиста FoxPro. Отсюда вытекают остальные проблемы:
  • создать систему обмена сообщений внутри фирмы
  • возможность ведения частных и приватных диалогов
  • наличие специальных администраторов
  • совмещенная экранная форма в приложении – для администратора и клиента (у администратора добавляются по мере необходимости дополнительные объекты управления)
  • стандартный набор функций клиента:
    1. регистрация (для простоты пароли будем хранить в открытом виде)
    2. публиковать свои сообщения: всем (ALL) или определенному лицу (выбор из списка – в качестве параметра передовать на сервер начальные буквы User_nick)
    3. отвечать на общие и приватные сообщения
    4. вся необходимая информация о других клиентах будет предоставлена в Grid

  • стандартный набор функций администратора:
    1. добавлять пользователей и изменять их профайлы
    2. удалять и редактировать любые сообщения
    3. блокировать пользователей
    4. наличие на форме специального фильтра, ограничивающего период запрашиваемых с сервера сообщений

    Дизайн. Создание базы данных.



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

    В этом направлении все сильно запущено, но все-таки воспользуемся привычным для западного человека графическим изображением модели базы данных, применив для этого ERM диаграмму и условно-бесплатный редактор QSEE Superlight. В общем-то ничего сложного для своего примера мы брать и не собирались:


    Как мы видим из приведенной диаграммы, у нас будет три сущности (entity), связанные соотношениями (relationships) один ко многим. Имена атрибутов и их тип видны на рисунке. Далее, как любят показывать в рекламе, нажимается кнопка и генерируется код создания базы данных. Но не все так просто - этот код не всегда именно то, что нам надо, и приходится, как правило, довольно много потом исправлять руками. Да и наша мысль не стоит на месте. Изменения легче внести руками в готовую базу, чем рисовать это в ERM, а потом снова генерировать, исправлять... Короче, замкнутый круг на любителя. Для меня, как практика, эти диаграммы являются хорошим подспорьем для начальных бесед с клиентом. Обилие непонятных слов и картинки, как правило, производят на него неизгладимые впечатления, парализуют его мозг и позволяют легче выбивать из него деньги (может поэтому специалисты Oracle, DB2 "гребут деньги лопатой" за гораздо меньший труд, чем программисты FoxPro, что умеют "замутить" подобным образом мозги заказчику).
    Для простоты повторения мы рекомендуем Вам создать аналогичную структуру директориев, как и в нашем проекте. Для серверной части, например: C:\WS_MESSAGE\SERVER\
    По причинам указанным выше (то есть как это принято у "серьезных админов" баз данных) приведу создание таблиц нашей базы данных в коде, запустив который Вы создадите требуемую базу данных и заполните ее некоторыми начальными значениями. Код прозрачный, так что копируете и вставляете в окно редактора программ FoxPro:
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0 (так как применим новые данные совместимые с SQL Server)  
     * Program-ID......: DB_CREATE.PRG  
     * Purpose.........: Создание базы данных для проекта обмена сообщениями внутри   
     *                   компании. Данная база данных должна находится в дирректории  
     *                   где Ваш Web Service (это сделано только для простоты  
     *                   понимания данного проекта)  
     * Project Manager.:   
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 07/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      SET SAFETY OFF
      CLOSE DATABASES ALL
      PUBLIC m.pcpath
      m.pcpath='C:\WS_MESSAGE\SERVER\'
     * Так-как у нас SET SAFETY OFF  
     * предыдущая база будет удалена без предупреждения  
      IF FILE(m.pcpath+'\DBWS.DBC')
        DELETE DATABASE (m.pcpath+'DBWS') DELETETABLES
      ENDIF
     * собственно создаем базу данных  
      CREATE DATABASE (m.pcpath+'DBWS')
    
      CREATE TABLE m.pcpath+'USERS' CODEPAGE=1251( ;
        User_ID INTEGER NOT NULL AUTOINC NEXTVALUE 1 STEP 1 PRIMARY KEY, ;
        User_nick CHARACTER(10) NOT NULL, ;
        PASSWORD CHARACTER(10) NOT NULL, ;
        email VARCHAR(40), ;
        city VARCHAR(30), ;
        admin NUMERIC(1,0), ;
        isblocked NUMERIC(1,0), ;
        register T NOT NULL, ;
        lastvisit T  ;
        )
    
     * В нижеследующей таблице устанавливаем постоянные соотношения  
     * один ко многим с таблицей User  
     * хотя, в принципе, они нам и не нужны  
      CREATE TABLE  m.pcpath+'Mes_Header' CODEPAGE=1251( ;
        Mes_ID	INTEGER NOT NULL AUTOINC NEXTVALUE 1 STEP 1 PRIMARY KEY , ;
        User_from INTEGER NOT NULL REFERENCES USERS TAG User_ID, ;
        User_to INTEGER NOT NULL REFERENCES USERS TAG User_ID, ;
        WASUPDATED T NOT NULL, ;
        TITLE VARCHAR(100), ;
        published T NOT NULL ;
        )
      INDEX on TTOD(WASUPDATED) TAG WASUPDATED ADDITIVE
    
     * здесь устанавливаем постоянное соотношение  
     * один ко многим с таблицей Mes_Header  
     * применение типа Blob для Message устраняет много проблем в будущем  
     * при передаче данных  
      CREATE TABLE m.pcpath+'Mes_body' CODEPAGE=1251( ;
        Reply_ID INTEGER NOT NULL AUTOINC NEXTVALUE 1 STEP 1 PRIMARY KEY, ;
        Mes_ID INTEGER NOT NULL REFERENCES Mes_Header TAG Mes_ID, ;
        User_from INTEGER NOT NULL REFERENCES USERS TAG User_ID, ;
        MESSAGE W, ;
        published T ;
        )
    
     * добавим сразу несколько необходимых записей  
     * Пользователь ALL (или вроде как код для широковещательного сообщения  
     * очень важно ввести его первой записью, чтобы код был равен 1)  
     * пароль выбираем случайным образом, чтобы никто не писал от его имени  
      INSERT INTO (m.pcpath+'USERS') (User_nick, PASSWORD,admin ,register , lastvisit  ) ;
        VALUES;
        ('ALL',SYS(2015),0,DATETIME(),DATETIME())
     * администратора (для реальной системы рекомендуется сменить пароль)  
      INSERT INTO (m.pcpath+'USERS') (User_nick, PASSWORD,admin ,register , lastvisit  ) ;
        VALUES;
        ('admin','admin',1,DATETIME(),DATETIME())
     * добавляем просто пользователя для тестирования  
     * здесь можете добавить себя  
      INSERT INTO (m.pcpath+'USERS') (User_nick, PASSWORD,admin ,register , lastvisit  ) ;
        VALUES;
        ('sergey','sergey',1,DATETIME(),DATETIME())
     * теперь добавим тестовое сообщение  
      INSERT INTO (m.pcpath+'Mes_Header') (User_from , User_to, WASUPDATED, TITLE, published) ;
      VALUES ;
      (2,1,DATETIME(),'Добро пожаловать в систему обмена сообщениями', DATETIME())
      INSERT INTO (m.pcpath+'Mes_body')  (Mes_ID,User_from ,MESSAGE,published ) ;
      VALUES ;
      (1,2,'Собственно поздравление.'+CHR(13)+'Надеемся, что все будет работать.', DATETIME())
    
     * покажем, что у нас получилось  
     *DISPLAY TABLES  
     *DISPLAY DATABASE  
     * чистим за собой  
      CLOSE DATABASES


    DB_CREATE.PRG

    Как мы видим, ничего сложного. Только пара нюансов - использование явного указания кодовой страницы и применение новго типа данных Blob. К сожалению, они доступны только начиная с версии VFP 9.0.

    Далее создаем хранимые процедуры - "рабочие лошадки" нашего приложения. Существует мнение, что работать с базами данных следует только через хранимые процедуры. В принципе, хороший похдод, тем более, что все изменения в структуре Ваших данных и даже смену СУБД можно производить без смены клиента. Еще одно удобство - это ориентированность на наше WEB приложение (простота и прозрачность): клиент послал запрос в виде параметров хранимой процедуры, а в ответ получил результат. Все просто и надежно. Думаю, начав подобным образом разрабатывать приложения, Вы выбьете почву из под противников FoxPro, ибо они используют аналогичный подход и очень этим гордятся.

    Все хранимые процедуры начинаются с SP (это перевод на английский ХП - Stored Procedures). Далее в названии используется английское наименование функции (для больших задач рекомендуется после SP использовать имя модуля, а затем название выполняемой функции). Теперь небольшое лирическое отступление об использовании английского языка. В принципе, можно использовать и русский, но столкнувшись с некоторыми проблемами совместимости, я пришел к выводу - использовать все-таки английский. Это хорошая практика, так как неизвестно, куда Вас закинет судьба работать завтра - может в ОАЭ, где никто не говорит по-русски, но смогут понять Ваш код на английском.

    Приведу текст всех Хранимых Процедур:
     */--------------------------------------------------------------------------/*  
     * Текст всех ХП находится в sp_procedures.txt  
     * Для создания всех ХП из текстового файла запустите Create_SP.PRG  
     */--------------------------------------------------------------------------/*  
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_chk_admin.PRG  
     * Purpose.........: Проверка на наличие прав администратора по user_id  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 22/05/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_chk_admin
      PARAMETERS m.lcuser_id
      SET DELETED ON
      PRIVATE m.lnreturn_parameter
      m.lnreturn_parameter=-1
      IF m.lcuser_id>0
        SELECT admin FROM USERS WHERE User_ID=m.lcuser_id  INTO CURSOR user_exists
        IF user_exists.admin >0
          m.lnreturn_parameter=user_exists.admin
        ENDIF
      ENDIF
      IF USED('USERS')
        USE IN USERS
      ENDIF
      IF USED('USER_EXISTS')
        USE IN user_exists
      ENDIF
    
      RETURN m.lnreturn_parameter
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_message_read.PRG  
     * Purpose.........: Чтение заголовков сообщений с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 22/05/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_message_read
      PARAMETERS m.lddate, m.lcUser_nick, m.lcpassword, m.lndays_show
      SET DELETED ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      lcXML=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0
        m.lnadmin=sp_chk_admin(m.lnuser_id)
        IF m.lnadmin>0 && это администратор, значит есть доступ ко всем сообщениям  
          SELECT Mes_Header.*,User_nick, city FROM Mes_Header ;
            LEFT OUTER JOIN USERS ON Mes_Header.User_from=USERS.User_ID ;
            WHERE TTOD(Mes_Header.WASUPDATED) >= ;
            DATE(YEAR(m.lddate),MONTH(m.lddate),DAY(m.lddate)) - m.lndays_show ;
            INTO CURSOR CUR_TEMP &&  
        ELSE && обычный пользователь  
          SELECT Mes_Header.*,User_nick, city FROM Mes_Header ;
            LEFT OUTER JOIN USERS ON Mes_Header.User_from=USERS.User_ID ;
            WHERE (Mes_Header.User_to=1 OR Mes_Header.User_to=m.lnuser_id or ;
            Mes_Header.User_from=m.lnuser_id) AND ;
            TTOD(Mes_Header.WASUPDATED) >= ;
            DATE(YEAR(m.lddate),MONTH(m.lddate),DAY(m.lddate)) - m.lndays_show ;
            INTO CURSOR CUR_TEMP &&  
        ENDIF
        SELECT CUR_TEMP
        IF RECCOUNT()>0
          CURSORTOXML("CUR_TEMP","lcXML",1,1,0,"1")
        ENDIF
      ENDIF
      CLOSE TABLES ALL
      RETURN lcXML
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_user_login_xml.PRG  
     * Purpose.........: Проверка пароля и имени пользователя  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 06/05/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_user_login_xml
      PARAMETERS m.User_nick, m.PASSWORD
      SET DELETED ON
      PRIVATE m.lcXML
      m.lcXML=-1 && в случае неуспеха ответ в числовом виде  
      IF LEN(m.User_nick)>=3 AND LEN(m.PASSWORD)>3
        SELECT User_ID, User_nick, admin, ISBLOCKED FROM USERS WHERE  ;
        UPPER(USERS.User_nick)==UPPER(m.User_nick) ;
          AND UPPER(USERS.PASSWORD)==UPPER(m.PASSWORD) INTO CURSOR user_exists
        IF RECCOUNT('USER_EXISTS')>0 AND EMPTY(user_exists.ISBLOCKED)
     * у нас есть такой пользователь  
          CURSORTOXML('user_exists',"lcXML",1,1,0,"1")
        ENDIF
      ENDIF
      IF USED('USER_EXISTS')
        USE IN user_exists
      ENDIF
      IF USED('USERS')
        USE IN USERS
      ENDIF
      RETURN m.lcXML
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_user_login_id.PRG  
     * Purpose.........: Проверка пароля и имени пользователя  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 06/05/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_user_login_id
      PARAMETERS m.User_nick, m.PASSWORD
      SET DELETED ON
      PRIVATE m.lnreturn_parameter
      m.lnreturn_parameter=-1 && в случае неуспеха ответ в числовом виде  
      IF LEN(m.User_nick)>=3 AND LEN(m.PASSWORD)>3
        SELECT User_ID, User_nick, admin, ISBLOCKED FROM USERS WHERE  ;
        UPPER(USERS.User_nick)==UPPER(m.User_nick) ;
          AND UPPER(USERS.PASSWORD)==UPPER(m.PASSWORD) INTO CURSOR user_exists
        IF RECCOUNT('USER_EXISTS')>0 AND EMPTY(user_exists.ISBLOCKED)
     * у нас есть такой пользователь  
          m.lnreturn_parameter=user_exists.User_ID
        ENDIF
      ENDIF
      IF USED('USER_EXISTS')
        USE IN user_exists
      ENDIF
      IF USED('USERS')
        USE IN USERS
      ENDIF
      RETURN m.lnreturn_parameter
    
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_users_read_xml.PRG  
     * Purpose.........: Чтение списка пользователей с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 31/05/2005  
     * Last edited.....: 31/05/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_users_read_xml
      PARAMETERS m.lcUser_nick, m.lcpassword
      SET DELETED ON
      PRIVATE m.lnuser_id, lcXML
      STORE 0 TO m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      lcXML=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0
        SELECT User_ID, User_nick FROM USERS ;
          INTO CURSOR CUR_TEMP
        IF RECCOUNT('CUR_TEMP')>0
          CURSORTOXML("CUR_TEMP","lcXML",1,1,0,"1")
        ENDIF
      ENDIF
      CLOSE TABLES ALL
      RETURN lcXML
    
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_new_message_add.PRG  
     * Purpose.........: Добавление нового сообщения в таблицы Mes_Header, Mes_body  
     *                   а так-же обновляем информацию у клиента  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 30/05/2005  
     * Last edited.....: 04/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_new_message_add
      PARAMETERS m.User_nick, m.PASSWORD , m.lnUser_to, m.lcTITLE, m.lcMes_Body
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnreturn_parameter, m.lnuser_id, m.lnmes_id
    
      m.lnreturn_parameter=-1
      m.lnuser_id=sp_user_login_id(m.User_nick, m.PASSWORD)
      IF m.lnuser_id>0
        BEGIN TRANSACTION
        TRY
          INSERT INTO Mes_Header (User_from , User_to, WASUPDATED, TITLE, published) ;
            VALUES ;
            (m.lnuser_id,m.lnUser_to,DATETIME(),ALLTRIM(m.lcTITLE), DATETIME())
          m.lnmes_id=GETAUTOINCVALUE(0)
          INSERT INTO Mes_body  (Mes_ID,User_from,MESSAGE,published ) ;
            VALUES ;
            (m.lnmes_id,m.lnuser_id, m.lcMes_Body, DATETIME())
          UPDATE USERS SET lastvisit = DATETIME() WHERE User_ID=m.lnuser_id
          END TRANSACTION
          m.lnreturn_parameter=1
        CATCH TO oException
          ROLLBACK
        FINALLY
        ENDTRY
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
    
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_thread_read.PRG  
     * Purpose.........: Чтение всего потока одного сообщения с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 04/06/2005  
     * Last edited.....: 06/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_thread_read
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnmes_id
      SET DELETED ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      lcXML=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0
        SELECT Mes_body.*,User_nick, city FROM Mes_body ;
          LEFT OUTER JOIN USERS ON Mes_body.User_from=USERS.User_ID ;
          WHERE Mes_ID=m.lnmes_id ;
          INTO CURSOR CUR_TEMP &&  
        SELECT CUR_TEMP
        IF RECCOUNT()>0
          CURSORTOXML("CUR_TEMP","lcXML",1,1,0,"1")
        ENDIF
      ENDIF
      CLOSE TABLES ALL
      RETURN lcXML
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_existed_message_add.PRG  
     * Purpose.........: Добавление нового сообщения в таблицу Mes_body  
     *                   а так-же обновляем информацию у клиента  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 05/05/2005  
     * Last edited.....: 06/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_existed_message_add
      PARAMETERS m.User_nick, m.PASSWORD ,  m.lcMes_Body, m.lnmes_id
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnreturn_parameter, m.lnuser_id
      m.lnreturn_parameter=-1
      m.lnuser_id=sp_user_login_id(m.User_nick, m.PASSWORD)
      IF m.lnuser_id>0
        BEGIN TRANSACTION
        TRY
          INSERT INTO Mes_body  (Mes_ID,User_from,MESSAGE,published ) ;
            VALUES ;
            (m.lnmes_id,m.lnuser_id, m.lcMes_Body, DATETIME())
          UPDATE USERS SET lastvisit = DATETIME() WHERE User_ID=m.lnuser_id
          END TRANSACTION
          m.lnreturn_parameter=1
        CATCH TO oException
          ROLLBACK
        FINALLY
        ENDTRY
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_message_delete.PRG  
     * Purpose.........: Удаление всего потока сообщения с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 05/06/2005  
     * Last edited.....: 05/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_message_delete
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnmes_id
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      m.lnadmin=sp_chk_admin(m.lnuser_id)
      m.lnreturn_parameter=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0 AND m.lnadmin>0
        BEGIN TRANSACTION
        TRY
          DELETE FROM Mes_Header WHERE Mes_ID=m.lnmes_id
          DELETE FROM Mes_body WHERE Mes_ID=m.lnmes_id
          UPDATE USERS SET lastvisit = DATETIME() WHERE User_ID=m.lnuser_id
          END TRANSACTION
          m.lnreturn_parameter=1
        CATCH TO oException
          ROLLBACK
        FINALLY
        ENDTRY
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_answer_delete.PRG  
     * Purpose.........: Удаление одного ответа из сообщения с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 05/06/2005  
     * Last edited.....: 05/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_answer_delete
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnReply_id, m.lnmes_id
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      m.lnadmin=sp_chk_admin(m.lnuser_id)
      m.lnreturn_parameter=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0 AND m.lnadmin>0
        BEGIN TRANSACTION
        TRY
          DELETE FROM Mes_body WHERE Reply_ID=m.lnReply_id
     *     теперь смотрим - остались ли еще сообщения и если нет - то удаляем  
     *     и заголовок сообщения  
          SELECT COUNT(Mes_ID) AS RECORDS ;
            FROM Mes_body ;
            WHERE Mes_ID=m.lnmes_id ;
            INTO CURSOR CUR_TEMP
          SELECT CUR_TEMP
          IF CUR_TEMP.RECORDS=0
            DELETE FROM Mes_Header WHERE Mes_ID=m.lnmes_id
          ENDIF
          UPDATE USERS SET lastvisit = DATETIME() WHERE User_ID=m.lnuser_id
          END TRANSACTION
          m.lnreturn_parameter=1
        CATCH TO oException
          ROLLBACK
        FINALLY
        ENDTRY
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_users_profile_read_xml.PRG  
     * Purpose.........: Чтение профиля пользователя с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 06/06/2005  
     * Last edited.....: 06/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_users_profile_read_xml
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnUserProfile_ID
      SET DELETED ON
      PRIVATE m.lnuser_id, lcXML, m.lnadmin
      STORE 0 TO m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      m.lnadmin=sp_chk_admin(m.lnuser_id)
      lcXML=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0 AND m.lnadmin>0
        SELECT * FROM USERS ;
          INTO CURSOR CUR_TEMP WHERE User_ID=m.lnUserProfile_ID READWRITE NOFILTER
        IF RECCOUNT('CUR_TEMP')=0
          SELECT CUR_TEMP
          APPEND BLANK
        ENDIF
        CURSORTOXML("CUR_TEMP","lcXML",1,1,0,"1")
      ENDIF
      CLOSE TABLES ALL
      RETURN lcXML
    
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_users_add_edit.PRG  
     * Purpose.........: Добавление/изменение профиля клиента  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 06/06/2005  
     * Last edited.....: 06/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_users_add_edit
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnUserProfile_ID, m.lcXML_Cursor
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      m.lnadmin=sp_chk_admin(m.lnuser_id)
      m.lnreturn_parameter=-1 && в случае неуспеха ответ в числовом виде  
      IF m.lnuser_id>0 AND m.lnadmin>0 AND !EMPTY(m.lcXML_Cursor)
        XMLTOCURSOR(m.lcXML_Cursor,'TMCURSOR',4)
        SELECT TMCURSOR
        IF RECCOUNT()>0 && у нас есть работа  
          IF m.lnUserProfile_ID>0 && обновление существующих данных  
            BEGIN TRANSACTION
            TRY
     * это конечно узкое место, но нам хотелось все сделать с помощью CRUD команд  
              UPDATE USERS SET  User_nick=TMCURSOR.User_nick, PASSWORD = TMCURSOR.PASSWORD,;
                email=TMCURSOR.email, city=TMCURSOR.city,admin = TMCURSOR.admin, ;
                ISBLOCKED=TMCURSOR.ISBLOCKED ;
                WHERE User_ID=m.lnUserProfile_ID
              END TRANSACTION
              m.lnreturn_parameter=1
            CATCH TO oException
              ROLLBACK
            FINALLY
            ENDTRY
          ELSE && добавление нового клиента  
            BEGIN TRANSACTION
            TRY
              INSERT INTO USERS ;
                (User_nick,         PASSWORD ,         email,        city,         ;
                admin         , register,  lastvisit,  ISBLOCKED          ) ;
                VALUES ;
                (TMCURSOR.User_nick,TMCURSOR.PASSWORD,TMCURSOR.email,TMCURSOR.city,;
                TMCURSOR.admin, DATETIME(), DATETIME(),TMCURSOR.ISBLOCKED)
              END TRANSACTION
              m.lnreturn_parameter=1
            CATCH TO oException
              ROLLBACK
            FINALLY
            ENDTRY
          ENDIF
        ELSE && нечего делать  
        ENDIF
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
      


    Stored Procedures DBWS.DBC

    Stored Procedures DBWS.DBC

    Теперь, собственно, сам текст этой небольшой процедуры, которая создает эти ХП:
     */-----------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0   
     * Program-ID......: Create_SP.PRG  
     * Purpose.........: Создание Хранимых Процедур для базы данных DBWS.DBC  
     * Project Manager.:   
     * Programmer......: Sergey Chavlytko  
     * Start...........: 22/05/2005  
     * Last edited.....: 05/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PUBLIC m.pcpath
      m.pcpath='C:\WS_MESSAGE\SERVER\'
      OPEN DATABASE (m.pcpath+'DBWS.DBC')
      APPEND PROCEDURES FROM (m.pcpath+'SP_PROCEDURES.TXT') as 1251 OVERWRITE
      CLOSE DATABASES
      


    Create_SP.PRG



    Кстати, в проекте, который Вы можете скачать
    ЗДЕСЬ (файл ws_mes_serv.zip 34 Kb) , так и сделано.
    Второй путь - открыть базу данных, написать команду MODIFY PROCEDURE и в открывшееся окно скопировать текст всех хранимых процедур.
    При отладке ХП могут иногда возникнуть проблемы - не отображаются внесенные Вами изменения. Для этого Вам надо открыть базу данных в режиме EXCLUSIVE и выполнить команду PACK DATABASE.
    Теперь солидная "ложка дегтя" к нашей "бочке меда". Дело в том, что ряд разработчиков используют базы данных FoxPro и для других приложений, например, в ASP.NET. Работа с базами данных осуществляется с помощью Visual FoxPro OLE DB Provider, который, к сожалению, пока все еще не поддерживает структуру TRY..CATCH..ENDTRY. В этом случае нам придется обойтись старыми приемами, основанными на буферизации таблиц и вложенных транзакциях. Для простоты повествования приведем текст примера только для одной хранимой процедуры sp_message_delete():
     */--------------------------------------------------------------------------/*  
     *  
     * MS VFP version..: 9.0  
     * Program-ID......: sp_message_delete.PRG  
     * Purpose.........: Удаление всего потока сообщения с сервера  
     * Project Manager.:  
     * Programmer......: Sergey Chavlytko  
     * Start...........: 05/06/2005  
     * Last edited.....: 05/06/2005  
     *  
     * (С) www.sergey.co.uk 2005  
     */--------------------------------------------------------------------------/*  
      PROCEDURE sp_message_delete
      PARAMETERS m.lcUser_nick, m.lcpassword, m.lnmes_id
      SET DELETED ON
      SET MULTILOCKS ON
      PRIVATE m.lnuser_id, m.lnadmin, lcXML
      STORE 0 TO m.lnadmin, m.lnuser_id
      m.lnuser_id=sp_user_login_id(m.lcUser_nick, m.lcpassword)
      m.lnadmin=sp_chk_admin(m.lnuser_id)
      m.lnreturn_parameter=-1 && в случае неуспеха ответ в числовом виде  
    
      CLOSE TABLES ALL
      SELECT 0
      USE MES_HEADER SHARED
      =CURSORSETPROP("Buffering" ,5,'MES_HEADER' )
      SELECT 0
      USE MES_BODY SHARED
      =CURSORSETPROP("Buffering" ,5,'MES_BODY' )
      SELECT 0
      USE USERS ALIAS USERS SHARED
      =CURSORSETPROP("Buffering" ,5,'USERS' )
      SELECT 0
    
      IF m.lnuser_id>0 AND m.lnadmin>0
    
        LOCAL llRollBack
        llRollBack=.F.
    
        BEGIN TRANSACTION
        DELETE FROM MES_HEADER WHERE Mes_ID=m.lnmes_id
        DELETE FROM MES_BODY WHERE Mes_ID=m.lnmes_id
        UPDATE USERS SET lastvisit = DATETIME() WHERE User_ID=m.lnuser_id
    
        IF !TABLEUPDATE(2,.T.,'MES_HEADER')
          llRollBack=.T.
        ELSE
          IF !TABLEUPDATE(2,.T.,'MES_BODY')
            llRollBack=.T.
          ELSE
            IF !TABLEUPDATE(2,.T.,'USERS')
              llRollBack=.T.
            ENDIF
          ENDIF
        ENDIF
        IF llRollBack
          ROLLBACK
        ELSE
          END TRANSACTION
          m.lnreturn_parameter=1
        ENDIF
    
      ENDIF
      CLOSE TABLES ALL
      RETURN m.lnreturn_parameter
      


    Вариант ХП sp_message_delete() для Visual FoxPro OLE DB Provider


    Код как обычно прозрачен, так что думаю, что можно опустить объяснения. В скачиваемом файле (ws_mes_serv.zip 34 Kb) процедура для создания Хранимых Процедур носит название CREATE_SP_OLEDB.PRG, а их тексты находятся в файле SP_PROCEDURES_OLEDB.TXT. Для примера с Web Service на основе FoxPro не имеет значения какие хранимые процедуры использовать, но Вам, как программисту FoxPro, должна быть понятна эта разница и ограничения, накладываемые Visual FoxPro OLE DB Provider.

    Прислал Sergey Chavlytko
    Последнее обновление: 23.06.05


    Вернуться к списку статей






    © 2000-2017 Fox Club 
    При размещении любых материалов с сайта на других ресурсах- прямая ссылка на www.foxclub.ru обязательна
    Яндекс.Метрика