This page was last modified 12:06, 28 October 2007.
Пример базы данных с навигацией
From Forum Nokia Wiki
Перевод с английского, оригинальная статья находится здесь.
Contents |
Введение
Database Management System (DBMS (СУБД)) очень важный компонент Symbian OS (RU). В следующем примере иллюстрируется навигация в таблице базы данных в DBMS.
MyDatabase.h
#ifndef __MYDATABASE_H__ #define __MYDATABASE_H__ #include <e32std.h> #include <d32dbms.h> // RDbNamedDatabase #include <f32file.h> // RFs // для TDesC #include <e32cmn.h> typedef TBuf<1024> TQueryBuffer; //Имя базы данных _LIT(KMyDatabaseName, "DBMSTest.db"); // Константы для таблицы MyTable // Имя таблицы _LIT(KMyTable, "MyTable"); // Столбцы таблицы _LIT(KPrimaryCol, "MyTableId"); _LIT(KNameCol, "Name"); _LIT(KPhoneCol, "Phone"); _LIT(KEMailCol, "EMail"); class TMyTableItem { public: TMyTableItem(): iPrimeId(-1){}; public: TInt iPrimeId; TBuf8<100> iName; TBuf8<20> iPhone; TBuf8<40> iEMail; public: inline void Reset() { iPrimeId = 0; iName.Zero(); iPhone.Zero(); iEMail.Zero(); } }; class CMyDatabase : public CBase { public: // Конструктор и деструктор static CMyDatabase* NewL(); ~CMyDatabase(); public: TInt Close(); // Для закрытия базы данных /************************* Таблица MyTable ******************/ //Начало кода для таблицы MyTable void CreateMyTableTableL(); void CreateMyTableIndexL(); void DropMyTableTable(); TInt AddMyTableRecord(TMyTableItem& aMyTableItem); RArray<TMyTableItem> GetMyTableRecordsByKeyL(TDesC& aSearchString); TBool UpdateMyTableRecord(TMyTableItem& aMyTableItem); void ReadMyTableItemsL(RArray<TMyTableItem>& aMyTableItemArray); TBool RemoveMyTableRecord(TMyTableItem& aMyTableItem); TInt RemoveAllMyTableRecords(TInt& aResultCount); TBool GetMyTableRecordsById(TInt& Id,TMyTableItem& aMyTableItem); // Функции навигации по таблице void PrepareMyTableView(); TBool GetMyTableFirstRecord(TMyTableItem& aMyTableItem); TBool GetMyTableNextRecord(TMyTableItem& aMyTableItem); TBool GetMyTablePreviousRecord(TMyTableItem& aMyTableItem); TBool GetMyTableLastRecord(TMyTableItem& aMyTableItem); // Для возвращения число записей в таблице MyTable TInt GetMyTableCount(); //Конец кода для таблицы MyTable private: // Конструктор void ConstructL(); CMyDatabase(); private: // Члены класса RArray<TMyTableItem> aMyTableItemArray; //Для проверки успешности выполнения функции. TBool iReturnFlag; //Вспомогательные переменные для функций навигации TBool BookmarkFlag; TBool iAtBeginningFlag; TDbBookmark iBookmark; //Для работы с базой данных RFs iFsSession; RDbNamedDatabase iMyDatabase; //Для навигации RDbView iMyTableView; }; #endif // __MYDATABASE_H__
MyDatabase.cpp
Создание базы данных и таблиц
#include <bautils.h> // BaflUtils::FileExists #include <eikenv.h> #include "MyDatabase.h" // --------------------------------------------------------------------------- // CMyDatabase::NewL() // // Создаем экземпляр MobiCRM. // --------------------------------------------------------------------------- CMyDatabase* CMyDatabase::NewL() { CMyDatabase* self = new (ELeave)CMyDatabase(); CleanupStack::PushL(self); self->ConstructL(); CleanupStack::Pop(); return self; } // --------------------------------------------------------------------------- // CMyDatabase::ConstructL() // // Вторая фаза конструктора. Если сессия RFs не может быть создана - // происходит сброс. Здесь выполняется Создание/Открытие базы данных // --------------------------------------------------------------------------- void CMyDatabase::ConstructL() { TInt err = iFsSession.Connect(); if(err) User::Leave(err); TFileName DBFileName; // Путь к папке private программы (без диска) //Напр.: Для UID3=0xe42d8cfd, эта папка будет \Private\e42d8cfd\ iFsSession.PrivatePath(DBFileName);//Т.о. DBFileName=\Private\e42d8cfd\ TFindFile PrivFolder(iFsSession); // ищем диск if(KErrNone == PrivFolder.FindByDir(DBFileName, KNullDesC)) { DBFileName.Copy(PrivFolder.File()); //Теперь DBFileName= C:\Private\e42d8cfd\DBMSTest.db или E:\.. DBFileName.Append(KMyDatabaseName); if(!BaflUtils::FileExists(iFsSession, DBFileName)) { // базы данных не и мы ее создаем User::LeaveIfError(iMyDatabase.Create(iFsSession, DBFileName)); // и создаем необходимые таблицы CreateMyTableTableL(); //Закрываем базу - мы откроем ее заново в дальнейшем Close(); } else { User::LeaveIfError(iMyDatabase.Open(iFsSession, DBFileName)); PrepareMyTableView(); } } } // --------------------------------------------------------------------------- // CMyDatabase::CMyDatabase() // // Конструктор // --------------------------------------------------------------------------- CMyDatabase::CMyDatabase() { } // --------------------------------------------------------------------------- // CMyDatabase::~CMyDatabase() // // Деструктор MobiCRM. Освобождение ресурсов. // --------------------------------------------------------------------------- CMyDatabase::~CMyDatabase() { Close(); // Закрываем базу данных iFsSession.Close(); } // --------------------------------------------------------------------------- // CMyDatabase::Close() // // Закрываем базу данных. // --------------------------------------------------------------------------- TInt CMyDatabase::Close() { iMyDatabase.Close(); return KErrNone; } //Все операции с базой данных выполнены
Операции с таблицами
Следующий код демонстрирует работу с таблицами
//Начало операций с таблицами // --------------------------------------------------------------------------- // CMyDatabase::PrepareMyTableView() // // Подготовка отображения (view) для навигации. // --------------------------------------------------------------------------- //Подготовка глобального отображения (view) таблицы БД для навигации. void CMyDatabase::PrepareMyTableView() { //SELECT * FROM MyTable ORDER BY MyTableId _LIT(KSelect,"SELECT * FROM "); _LIT(KOrderBy, " ORDER BY "); TQueryBuffer QueryBuffer; QueryBuffer.Copy(KSelect); QueryBuffer.Append(KMyTable); QueryBuffer.Append(KOrderBy); QueryBuffer.Append(KPrimaryCol); iMyTableView.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); iMyTableView.EvaluateAll(); iMyTableView.FirstL(); } // --------------------------------------------------------------------------- // CMyDatabase::CreateMyTableTableL() // // Создаем таблицу MyTable. Сброс, если таблица не может быть создана. // --------------------------------------------------------------------------- void CMyDatabase::CreateMyTableTableL() { // Укажем столбцы для таблицы MyTable TDbCol primaryCol(KPrimaryCol, EDbColInt32); TDbCol nameCol(KNameCol, EDbColText8); TDbCol phoneCol(KPhoneCol, EDbColText8); TDbCol emailCol(KEMailCol, EDbColText8); primaryCol.iAttributes= TDbCol::EAutoIncrement; nameCol.iAttributes= TDbCol::ENotNull; // Добавим столбцы в множество столбцов CDbColSet* MyTableColSet = CDbColSet::NewLC(); MyTableColSet->AddL(primaryCol); MyTableColSet->AddL(nameCol); MyTableColSet->AddL(phoneCol); MyTableColSet->AddL(emailCol); // Создаем таблицу MyTable User::LeaveIfError(iMyDatabase.CreateTable(KMyTable,*MyTableColSet)); CleanupStack::PopAndDestroy(MyTableColSet); } // --------------------------------------------------------------------------- // CMyDatabase::AddMyTableRecord() // // Добавляем запись в базу данных с помощью RDbView и SQL // --------------------------------------------------------------------------- TInt CMyDatabase::AddMyTableRecord(TMyTableItem& aMyTableItem) { if(aMyTableItem.iName.Length()==0) { return KErrGeneral; } TQueryBuffer QueryBuffer; // SELECT * FROM MyTable QueryBuffer.Copy(_L("SELECT * FROM ")); QueryBuffer.Append(KMyTable); iMyDatabase.Begin(); RDbView MyView; MyView.Prepare(iMyDatabase, TDbQuery(QueryBuffer)); CleanupClosePushL(MyView); MyView.InsertL(); MyView.SetColL(2, aMyTableItem.iName); MyView.SetColL(3, aMyTableItem.iPhone); MyView.SetColL(4, aMyTableItem.iEMail); MyView.PutL(); // Здесь получим автоматически увеличиваемое уникальное MyTableId. aMyTableItem.iPrimeId = MyView.ColInt(1); CleanupStack::PopAndDestroy(1); // Myview iMyDatabase.Commit(); iMyTableView.Reset(); PrepareMyTableView(); GetMyTableLastRecord(aMyTableItem); return KErrNone; } // --------------------------------------------------------------------------- // CMyDatabase::DropMyTableTable() // // Последовательная (пошаговая) операция удаления таблицы MyTable. // Использованы RDbIncremental и инструкции DDL. // --------------------------------------------------------------------------- void CMyDatabase::DropMyTableTable() { _LIT(KDropTable, "DROP TABLE "); // Sql: DROP TABLE MyTable TQueryBuffer sqlStr; sqlStr.Append(KDropTable); sqlStr.Append(KMyTable); RDbIncremental incOp; TInt incStep = 0xFFFF; // Инициализация команды TInt incStat = incOp.Execute(iMyDatabase, sqlStr, incStep); while (incStep>0 && incStat==KErrNone) { incStat = incOp.Next(incStep); // Выполняем задачу } incOp.Close(); } // --------------------------------------------------------------------------- // CMyDatabase::ReadMyTableItemsL() // // Чтение всех записей таблицы MyTable // и сохранение их в массиве aMyTableItemArray // --------------------------------------------------------------------------- void CMyDatabase::ReadMyTableItemsL(RArray<TMyTableItem>& aMyTableItemArray) { aMyTableItemArray.Reset();//очистим массив TQueryBuffer QueryBuffer; // SELECT * FROM MyTable QueryBuffer.Copy(_L("SELECT * FROM ")); QueryBuffer.Append(KMyTable); RDbView Myview; Myview.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); Myview.FirstL(); // считываем данные while(Myview.AtRow()) { Myview.GetL(); TMyTableItem NewItem; NewItem.iPrimeId = Myview.ColInt(1); NewItem.iName.Copy(Myview.ColDes8(2)); NewItem.iPhone.Copy(Myview.ColDes8(3)); NewItem.iEMail.Copy(Myview.ColDes8(4)); // добавляем запись в RArray aMyTableItemArray.Append(NewItem); Myview.NextL(); } CleanupStack::PopAndDestroy(1); // Myview } // --------------------------------------------------------------------------- // CMyDatabase::GetMyTableRecordsByKeyL() // // Чтение всех записей соответствующих с переданной "Строкой Поиска" // из таблицы MyTable и сохранение их в массиве aMyTableItemArray // // --------------------------------------------------------------------------- RArray<TMyTableItem> CMyDatabase::GetMyTableRecordsByKeyL(TDesC& aSearchString) { RArray<TMyTableItem> aMyTableItemArray; aMyTableItemArray.Reset();//очистим массив //SELECT * FROM MyTable WHERE Name LIKE 'aSearchString' ORDER BY MyTableId _LIT(KSelect,"SELECT * FROM "); _LIT(KWhere, " WHERE "); _LIT(KLike, " LIKE '"); _LIT(KOrderBy, "' ORDER BY "); TQueryBuffer QueryBuffer; QueryBuffer.Copy(KSelect); QueryBuffer.Append(KMyTable); QueryBuffer.Append(KWhere); QueryBuffer.Append(KNameCol); QueryBuffer.Append(KLike); QueryBuffer.Append(aSearchString); QueryBuffer.Append(KOrderBy); QueryBuffer.Append(KPrimaryCol); RDbView Myview; Myview.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); Myview.FirstL(); // считываем данные while(Myview.AtRow()) { Myview.GetL(); TMyTableItem NewItem; NewItem.iPrimeId = Myview.ColInt(1); NewItem.iName.Copy(Myview.ColDes8(2)); NewItem.iPhone.Copy(Myview.ColDes8(3)); NewItem.iEMail.Copy(Myview.ColDes8(4)); // добавляем запись в RArray aMyTableItemArray.AppendL(NewItem); Myview.NextL(); } CleanupStack::PopAndDestroy(1); // Myview return aMyTableItemArray; } // --------------------------------------------------------------------------- // CMyDatabase::RemoveMyTableRecord() // // Удаление записи по столбцу первичного ключа PrimaryKey // --------------------------------------------------------------------------- TBool CMyDatabase::RemoveMyTableRecord(TMyTableItem& aMyTableItem) { //Получим значение первичного ключа Primary key //и сохраним в локальную переменную TInt aPrimeId = aMyTableItem.iPrimeId; // Очистим RArray чтобы определить правильный результат aMyTableItem.Reset(); iReturnFlag = EFalse; _LIT(KSelect,"SELECT * FROM "); _LIT(KWhere, " WHERE "); _LIT(KEqual," = "); // Sql: DELETE FROM MyTable WHERE MyTableId = aPrimeId TQueryBuffer QueryBuffer; QueryBuffer.Copy(KSelect); QueryBuffer.Append(KMyTable); QueryBuffer.Append(KWhere); QueryBuffer.Append(KPrimaryCol); QueryBuffer.Append(KEqual); QueryBuffer.AppendNum(aPrimeId); iMyDatabase.Begin(); RDbView Myview; // Подготовим отображение с сформированным запросом. Myview.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); Myview.FirstL(); // мы используем автоматически увеличиваемое значение // в качестве индекса, поэтому оно должно быть уникальным // но на всякий случай, используем 'while', вместо 'if' while(Myview.AtRow()) { if(iAtBeginningFlag) { Myview.GetL(); Myview.DeleteL(); Myview.NextL(); iMyTableView.Reset(); PrepareMyTableView(); GetMyTableFirstRecord(aMyTableItem); iAtBeginningFlag = EFalse; iReturnFlag = ETrue; break; } GetMyTablePreviousRecord(aMyTableItem); Myview.GetL(); Myview.DeleteL(); Myview.NextL(); iReturnFlag = ETrue; } CleanupStack::PopAndDestroy(1); // Myview iMyDatabase.Commit(); // сжимаем БД, удаляя удаленные данные физически. iMyDatabase.Compact(); if(iReturnFlag) { iMyTableView.Reset(); PrepareMyTableView(); if(iAtBeginningFlag) { aMyTableItem.Reset(); GetMyTableFirstRecord(aMyTableItem); } if(BookmarkFlag) { iMyTableView.GotoL(iBookmark); } } return iReturnFlag; } // --------------------------------------------------------------------------- // CMyDatabase::RemoveAllMyTableRecords() // // Асинхронное удаление записей. (RDbUpdate и DML) // Эта реализация все еще синхронна, т.к. использует // User::WaitForRequest. Вы должны реализовать асинхронную функцию // в виде активного объекта и интерфейса обратного вызова (callback). // --------------------------------------------------------------------------- TInt CMyDatabase::RemoveAllMyTableRecords(TInt& aResultCount) { _LIT(KDeleteFrom, "DELETE FROM "); // Sql: DELETE FROM MyTable TQueryBuffer QueryBuffer; QueryBuffer.Copy(KDeleteFrom); QueryBuffer.Append(KMyTable); RDbUpdate updOp; TRequestStatus incStat(1); TInt updStat = updOp.Execute(iMyDatabase, QueryBuffer, EDbCompareFolded); while (updStat==KErrNone && incStat ==1) { updOp.Next(incStat); // Запуск асинхронной функции // Она завершается немедленно. // Для простоты просто ждем окончания операции здесь. User::WaitForRequest(incStat); } aResultCount = updOp.RowCount(); updOp.Close(); if(updStat!=KErrNone) return updStat; // Системный код ошибки else return incStat.Int(); // KErrNone или Системный код ошибки } // --------------------------------------------------------------------------- // CMyDatabase::UpdateMyTableRecord() // // Обновление таблицы новыми значениями // содержащимися в переданном по ссылке аргументе TMyTableItem. // Здесь RDbView использован для обновления. // --------------------------------------------------------------------------- TBool CMyDatabase::UpdateMyTableRecord(TMyTableItem& aMyTableItem) { iReturnFlag = EFalse; TQueryBuffer QueryBuffer; QueryBuffer.Copy(_L("SELECT * FROM ")); QueryBuffer.Append(KMyTable); QueryBuffer.Append(_L(" WHERE ")); QueryBuffer.Append(KPrimaryCol); QueryBuffer.Append(_L(" = ")); QueryBuffer.AppendNum(aMyTableItem.iPrimeId); iMyDatabase.Begin(); RDbView Myview; Myview.Prepare(iMyDatabase, TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); Myview.FirstL(); if(Myview.AtRow()) { Myview.UpdateL(); Myview.SetColL(2, aMyTableItem.iName); Myview.SetColL(3, aMyTableItem.iPhone); Myview.SetColL(4, aMyTableItem.iEMail); Myview.PutL(); iReturnFlag = ETrue; //Нет ошибок } CleanupStack::PopAndDestroy(1); // Myview iMyDatabase.Commit(); return iReturnFlag; } // --------------------------------------------------------------------------- // CMyDatabase::GetMyTableRecordsById() // // Извлечение данных записи, с совпавшим Id // сохранение данных в переданном по ссылке аргументе TMyTableItem. // Здесь RDbView использован для обновления. // --------------------------------------------------------------------------- TBool CMyDatabase::GetMyTableRecordsById(TInt& Id,TMyTableItem& NewItem) { iReturnFlag = EFalse; //SELECT * FROM MyTable WHERE MyTableId = Id ORDER BY MyTableId _LIT(KSelect,"SELECT * FROM "); _LIT(KWhere, " WHERE "); _LIT(KSearch," = "); _LIT(KOrderBy, " ORDER BY "); TQueryBuffer QueryBuffer; QueryBuffer.Copy(KSelect); QueryBuffer.Append(KMyTable); QueryBuffer.Append(KWhere); QueryBuffer.Append(KPrimaryCol); QueryBuffer.Append(KSearch); QueryBuffer.AppendNum(Id); QueryBuffer.Append(KOrderBy); QueryBuffer.Append(KPrimaryCol); RDbView Myview; Myview.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); Myview.FirstL(); // считываем данные while(Myview.AtRow()) { Myview.GetL(); NewItem.iPrimeId = Myview.ColInt(1); NewItem.iName.Copy(Myview.ColDes8(2)); NewItem.iPhone.Copy(Myview.ColDes8(3)); NewItem.iEMail.Copy(Myview.ColDes8(4)); Myview.NextL(); iReturnFlag = ETrue; } CleanupStack::PopAndDestroy(1); // Myview return iReturnFlag; }
Функции навигации
Следующие функции обеспечивают навигацию по таблице.
/**************************Функции навигации*********************************/ //Следующая функция обеспечивает навигацию //в прямом направлении по отображению таблицы TBool CMyDatabase::GetMyTableNextRecord(TMyTableItem& NewItem) { iAtBeginningFlag = EFalse; BookmarkFlag=EFalse; iReturnFlag = EFalse; if(iMyTableView.AtRow()) { iMyTableView.NextL(); if(iMyTableView.AtEnd()) { iMyTableView.LastL(); return EFalse; } iMyTableView.GetL(); NewItem.iPrimeId = iMyTableView.ColInt(1); NewItem.iName.Copy(iMyTableView.ColDes8(2)); NewItem.iPhone.Copy(iMyTableView.ColDes8(3)); NewItem.iEMail.Copy(iMyTableView.ColDes8(4)); iReturnFlag = ETrue; } return iReturnFlag; } //Следующая функция обеспечивает переход //к первой записи отображения таблицы TBool CMyDatabase::GetMyTableFirstRecord(TMyTableItem& NewItem) { iAtBeginningFlag = EFalse; BookmarkFlag=EFalse; iReturnFlag = EFalse; if(iMyTableView.AtRow()) { iMyTableView.FirstL(); if(iMyTableView.AtEnd()) return EFalse; iMyTableView.GetL(); NewItem.iPrimeId = iMyTableView.ColInt(1); NewItem.iName.Copy(iMyTableView.ColDes8(2)); NewItem.iPhone.Copy(iMyTableView.ColDes8(3)); NewItem.iEMail.Copy(iMyTableView.ColDes8(4)); iReturnFlag = ETrue; iAtBeginningFlag = ETrue; } return iReturnFlag; } //Следующая функция обеспечивает навигацию //в обратном направлении по отображению таблицы TBool CMyDatabase::GetMyTablePreviousRecord(TMyTableItem& NewItem) { iAtBeginningFlag = EFalse; iReturnFlag = EFalse; if(iMyTableView.AtRow()) { iMyTableView.PreviousL(); if(iMyTableView.AtBeginning()) { iMyTableView.FirstL(); BookmarkFlag=EFalse; iAtBeginningFlag = ETrue; return EFalse; } iMyTableView.GetL(); NewItem.iPrimeId = iMyTableView.ColInt(1); NewItem.iName.Copy(iMyTableView.ColDes8(2)); NewItem.iPhone.Copy(iMyTableView.ColDes8(3)); NewItem.iEMail.Copy(iMyTableView.ColDes8(4)); iBookmark = iMyTableView.Bookmark(); iReturnFlag = ETrue; BookmarkFlag = ETrue; } return iReturnFlag; } //Следующая функция обеспечивает переход //к последней записи отображения таблицы TBool CMyDatabase::GetMyTableLastRecord(TMyTableItem& NewItem) { iAtBeginningFlag = EFalse; BookmarkFlag = EFalse; iReturnFlag = EFalse; if(iMyTableView.AtRow()) { iMyTableView.LastL(); if(iMyTableView.AtEnd()) return EFalse; iMyTableView.GetL(); NewItem.iPrimeId = iMyTableView.ColInt(1); NewItem.iName.Copy(iMyTableView.ColDes8(2)); NewItem.iPhone.Copy(iMyTableView.ColDes8(3)); NewItem.iEMail.Copy(iMyTableView.ColDes8(4)); iReturnFlag = ETrue; } return iReturnFlag; } /*************************Конец функций навигации****************************/
Следующая функция возвращает количество записей в таблице базы данных.
TInt CMyDatabase::GetMyTableCount() { TQueryBuffer QueryBuffer; //SELECT * FROM MyTable QueryBuffer.Copy(_L("SELECT * FROM ")); QueryBuffer.Append(KMyTable); RDbView Myview; Myview.Prepare(iMyDatabase,TDbQuery(QueryBuffer)); CleanupClosePushL(Myview); Myview.EvaluateAll(); TInt RecordCount=Myview.CountL(); CleanupStack::PopAndDestroy(1); // Myview return RecordCount; } //Конец кода таблицы MyTable
Ссылки
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| CAknView | b_monkey | Russian Developer Forum - Форум Российских разработчиков | 7 | 2007-12-04 12:12 |
| Присоединение MBM файлов | LuckyBeaver | Russian Developer Forum - Форум Российских разработчиков | 7 | 2008-01-20 11:17 |
| Делаем основной цикл игры | Ecconaut | Russian Developer Forum - Форум Российских разработчиков | 17 | 2007-12-12 04:32 |
| NokiaCLFileTransfer | soumi | Russian Developer Forum - Форум Российских разработчиков | 3 | 2008-07-02 09:50 |
| samsung & symbian sdk | spirt | Russian Developer Forum - Форум Российских разработчиков | 16 | 2008-08-05 14:45 |
