Лабораторная работа №6.
Тема: Созданиеприложения ODBC.
1. Проект MFC AppWizard.
Прежде всего надо создать (или выбрать) саму базу данных.Первым шагом на этом пути является выбор в качестве проекта MFC AppWizardрис. 1.
Рис.1
Рис.2 Первое окномастера MFC AppWizard
Начнем с создания самого простого приложения для работы сбазой данных. Поэтому выберите переключатель Single document и нажмите кнопку Next.В результате мы перейдем к самому интересному для нас окну мастера MFCAppWizard — Step 2 of 6, показанному на рис.3 — именно здесь мы будемопределять параметры базы данных.
Первое, что сразу бросается вглаза — это группа переключателей What database support would you like toinclude? (Какую поддержку базы данных вы хотите включить в проект) и кнопкаData Source… (Источник данных). Сначала рассмотрим поддержку. Здесьвозможны четыре варианта:
· None (Нет) — не обеспечивается поддержкабаз данных (по умолчанию). Не используйте этот переключатель, если есть хотьмалейший шанс, что приложению потребуется работа с базой данных — добавлениетакой поддержки позднее потребует значительных усилий.
· Header files only (Только заголовочныефайлы) — AppWizard создает и включает файл заголовка ,обеспечивая основную поддержку базы данных. Вы можете создавать наборы записей(recordset) и затем проверять и модифицировать их. При выборе этогопереключателя, если в дальнейшем потребуется обеспечить работу с базами данных,основную работу можно будет «поручить» мастеру ClassWizard.
· Database view without file support (Просмотрбазы данных без файловой поддержки) — предписывает AppWizard создать основанноена формах приложение, в котором просмотр и модификация записей производитсячерез набор записей. Приложение не поддерживает сериализацию документов, таккак большинство приложений баз данных работает на основе записей быстрее, чемна
основе файлов.
· Database view with file support (Просмотрбазы данных с файловой поддержкой) — предписывает создать, основанное на формахприложение, в котором просмотр и модификация записей также производится черезнабор записей. В данном случае приложение поддерживает сериализацию, что можетиспользоваться, например, для обновления файла настроек пользователя.
Рис. 3
ВыберитепереключательDatabase view with file support.
Теперь необходимо указатьисточник данных, с которым мы будем работать. Для этого нажмите кнопку DataSource..., после чего откроется диалоговое окно Database Options(Параметры базы данных), показанное на рис.4
Рис.4 Диалоговое окно DatabaseOptions
Теперь требуется выбрать один изпереключателей Recordset type (Тип набора записей). Набор записей (Recordset)— это, говоря несколько упрощенно, выборка из таблицы (или запроса) базыданных.
Существуют три вида набора записей:
· Snapshot (Моментальный снимок) —статическая копия данных, которые содержатся в одной или нескольких таблицахбазы данных. При выборе этого переключателя результат выполнения запроса будетзагружен в один мгновенный список, т. е. вы получаете полную картинуинтересующего вас содержимого базы данных и можете использовать ее в качествеосновы для последующей работы. Этот тип набора записей используется в основномдля поиска и обобщения данных, и у него есть три основных недостатка. Во-первых,вы не увидите обновлений, если они сделаны по сети другими пользователями, аэто означает, что ваше решение будет основываться на устаревшей информации.Во-вторых, загрузка всех этих записей одновременно означает, что вы сильнонагружаете сеть: В-третьих, пользователю, скорее всего, надоест ждать, показаписи загрузятся, и он начнет проявлять недовольство по поводу медленнойработы сети. Но есть и два преимущества. Во-первых, как только записизагрузятся, активность в сети со стороны рабочей станции будет достаточно мала— сеть освобождается для других запросов, и в общем случае пропускнаяспособность сети улучшится. Во-вторых, так как все запрашиваемые записинаходятся теперь на машине пользователя, общая производительность приложениядля него также повысится.
· Dynaset (Динамический набор) —динамическая копия данных, которые содержатся в одной или нескольких таблицахбазы данных. В отличие от моментального снимка, любые внесенные в наборизменения сразу же становятся доступны всем остальным пользователям базыданных. При выборе этого переключателя Visual C++ создает отдельный указательдля каждой запрашиваемой записи. Кроме того, с сервера загружаются только тезаписи, которые действительно нужны для заполнения формы. Преимущества такогоподхода очевидны — записи на экране появляются практически немедленно. Помимоэтого, вы также будете в курсе тех изменений, которые другиепользователиосуществляют в базе данных. И, наконец, другие пользователи будут знать обизменениях, которые делаете вы, так как если записи изменились, то они сразу жезагружаются на сервер. Совершенно очевидно, что этот подход требует практическипостоянного доступа к серверу, что будет снижать общую пропускную способностьсети, а также производительность приложения. Этот переключатель следуетвыбирать для создания приложений, где пользователь больше всего времени будеттратить на корректировку данных. Это также наилучший выбор для больших базданных, потому что будет загружаться только та информация, котораядействительно нужна пользователю.
· Table(Таблица). Предыдущие две опции работают на уровне записей, при использованииже табличного подхода (доступен только для модели DАО и нами использоваться не будет)результат выполнения запроса помещается во временную таблицу. Это не толькосокращает объем информации, загружаемой с сервера, но и означает, что вы, какпрограммист, сразу можете непосредственно манипулировать полями и записямивременной таблицы. Каковы затраты при таком режиме работы? Если невнимательноподойти к формированию запроса, то процесс загрузки с сервера может оказатьсяболее длительным, чем при использовании набора записей. Кроме того, можно неувидеть никаких изменений, сделанных другими пользователями, а они не смогутувидеть изменения, сделанные вами.
Для нашегопримера установите переключатель Snapshot и нажмите кнопку ОК.После регистрации соединения с базой данных вы увидите блок диалога SelectDatabase Tables. Выберите таблицы базы данных, где необходимо выделить тетаблицы или запросы (queries), которые требуется включить в набор записей. Внашем простейшем случае это пока одна таблица, например — jobs.
После нажатияна кнопку ОК вы вернетесь к диалоговому окну MFC AppWizard — Step2 of 6, где, правда, изменилась надпись под кнопкой Data Source...,которая теперь сообщает о выбранных таблицах. На данном этапе конфигурированиеприложения для использования базы данных pubs завершается. Три следующие окна мастера для нас неинтересны,поэтому просто четыре раза нажмите кнопку Next. В результате на экране появитсядиалоговое окно MFC AppWizard — Step 6 of 6, аналогичное показанному нарис. 5. В отображенном списке выделите элемент CDBView, чтобы обратитьвнимание на его базовый класс — CRecordView, с которым мы подробнопознакомимся чуть ниже. Нажмите кнопку Finish, и Visual C++ отобразитдиалоговое окно New Project Information.
Рис. 5 ДиалоговоеокноMFCAppWizard — Step 6 of 6
Рис. 6 Приложение,созданное мастером AppWizard, не предоставляет пользователюникакой информации осодержимом базы данных
2. Извлечение информации из базы данных.
Подготовка формы для отображения данных.
В нашем примере мы должны научиться манипулироватьданными одной единственной таблицы — jobs БД pubs. Используемые нами столбцы этой таблицы перечислены в таблице 1.
Таблица 1. Используемые столбцы таблицы jobs.
Нужно создать форму для отображения информации о должностях(см. Рис. 7).
Рис. 7
Примечание:
Есливы хотите, использовать русские названиядля полей (столбцов) таблицы, то перед тем, как набирать эти названия, необходимоизменить основной язык для окна диалога. Щелкните правой кнопкой мыши на идентификаторе окна диалога IDD_PRIM_FORM (на рис. 1 он обведен рамкой) и в появившемсяконтекстном меню выберите команду Properties (Свойства), в результате чего наэкране появится диалоговое окно Dialog Properties (Свойства диалога) (рис. 8).В комбинированном списке Language (Язык) выберите Russian. – в двух местахDialog
Рис. 8
Если теперь скомпилировать изапустить приложение, то на экране появится окно, отображающее форму с пустымиполями. Однако, несмотря на то, что мы присвоили всем элементам управленияформы соответствующие идентификаторы и знаем, что в таблице базы данных естьинформация, она не отображается в окне.
Придадим окну формы болеепривлекательный вид. Необходимо немного модифицировать функцию: CMainFrame::PreCreateWindow
ClassView→CMainFraim→PreCreateWindow(CREATESTRUCT&cs).
Вот как она должна выглядеть:
BOOLCMainFrame::PreCreateWindowfCREATESTRUCTS cs)
{
// Изменяем размеры главного окна
cs.cx= 376;
cs.cy= 272;
returnCFrameWnd::PreCreateWindow(cs);
}
Примечание:
Ваши значения могут отличаться отприведенных здесь значений (поскольку они зависят от размеров окна диалога). (Вданном случае они равны 242x106, и в качестве шрифта установлен MS Sans Serif,8.). Подберите значения, улучшающие вид вашей формы.В результате этих минимальных добавлений внешний вид окна формы улучшился.
После усовершенствования внешнеговида формы переходим непосредственно к работе с базой данных.
3. Отображение и обновление содержимого базы данных.
Для того чтобы отобразить данные из таблицы базы данных,необходимо выполнить определенные действия. Для получения информации из таблицы базы данных требуется:
1.
2.
3.
4.
Мы пока ничего из этого несделали (правда, очень многое за нас выполнила библиотека MFC). Запуститеприложение, обратив внимание на то, что на панели инструментов кнопкиперемещения на следующую и последнюю записи доступны, а на предыдущую и первую— нет. Попробуйте понажимать на них. Как видите, они реагируют на нажатия, хотяв полях ничего и не отражается. О чем это говорит? О том, что библиотека MFCсама реализовала три первых этапа процесса получения информации,воспользовавшись для этого теми параметрами, которые мы указали при созданиипроекта.
Убедитесьв этом, просмотрев соответствующий код в вашем проекте.
********Class CPrimSet *******
CStringCPrimSet::GetDefaultConnect()
{
// Параметрыисточникаданных
// CONNECT1- название источника данных
return_T("ODBC;DSN=CONNECT1");
}
CString CPrimSet::GetDefaultSQL()
{// Параметрытаблицы
return _T("[dbo].[jobs]");
}
class CPrimSet: public CRecordset
{
public:
CPrimSet(CDatabase* pDatabase =NULL);
DECLARE_DYNAMIC(CPrimSet)
// //Переменные для отображения данных строки таблицы
//{{AFX_FIELD(CPrimSet, CRecordset)
int m_job_id;
CString m_job_desc;
BYTEm_min_lvl;
BYTEm_max_lvl;
//}}AFX_FIELD
…
};
На нашу долю осталась реализациятолько последнего, четвертого, этапа — отображение результатов. Для этого нужносоздать соответствующие переменные.
Раскройте спроектированное ранеедиалоговое окно IDD_DB_FORM и принажатой клавише дваждыщелкните на элементе управления. В результате на экране появится диалоговоеокно Add Member Variable (Добавитькомпонентную переменную), показанное на рис. 9. В комбинированном списке Member variable name (Имя компонентнойпеременной) этого окна необходимо выбрать соответствующую переменную — в данномслучае m_pSet->m_job_id.
Рис. 9. ДиалоговоеокноAdd Member Variable
Примечание:
Здесь m_pSet — указатель на объект класса, производного от CRecordset, содержащий текущую запись.Переменная m_job_id в этом объекте содержит текущее значение поля job_id из таблицы jobs. Есливы посмотрите содержимое комбинированного списка Member variable name, то увидите указатель для всех полей запроса,который для нас сконструировала библиотека MFC, и поэтому можно повторитьрассмотренную процедуру сопоставления элементов управления формы с переменнымидля каждой из них.
После того как все элементыуправления сопоставлены переменным, обязательно убедитесь, что все сделанокорректно. Используйте для этого команду View/ClassWizard… (или одноименную кнопку на панели инструментов), чтобы отобразитьдиалоговое окно MFC ClassWizard, вкотором выберите вкладку MemberVariables (Компонентные переменные). В раскрывающемся списке Class name необходимо выбрать класс CPrimView. Списоккомпонентных переменных должен выглядеть так, как показано на рис. 10.
Рис. 10. Компонентные переменныекласса CPrimView
Теперь скомпилируйте и выполнитеприложение. Сразу после запуска вы увидите окно, показанное на рис. 11.Попробуйте перемешаться по записям базы данных, воспользовавшисьсоответствующими кнопками на панели инструментов или командами меню. И хотя мыпока не написали ни строчки кода, приложение работает прекрасно — можнопереходить от записи к записи и даже изменять значения полей.
Рис. 11
Если сейчас выполнить приложение, то можно будетперемещаться по записям базы данных, а также их корректировать
3. Добавление и удаление записей в таблице.
Добавление записей в таблицу.
Как и многое другое, этувозможность реализовать достаточно просто, поскольку большую часть работы мыможем переложить на библиотеку MFC. Основная наша задача — это корректнымобразом предоставлять ей информацию.
Позаботимся о некоторых связанныхс основной задачей вопросах. Необходимо создать либо элемент меню, либо кнопкуна панели инструментов, либо и то, и другое. Основываясь на собственныхсимпатиях, остановимся на создание кнопки.
1. Раскройте вкладку ResourceView (ресурсы) окна проектов. Щелкните по значку +, расположенному рядом спапкой Toolbar, а затем по IDR_MAINFRAME. Появится панельинструментов.
2. Выделите пустую кнопку,расположенную справа, и нарисуйте какой-либо символ New Record (Новая запись), например, такой, как показан на рис. 12.Переместите кнопку на место, расположенное сразу после четырех кнопокперемещения по базе данных.
Рис. 12. Новая кнопка на панели инструментов для добавленияновой записи
3. Дважды щелкните по вновьсозданной кнопке на разрабатываемой панели инструментов. Раскроется диалоговоеокно Toolbar Button Properties, (Свойства кнопки панелиинструментов). Введите в качестве идентификатора в список ID (Идентификатор) ID_RECORD_APPEND.
4. В поле Prompt (Подсказка) наберите текст — Append a new record to thetable.New Record (Добавление новой записи в таблицуНовая запись), какпоказано на рис. 13.
5. Нажмите кнопку закрытия вправом верхнем углу диалогового окна ToolbarButton Properties, и Visual C++ автоматически присвоит новой кнопкеидентификатор ID_RECORD_APPEND.
Рис. 13.
Теперь необходимо сопоставитьсозданной кнопке некоторые действия. Откройте окно Class Wizard, выполнив команду View/ClassWizard,выберите вкладку Message Maps (картасообщений) и в списке Object IDsвыделите элемент ID_RECORD_APPEND, ав
раскрывающемся списке Class name выберите CPrimView — класс, который служит дляпросмотра базы данных. Именно для него потребуется добавить некоторый код.Далее в списке Message выделитеэлемент COMMAND и нажмите кнопку Add Function, в результате чего наэкране появится диалоговое окно AddMember Function, в котором, уже предложено некоторое имя (рис. 14),базирующееся на идентификаторе кнопки (присваивайте всем идентификаторамсодержательные имена).
Рис. 14. Если идентификатору присвоено содержательное имя,то можно просто нажать кнопку ОК
Нажмите кнопку ОК, и диалоговоеокно MFC ClassWizard примет вид,показанный на рис. 15. В этом окне нажмите кнопку Edit Code (Редактировать код), чтобы сразу перейти к шаблонусозданной функции, куда потребуется добавить код, приведенный ниже. Просмотрите примечание, расположенное после текстакода.
voidCPrimView::OnRecordAppend()
{
//TODO: Add your command handler code here
//Сначала проверяем, не была лиоткрыта база данных
// в режиме только для чтения. Если это так,
//то выводим предупреждение и выходим изфункции
if(m_pSet->CanAppend() == 0)
MessageBox(«Можно только просматривать записи »,
"Ошибка добавления записи",
MB_OK | MB_ICONWARNING);
else
{
// Перемещаемся на первую запись
m_pSet->MoveFirst();
// Создаем пустую запись,
// в которую пользователь будетвводить значения
m_pSet->AddNew();
// Устанавливаем флаг перехода врежим добавления записи
m_bAdd= TRUE;
// Обновляем поля формы
UpdateData(FALSE);
}
}
Рис. 15. Диалоговое окно MFC ClassWizard после проведенныхдействий
Примечание:
Для успешной работы приложения необходимо ввести новуюпеременную для фиксации режима добавления записи m_bAdd:В окне ClassView щелкните правой кнопкой на имени класса CPrimView и выберите в появившемся контекстном меню команду Add→AddVariable. Появится диалоговое окно Add Member Variable Wizard. В раскрывающемся списке Access выделите метод доступа protected, в текстовом поле раскрывающегося списка Variable type сохраните тип переменной bool, в текстовом поле Variable name введите идентификатор переменной m_bAdd и нажмите кнопку Finish. Проинициализируем добавленную переменную значением FALSE для нормальной работы в режиме просмотра записей.
CPrimView→CPrimView()
Вставьте код:
CDBView::CDBView():CRecordView(CDBView::IDD)
{
m_bAdd =FALSE;
}
Рассмотрим, как работает функция OnRecordAppend. Прежде всего онапроверяет, можно ли добавлять данные в базу данных. Сделать это можно с помощьюфункции CanAppend класса CRecordset. Если добавлять записинельзя, то необходимо вывести сообщение об ошибке и завершить работу, что исделано в нашем примере.
Далее нужно подготовить элементыуправления в форме для ввода новых значений. Для этого мы перемещаемся в началонабора записей (функция MoveFirst),вызываем специальную функцию AddNew,подготавливающую результирующий набор к приему новой записи, и устанавливаемфлаг, что это новые данные. Осталось только очистить поля элементов управления,что и делает функция UpdateData(FALSE).
Итак, элементы управления в формеи результирующий набор готовы к приему данных. Теперь необходимо решить вопрос,каким образом и где передать введенные в форме значения в результирующий набор.Самым простым представляется способ добавления специальной кнопки, нажатие накоторую вызовет специальный обработчик, где введенные значения перепишутся врезультирующий набор. Второй способ не требует создания дополнительныхэлементов управления и для фиксации значений использует переопределеннуюфункцию перемещения по записям результирующего набора Move. (В классе CPrimViewвыделите в списке функцию OnMove идобавьте заготовку для этой функции). Кроме того, необходимо определитьпеременную m_bAdd.
BOOLCPrimView::OnMove(UINTnIDMoveCommand)
{
//TODO: Add your specialized code here and/or call the base class
// Проверяем, в каком режиме —добавления или перемещения —
// мы находимся
if(m_bAdd) {
// «Выходим из режима добавления»
m_bAdd=false;
UpdateData();
if (m_pSet->CanUpdate() )
m_pSet->Update();
m_pSet->Requery();
UpdateData(FALSE);
returnTRUE;
}
else
// Переходим к следующей записи врезультирующем наборе
returnCRecordView::OnMove(nIDMoveCommand);
}
Рассмотрим логику работы функции OnMove. Если мы попали в нее послеввода новой записи (установлен флаг m_bAdd),то переписываем введенные значения в базу данных. В противном случае простопереходим к следующей записи. Нас, естественно, интересует режим добавления.Прежде всего необходимо прочитать данные из элементов управления формы.Обратите внимание, что переменные класса CDBViewопределены так, что мы это делаем непосредственно в результирующий набор,используя функции обмена полями данных, например, для поля IDC_PROD.
DDX_FieldText(pDX, IDC_PROD,m_pSet->m_ProductName, m_pSet);
Если никакой ошибки не произошло,то перечитаем информацию из базы данных, чтобы работать с самым последнимнабором. Теперь осталось только обновить элементы управления в форме. Помните,в функции OnRecordAppend мы передвходом в режим добавления переместились на первую запись результирующегонабора. Поэтому необходимо вызвать функцию UpdateData(FALSE),чтобы отобразить ее в элементах управления формы. И, наконец, не забываемсбросить флаг m_bAdd, чтобы избежать ошибок.
Вернемся к табл.1, гдепредставлены поля таблицы jobs. Видим, что устолбца job_idустановлен тип данных IDENTITY.Это означает, что система управления базами данных сама позаботится оприсвоении значения этому столбцу. Чтобы решить эту проблему достаточнопоменять переменную, с которой связан элемент управления IDC_EDIT4 (например,на m_job_Nom типа long),и тем самым переложить задачу на СУБД.
Кроме этого, в код требуется также добавитьодну строку, чтобы можно было видеть информацию об идентификаторе job_id.
voidCPrimView::DoDataExchange(CDataExchange* pDX)
{// Для отображения значений поля job_idтаблицы
// необходимо выполнить присваивание
m_job_Nom=m_pSet->m_job_id;
// Осуществляем обмен данными сэлементами управления в форме
CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPrim_1View)
DDX_FieldText(pDX, IDC_EDIT3,m_pSet->m_min_lvl, m_pSet);
DDX_FieldText(pDX, IDC_EDIT2,m_pSet->m_max_lvl, m_pSet);
DDX_FieldText(pDX, IDC_EDIT1,m_pSet->m_job_desc, m_pSet);
DDX_Text(pDX, IDC_EDIT4, m_job_Nom);
//}}AFX_DATA_MAP
}
Уберем значение идентификатора с экрана на время вставкиновой записи. Для этого немного модифицируем код в двух функциях OnRecordAppendи On Move, как
показанониже.
voidCPrimView::OnRecordAppend()
{
// TODO: Add your command handlercode here
// Сначала проверяем, не была лиоткрыта база данных
//в режиме только для чтения. Если это так,
//товыводим предупреждение и выходим из функции
if(m_pSet->CanAppend()== 0)
MessageBox(«Можно только просматривать записи»,
«Ошибкадобавления записи»,
MB_OK| MB_ICONWARNING);
else
{
// Скрываем элементы управления навремя ввода новой записи
GetDlgItem(IDC_EDIT4)->ShowWindow(SW_HIDE);
// Устанавливаем фокус на поле вводаназвания
GetDlgItem(IDC_EDIT1)->SetFocus();
//Перемещаемся на первую запись
m_pSet->MoveFirst();
// Создаем пустую запись,
//в которую пользователь будетвводить значения
m_pSet->AddNew();
// Устанавливаем флаг перехода врежим добавления записи
m_bAdd = TRUE;
// Обновляем поля формы
UpdateData(FALSE);}
}
BOOLCPrimView::OnMove(UINT nIDMoveCommand)
{
//TODO: Add your specialized code here and/or call the base class
// Проверяем, в каком режиме —добавления или перемещения —
// мы находимся
if(m_bAdd) {
// «Выходим из режима добавления»
m_bAdd=false;
// После завершения ввода сноваотображаем элементы управления
GetDlgItem(IDC_EDIT4)->ShowWindow(SW_SHOW);
UpdateData();
if (m_pSet->CanUpdate() )
m_pSet->Update();
m_pSet->Requery();
UpdateData(FALSE);
returnTRUE;
}
else
// Переходим к следующей записи врезультирующем наборе
returnCRecordView::OnMove(nIDMoveCommand);
}
После внесения этих изменений скомпилируйте и запуститеприложение.
После нажатия кнопки New Record иввода информации о новой должности основное окно будет иметь вид представленныйна рис. 16.
Рис. 16. Так теперь выглядит основное окно приложения врежиме ввода новой записи в базу данных
Итак, теперь мы умеем обновлять и добавлять записи в базуданных. Следующим шагом является удаление записей.
4. Удаление записей из таблицы.
Как обычно, начнем с того, чтодобавим в наше приложение кнопку на панели инструментов, нажатие на которуюпозволит перейти в режим удаления. Создайте функцию OnRecordDelete,воспользовавшись стандартной описанной ранее.
void CPrimView::OnRecordDelete()
{
// TODO: Add your command handlercode here
// Последняявозможностьсохранитьзапись
if(MessageBox(«Вы действительно хотите удалить этузапись?»,
"Удаление записи",
MB_OKCANCEL|MB_ICONQUESTION|MB_DEFBUTTON2)== IDOK)
//Удаляем запись
m_pSet->Delete();
//Перечитываеминформацию из БД.
m_pSet->Requery();
// Переходимк следующей записи
m_pSet->MoveNext ();
// Еслимы переместились за последнюю запись,
//тоустанавливаем указатель на последнюю запись
if(m_pSet->IsEOF())
m_pSet->MoveLast();
// Еслитаблица стала пустой, то очищаем поля.
if(m_pSet->IsBOF())
m_pSet->SetFieldNull(NULL);
// Обновляемполя формы
UpdateData(FALSE);
}
Правила хорошего тона требуют,чтобы перед удалением пользователю был задан вопрос, хорошо ли он подумал и неслучайно ли нажал кнопку удаления. Если запись действительно надо удалить, тосмело нажимайте кнопку ОК, после чего будет вызвана функция Delete класса CRecordset,которая проведет корректное удаление записи из базы данных. Чтобы обновитьнабор, с которым мы работаем, необходимо вызвать функцию Requery, иначе мы будем продолжать работать с записью, которой вбазе данных уже нет. Этот шаг был бы не нужен, если бы мы работали сдинамическим набором — как вы помните, вэтом случае результирующий набор обновляется одновременно с обновлением базыданных. Новыми при удалении являются следующие два действия — проверка на выходза начало и конец записей. Действительно, если мы переместились (вызов функции MoveNext) за последнюю запись (проверкаif (m_pSet->isEOF ())), то непонятно, на что в этом случае будет указыватьуказатель. Поэтому его нужно установить на последнюю запись результирующегонабора (вызов m_pSet->MoveLast ()).Аналогичные действия необходимо предпринять для проверки на выход за«левую границу», т. е. за первую запись (вызов if(m_pSet->isBOF())). Эта ситуация возникает тогда, когда из таблицы удаляетсяпоследняя строка и требуется очистить поля единственной пустой строки (ВЫЗОВm_pSet->SetFieldNull (NULL)).
Как и в случае обновления идобавления новой записи, здесь также всю основную работу делает библиотека MFC,а точнее, ее класс CRecordset.
5. Сортировка записей.
Для демонстрации этой возможностисоздадим специальные элементы меню, внешний вид которых представлен на рис 17.Используем для организации сортировки два критерия: по идентификаторудолжности, по названию. Для создания элементов меню откройте окно ResourceView→Menuи дважды щелкните левой кнопкоймыши на идентификаторе ресурса IDR_MAINFRAIM. В строке заголовков менювведите текст &Sort(Сортировка) и добавьте подпункты — &ID_JOB и&JOB_NAME (с именами S_JOB_ID и S_JOB_DESC, а также соответствующими подсказками типа Sort by job_idJOB_IDsort).
Рис. 17.Окно свойствэлементов меню
После того, как элементы менюсозданы и им присвоены соответствующие идентификаторы, необходимо создатьобработчик соответствующих команд (воспользуйтесь ClassWizard аналогично построению функций для кнопок).
//Сортировка
voidCPrimView::OnSortJobId()
{
OnSort(«job_id»);
}
voidCPrimView::OnSortJobDesc()
{
OnSort(«job_desc»);
}
Добавьте в класс CPrimView функцию OnSort, непосредственноосуществляющую сортировку по записям.
//Сортировка по записи
Рис. 18
voidCPrimView::OnSort(CString szText)
{
m_pSet->Close();
m_pSet->m_strSort=szText;
m_pSet->Open();
UpdateData(FALSE);
}
6. Поиск информации в базе данных.
Необходимо потратить некотороевремя на модификацию меню и/или панели инструментов, прежде чем переходитьнепосредственно к поиску. Добавим кнопку. Для того чтобызапросить у пользователя, что именно требуется найти, необходимо создатьнебольшое диалоговое окно. В окне ResourceView щелкните правой кнопкой мыши на папке Dialog и выберите из контекстного меню Insert Dialog.
Рис. 19. Свойства блока диалога
Наберите IDD_DLG_FIND в поле ID.Далее следует дать этому диалоговому окну более содержательный заголовок.Наберите «Поиск информации в базе данных» в поле ввода Caption(Заголовок), а затем нажмите кнопку Close, расположенную в правом верхнем углуокна, чтобы завершить, ввод изменений.
Теперь нам необходимо добавитьодин элемент управления Static Textи связанный с ним элемент управления EditBox, чтобы завершить создание блока диалога. Последняя часть работы дляэтого диалогового окна — установить свойства элемента управления Edit Box. Щелкните правой кнопкой мышина этом элементе управления и выберите Properties из контекстного меню. Изменитесвойство ID в диалоговом окне Edit Properties (Свойства текстового поля) наIDC_RECORD_FIND. Нажмите кнопку Close.Теперь при нажатой клавише дважды щелкните на элементе управления EditBox. При этом вы увидите блок диалога Addinga Class (Добавить класс). Причина появления этого блока диалога заключа