Главная страница
Навигация по странице:

  • 5.8. Соединения с базой данных и транзакции

  • 5.9. Управление данными

  • 6. СЕТЕВЫЕ ПРОГРАММЫ И СОКЕТЫ

  • БГУ Пособие - Программирование в C++ Builder. Учебное пособие по курсу методы программирования для студентов специальностей


    Скачать 1.24 Mb.
    НазваниеУчебное пособие по курсу методы программирования для студентов специальностей
    АнкорБГУ Пособие - Программирование в C++ Builder.pdf
    Дата26.05.2018
    Размер1.24 Mb.
    Формат файлаpdf
    Имя файлаБГУ Пособие - Программирование в C++ Builder.pdf
    ТипУчебное пособие
    #19699
    страница9 из 12
    1   ...   4   5   6   7   8   9   10   11   12
    Запросы. Компонент TQuery обеспечивает доступ к нескольким таб- лицам одновременно. Вид возвращаемого набора данных зависит от SQL запроса, который может быть либо статическим, когда параметры запро- са задаются на стадии проектирования, или динамическим, когда пара- метры определяются во время выполнения программы.
    Свойство Active разрешает или запрещает режим просмотра "живых данных", возвращаемых запросом на этапе проектирования. Свойство
    DatabaseName содержит псевдоним базы данных или полный путь к ее каталогу, необходимые для разрешения запроса. Свойство SQL исполь-

    88
    зуется для ввода команды SQL посредством строчного редактора списка, который открывается двойным щелчком мышью.
    Аналогично таблице, компонент запроса TQuery также инкапсулиру- ет следующие методы:
    First(), Next(), Prior(), Last() и MoveBy() – используются для навига- ции по результатам динамического запроса;
    Append(), Insert(), AppendRecord() и InsertRecord() – добавляют новую запись к таблице;
    Delete() – удаляет текущую запись;
    Edit() – разрешает приложению модифицировать записи;
    Post() – вызывает фактическое изменение содержимого базы данных.
    Следующая процедура иллюстрирует процесс создания простой фор- мы для базы данных StudentBase:
    1.Поместите на форму Form1 пять наборов TTable, TDataSource,
    TDBGrid, TDBNavigator.
    2. Установите свойства объектов таблиц Table1 – Table5
    DatabaseName =StudentBase; Table1Name =students,
    Table2Name=predmets, Table3Name =prepods, Table4Name=exams,
    TableName5=raspisanie.
    3. Установите свойства объектов источников DataSourcel ->
    DataSet =Table1, …, DataSource5 -> DataSet =Table5 4. Установите свойства компонентов отображения данных
    DBGrid1 -> DataSource = DataSource1, …, DBGrid5 ->DataSource =
    DataSource5 5. Установите свойство Active = true для таблиц, чтобы сразу же ото- бразить данные в сетках на форме.
    6.Создайте новую форму Form2 и поместите на нее компоненты
    Query1, Table1, DataSourse1, DBGrid1. Задайте свойства этих компонен- тов.
    7. В свойстве SQL компонента Query1 задайте SQL запрос:
    SELECT StudentsName, ExamMark, PrepodName, PredmetName
    FROM students, exams, predmets,prepods,raspisanie
    WHERE students.Id_stud=exams.Id_stud
    AND raspisanie.Id_predmet=exams.Id_predmet
    AND raspisanie.Id_prepod=prepods.Id_prepod
    AND exams.Id_predmet=predmets.Id_predmet
    AND predmets.PredmetName LIKE 'Програм'
    AND exams.ExamMark >'5';
    8. Выполните компиляцию и запустите приложение. На рис. 19 пока- зан результат выполнения приложения.

    89
    Рис. 19. Результат выполнения приложения
    Чтобы связать ведущую таблицу students с ведомой таблицей exams необходимо выполнить следующее:
    1. Активизируйте ведомую таблицу Table5 и установите свойство
    MasterSource = DataSource1 2. Дважды щелкните мышью в графе значений свойства MasterFields и в открывшемся окне редактора связи полей выберите Id_stud (связую- щее поле таблиц) из выпадающего списка Available Indexes; задайте
    Id_stud в списках Detail Fields и Master Fields; нажмите кнопку Add, что- бы добавить в список Joined Fields соединение Id_Stud-> Id_Stud; нажми- те кнопку OK, подтверждая сделанный выбор.
    Следующая процедура иллюстрирует процесс создания формы со статическим запросом к таблице EMPLOYEE для получения всей ин- формации о служащих, зарплата которых превышает заданную величи- ну:
    1. Поместите компонент TQuery на форму.
    2. Установите псевдоним адресуемой базы данных сервера в свойстве
    DatabaseName. В примере используется псевдоним BCDEMOS локаль-

    90
    ной демонстрационный базы данных, содержащей, в частности, таблицу служащих некоторого предприятия.
    3. Откройте строчный редактор списка, введите команду SQL
    SELECT * FROM EMPLOYEE WHERE Salary>40000 и нажмите кнопку ОК.
    4. Поместите на форму компонент TDataSource и установите его свойство DataSet = Query1.
    5. Поместите на форму компонент управления TDBGrid и установите его свойство DataSource = DataSource1.
    6. Установите свойство Active = true для запроса Queryl с тем, чтобы сразу же отобразить живые данные в компоненте управления.
    Далее приводится пример приложения для выполнения динамиче- ских SQL-запросов к таблице служащих.
    Свойство SQL компонента TQuery имеет тип TStrings и содержит список текстовых строк наподобие массива. Листинг показывает обра- ботчик события Button1Click, реализующий ввод запроса пользователем при нажатии кнопки на форме. Введенная команда SQL записывается в строчный массив (того же типа TStrings) свойства Memo1->Lines компо- нента TMemo. Результаты запроса можно, как и в предыдущем примере, отобразить с помощью компонента TDBGrid. void__fastcall TForm1::Button1Click(TObject *Sender) {
    // Проверить, введена ли какая-то строка в Memo1 if (strcmp(Memo1->Lines->Strings[0].c_str(), "") = = 0) (
    MessageBox(0, "Не введен SQL-запрос", "Ошибка", MB_OK) ; return;
    } else {
    // Исключить предыдущий запрос, если он имел место
    Queryl->Close ();
    // Очистить свойство SQL от предыдущего запроса
    Queryl->SQL->Clear ();
    // Присвоить введенный в Memo1 текст свойству SQL
    Queryl->SQL->Add(Memo1->Lines->Strings[0].c_str()) ; try{
    Query1->Open(); // выполнить команду SQL
    } catch(EDBEngineError* dbError){} .// обработка ошибок BDE
    { for (int i=0; iErrorCount; i++)
    MessageBox (0, dbError[i].Message.c_str(), "SQL Error", MB_OK) ;
    }
    }
    }

    91
    Для динамического формирования текста командной строки SQL во время выполнения программы удобно использовать стандартную функ- цию языка С sprintf(). Эта функция замещает параметры форматирования
    (%s, %d, %n и т.д.) передаваемыми значениями. Например, в результате подстановки значений параметров форматирования tblName = "Student"; fldName = "Kurs"; fldValue =2; char sqls[80]; sprintf(sqls, "SELECT * FROM %s WHERE %s = %d", tblName, fldName, fldValue); символьный массив sqls будет содержать следующую команду:
    SELECT * FROM Student WHERE Kurs =2.
    Далее созданный запрос выполняется
    Query1->Close() ;
    Query1->SQL->Clear() ;
    Query1->SOL->Add(sqls); try{
    Query1 -> Open(); // выполнить команду SELECT
    } catch(EDBEngineError* dbError) // обработка ошибок BDE
    { }
    }
    Метод Open() предназначен для передачи серверу команды Select языка SQL для исполнения. Существуют другие команды SQL, напри- мер, команда UPDATE, которая обновляет содержимое некоторой запи- си, но не возвращает какой бы то ни было результат. Для исполнения сервером таких запросов следует использовать метод ExecSQL() вместо метода Open().
    5.8. Соединения с базой данных и транзакции
    Компонент TDatabase позволяет создавать локальный псевдоним ба- зы данных, не требуя его наличия в конфигурационном файле BDE.
    Свойство AliasName содержит псевдоним существующей базы данных, определенный утилитой конфигурации BDE. Указание этого свойства является альтернативой значения свойства DriverName.
    Свойство DatabaseName позволяет создать локальный псевдоним ба- зы данных в дополнение к значениям AliasName или DriverName.
    Свойство DriverName содержит имя драйвера BDE при создании ло- кального псевдонима по значению DatabaseName. Указание этого свой- ства является альтернативой значения свойства AliasName.

    92
    Свойство Params содержит строчный массив параметров одиночного соединения (полный путь, имя сервера и т.д.).
    Компонента TDatabase может использоваться для управления тран- закциями. Примером транзакции является перевод денежных средств с банковских счетов. Такая транзакция состоит в добавлении суммы к но- вому счету и вычитании этой суммы из исходящего счета. Если выпол- нение любой из операций терпит неудачу, вся операция считается неза- вершенной. SQL-серверы дают возможность "прокручивать назад" ко- манды при возникновении ошибки, не производя изменений в базе дан- ных. Как правило, транзакция содержит несколько команд, поэтому на- чало транзакции надо отметить методом StartTransaction(). Как только транзакция началась, все ее исполняемые команды находятся во времен- ном состоянии до тех пор, пока один из методов Commit() или Rollback() не отметит конец транзакции. Вызов Commit() фактически модифициру- ет данные, а вызов Rollback() отменяет всякие изменения.
    Ниже приводится листинг, который реализует транзакцию по изме- нению адреса фирмы на примере связанных таблиц CUSTOMER и
    ORDERS. Старый адрес, введенный пользователем в область редактиро- вания EditOld, заменяется на новый, введенный в область редактирова- ния EditNew. В этом примере компонентный объект Database1 использо- вался для одиночного соединения с базой данных, поддерживающего выполнение одиночной транзакции. Этот объект необходимо каким-то образом связать с псевдонимом базы данных: или установкой соответст- вующих свойств компонента, или определив параметры соединения (та- кие как тип драйвера, имя сервера, имя пользователя, пароль) во время выполнения программы. Воспользуемя первым способом соединения на стадии проектирования формы приложения, установив нужные значения свойств компонента. void__fastcall TForm1::Button1Click(TObject *Sender) { char sqls[250]; // массив для хранения команды SQL try{
    Database1->StartTransaction ();
    Query1->SQL->Clear () ;
    // Изменить EditOld на EditNew в таблице CUSTOMER sprintf(sqls, "UPDATE CUSTOMER SET Addrl = \"%s\" WHERE
    (Addrl = \"%s\")", EditNew->Text.c_str(), EditOld->Text.c_str());
    Query1->SQL->Add(sqls) ;
    Query1->ExecSQL ();
    Query1->SQL->Clear () ;
    // Изменить EditOld на EditNew в таблице ORDERS sprintf(sqls, "UPDATE ORDERS SET ShipToAddrl = \"%s\" WHERE
    (ShipToAddrl = \"%s\")", EditNew->Text.c_str(),

    93
    EditOld->Text.c_str()) ;
    Query1->SQL->Add(sqls) ;
    Query1->ExecSQL();
    // Внести все изменения, сделанные до этого момента
    Database1->Commit();
    Table1->Refresh();
    Table2->Refresh();
    } catch(EDBEngineError* dbError) // обработка ошибок BDE
    { for (int i=0; iErrorCount; i++)
    MessageBox (0, dbError[i].Message.c_str(), "SQL Error", MB_OK) ;
    Database1->Rollback() ; return;
    } catch (Exception* exception) // обработка других исключений
    {}
    }
    5.9. Управление данными
    Остановимся на особенностях использования компонента навигатора
    TDBNavigator. Нажимая на кнопки компонента First, Prior, Next и Last, можно перемещаться от записи к записи, а с помощью кнопок Insert,
    Delete, Edit, Post, Cancel и Refresh – производить редактирование.
    Свойство DataSource соединяет кнопки управления панели навигато- ра с компонентами доступа к наборам данных через компонент источни- ка. Изменяя значение этого свойства во время выполнения программы, можно использовать один и тот же компонент для навигации по разным таблицам. Например, можно разместить на форме два компонента редак- тируемого ввода DBEdit1 и DBEdit2, связанные с таблицами
    CustomersTable и OrdersTable через источники данных CustomersSource и
    OrdersSource, соответственно. Когда пользователь выбирает название фирмы (поле Company в DBEdit1), навигатор тоже должен соединяться с источником CustomersSource, а когда активизируется номер заказа (поле
    OrderNo в DBEdit2), навигатор должен переключаться на источник
    OrdersSource. Чтобы реализовать подобную схему работы навигатора, необходимо написать обработчик события OnEnter для одного из объек- тов компонента редактирования, а затем присвоить этот обработчик дру- гому объекту.
    Свойство VisibleButtons позволяет убрать ненужные кнопки, напри- мер, кнопки редактирования на форме, предназначенной для просмотра данных. Во время выполнения программы можно динамически прятать или вновь показывать кнопки навигатора – в ответ на определенные дей-

    94
    ствия пользователя или на изменения состояния приложения. Предполо- жим, вы предусмотрели единый навигатор для редактирования таблицы
    CustomersTable и для просмотра таблицы OrdersTable. Когда навигатор подключается ко второй таблице, желательно спрятать кнопки редакти- рования Insert, Delete, Edit, Post, Cancel и Refresh, а при подключении к первой таблице – снова показать их.
    СвойствоShowHint разрешает или запрещает высвечивать подсказку с названием кнопки навигатора, когда на нее наведен курсор. Значение false (устанавливается по умолчанию) запрещает подсказки для всех кнопок.
    Свойство Hints содержит массив текстовых подсказок для каждой кнопки навигатора
    Итак, проектирование формы приложения СУБД в среде C++Builder в простейшем случае требует выполнения следующих действий:
    1. Перенесите на форму компонент TTable или TQuery со страницы
    Data Access и установите его свойства.
    2. Перенесите на форму компонент DataSource и в свойстве DataSet укажите ссылку на объект набора данных (например, Table1 или Query1).
    3. Перенесите на форму нужные компоненты отображения и редакти- рования данных со страницы DataControls и в их свойстве DataSource за- дайте источник данных (например, DataSource1). Определите отобра- жаемое поле набора данных в свойстве DataField.
    4. Если на предыдущем шаге вы выбрали компонент TDBGrid, то ис- пользуйте его совместно с компонентом навигатора TDBNavigator.
    Вопросы
    1. Что представляет собой псевдоним БД и как он создается?
    2. Как создать таблицу с помощью программы Database Desktop?
    Какие другие средства для создания таблиц можно использовать?
    3. Какие компоненты используются для связи таблиц БД с компо- нентами визуализации и управления данными DBGrid, DBEdit?
    4. Как связать компоненты Table и Query с нужной таблицей БД ?
    5. Как связать компонент DBNavigator с нужной таблицей БД ?
    6. Что такое первичные и вторичные индексы для таблицы и как их создать?
    7. Что такое SQL и из каких частей он состоит?
    8. Что означают следующие SQL-запросы: a) SELECT name, projectname FROM emploee, project
    WHERE empno=team_leader;

    95
    б) SELECT name, salary FROM emploee, prohibit
    WHERE salary>2900;
    9. Как использовать SQL-запрос в C++Builder ?
    Упражнения
    В следующих упражнениях создать указанные таблицы и записать
    SQL запрос для выборки данных из обеих таблиц.
    1. Построить головную таблицу «Телефонный справочник» с полями:
    Номер телефона, Адрес, а также вспомогательную таблицу «Население города» с полями: Номер телефона Фамилия И.О., Год рождения, Пол,
    Адрес.
    2. Головная таблица содержит данные о подразделениях предпри- ятия: Отдел – номер, название(например, Цех1, Бухгалтерия), тип отдела
    (например, Управление, Производство и т. д.). Вспомогательная таблица содержит сведения о сотрудниках: ID, Фамилия И.О., Год рождения,
    Пол, Номер_Отдела. Связать таблицы по полю Номер_Отдела.
    3. БД содержит следующие связанные таблицы: «Сведения о покупа- телях»:ID, Фамилия И.О., адрес, Номер банковского счёта, номер заказа и «Сведения о заказах»: Наименование товара, ID, Количество, Стои- мость, Дата заказа.
    4. БД содержит следующие связанные таблицы: «Студенты»: Номер зачётной книжки, Фамилия, Имя, Отчество, Специализация, Курс, Груп- па; «Учебный план»: Специализация, Курс, Предмет1, Предмет2,…;
    «Журнал успеваемости»: Фамилия, Имя, Отчество, Предмет 1, Предмет
    2, …
    5. БД «Абитуриенты» содержит следующие связанные таблицы:
    «Сведения об абитуриентах»: Номер личной карточки, Фамилия, Имя,
    Отчество, Факультет, Специальность,; «Сведения о сдаваемых предме- тах»: Специальность, Предмет; «Сведения об оценках»: Фамилия, Имя,
    Отчество, Номер личной карточки, Предмет, Оценка.
    6. БД
    «Автомобили» содержит следующие таблицы:
    «Общие сведения об автомобиле»:ID, Марка, Тип, Производитель; «Ха- рактеристика автомобиля»: Марка, Мощность двигателя, Тип двигателя,
    Стоимость.
    7. БД «Лабораторные занятия» содержит следующие таблицы:
    «Преподаватели»: ID, Фамилия, Имя, Отчество, Предмет, Курс, Группа;
    «Студенты»:ID,
    Фамилия,
    Имя,
    Отчество,
    Курс,
    Группа;
    «Пропуски занятий»: Фамилия, Имя, Отчество, Курс, Группа, Предмет,
    Пропущено.

    96 8. БД
    «Конференция» содержит следующие таблицы:
    «Расписание заседаний»:Номер, Название секции, Дата, Время;
    «Сведения об участниках»: Фамилия И.О., Название секции, Название доклада; «Оргработа»: Фамилия, Имя, Отчество, Дата приезда, Дата отъ- езда, Потребность в гостинице, Оргвзнос.
    9. БД
    «Библиотека» содержит следующие таблицы:
    «Общая характеристика единицы хранения»: Инвентарный номер, Тип издания (журнал, книга, рукопись), Название; «Характеристика изда- ния»: Тип издания, Авторы, Название, Издательство, Год издания, Но- мер, Количество страниц.
    10. БД «Магазин» содержит следующие таблицы: «Товары»: Артикул,
    Наименование товара, Количество, Дата поставки, Цена; «Поставщики»:
    Название организации, Наименование товара, Количество, Дата постав- ки, Адрес организации;
    «Покупатели»: Название организации, Наименование товара, Количест- во, Дата покупки, Адрес покупателя.
    11. БД
    «Поликлиника» содержит следующие таблицы:
    «Врачи»:
    Участок,
    Фамилия
    И.О.,
    Специальность;
    «Пациенты»:ID, Фамилия И. О., Диагноз, Возраст, Участок.
    12. БД
    «Спортивная база» содержит следующие таблицы:
    «Тренеры»:ID, Фамилия, Имя, Отчество, Вид спорта, Секция;
    «Спортсмены»: ID, Фамилия, Имя, Отчество, Вид спорта, Секция, Рей- тинг, Возраст.
    6. СЕТЕВЫЕ ПРОГРАММЫ И СОКЕТЫ
    Понятие «сокет» (socket) означает "гнездо", "разъем" по аналогии с гнездами на аппаратуре. В соответствии с этой аналогией, можно связать два "гнезда" соединением и передавать между ними данные. Каждое гнездо принадлежит определённому хосту (host – хозяин, держатель).
    Каждый хост имеет уникальный IP (Internet Packet) адрес, представляю- щий группу из четырех чисел, разделенных точками.
    Переданная по IP адресу на хост информация поступает на один из портов хоста. Порт определяется числом от 0 до 65535. После того, как сокет установлен, он имеет вполне определённый адрес, записывающий- ся так [host]:[port]. Например, 127.0.0.1:8888 означает, что сокет занимает порт 8888 на хосте 127.0.0.1(на данном компьютере). Чтобы не исполь- зовать труднозапоминаемый IP адрес, для доступа к хостам используется система имен DNS (DNS – Domain Name Service), поддерживаемая спе- циальным сервером. Цель этой системы – сопоставлять IP адресам сим-

    97
    вольные имена. Например, адресу "127.0.0.1" в большинстве компьюте- ров соответствует имя "localhost", что означает сам компьютер, на кото- ром выполняется программа.
    Сокеты – это абстракция, представляющая узлы соединения двух приложений - клиента и сервера. К этим узлам подключаются клиенты и серверы через соединение, которое можно представить как гипотетиче- ский кабель. Соединения с приложением-сервером. всегда устанавливают приложения-клиенты. В обязанность приложения-сервера входит прослушива- ние клиентов и ожидание соединения. После этого клиенты посылают серверу или получают от сервера сообщения в виде последовательности символов, а в конце работы закрывают соединение.
    Для организации сетевых соединений (сокетов) в C++ Builder исполь- зуются классы TСlientSocket и TServerSocket из группы компонентов
    Internet. Ниже описывается работа с компонентом TСlientSocket по уста- новке соединения.
    1   ...   4   5   6   7   8   9   10   11   12


    написать администратору сайта