В обычном MFC проекте, предназначенном для работы с базой данных, мы получаем множество классов, наследованных от CRecordset, которые генерирует для нас визард (ClassWizard). Представленный здесь класс CODBCRecordset легко может заменить все эти CRecordset классы. CODBCRecordset сам по себе наследуется от CRecordset , но не имеет жёско-заданных количества и типов полей базы данных. CODBCRecordset имеет как минимум два преимущества: - CODBCRecordset может использоваться не токо для получения значений из базы данных, но и для записи, используя MFC.
- Другие подобные примеры не могут одновременно открывать более одной записи через одно соединение с базой данных, в случае с базой данных MS SQL Server. В некоторых случаях это вызывает проблемы, так как открытие нового соединения довольно продолжительно по времени и требует значительных затрат ресурсов.
Так как CODBCRecordset наследуется от CRecordset и использует его механизм обмена данными, то он полностью совместим с MFC ODBC классом CDatabase . Каждое значение поля хранится в объекте CDBField. Класс CDBField унаследован от CDBVariant и имеет дополнительные функции, которые упрощают его использование. Классы CODBCRecordset и CDBField поддерживают все типы данных. CDBField делает неявное преобразование типов, в тех местах, где требуется представить данные в запрошенном формате. Ниже представлен список методов CODBCRecordset и CDBField: Класс CODBCRecordset | Конструктор | Тоже что и для CRecordset принимая CDatabase* | BOOL Open( LPCTSTR lpszSQL, UINT nOpenType, DWORD dwOptions ); | Открывает запись lpszSQL - это SQL выражение, которое возвращает запись т.е. SELECT * FROM tablename nOpenType тип открытия, см. CRecordset::Open() dwOptions опции для CRecordset, см. CRecordset::Open() Обратите внимание, что lpszSQL и nOpenType поменялись местами, если сравнивать с CRecordset::Open() | short GetODBCFieldCount() | Возвращает количество полей (колонок) в записи. Данный метод определён в CRecordset . | int GetFieldID( LPCTSTR ) | Возвращает индекс поля для данного имени поля. Не чувствителен к регистру. Напротив, CRecordset::GetFieldIndexByName() чувствителен к регистру. | CString GetFieldName( int ) | Возвращает имя поля для данного индекса поля | CDBField& Field( LPCTSTR ) CDBField& Field( int ) | По средствам этого метода можно получить ссылку на внутренний объект CDBField, отвечающий за определённую колонку (См. класс CDBField ). Данный метод может использоваться в двух вариациях - с аргументом типа LPCTSTR szName , указывающем имя колонки, и int nID , указывающем индекс колонки в записи. | CDBField& operator( LPCTSTR ) CDBField& operator( int ) | Оператор функции служит для облегчения использования класса и для вызова соответствующего метода Field() параметр типа LPCTSTR szName - указывает на имя колонки, а int nID - на индекс колонки. | bool | GetBool() | unsigned char | GetChar() | short | GetShort() | int | GetInt() | long | GetLong() | float | Getfloat() | double | GetDouble() | COleDateTime | GetDate() | CString | GetString() | CLongBinary* | GetBinary() | | Каждый из этих методов делает соответствующее преобразование, в зависимости от возвращаемых значений и типов данных. Эти методы вызывают Field().AsXXX() (См. класс CDBField).параметр типа LPCTSTR szName - указывает на имя колонки, а int nID - на индекс колонки. | Класс CDBField | Конструкторы | Здесь не присутствует конструкторов public. CDBField нельзя использовать без CODBCRecordset, так как внутренние структуры и объекты доступны через методы CODBCRecordset. | bool | AsBool() | unsigned char | AsChar() | short | AsShort() | int | AsInt() | long | AsLong() | float | AsFloat() | double | AsDoble() | COleDateTime | AsDate() | CString | AsString() | CLongBinary* | AsBinary() | | Каждый из этих методов делает соответствующее преобразование, в зависимости от возвращаемых значений и типов данных. (См. таблицу методов AsXXX, для более детального ознакомления с правилами преобразования). Здесь нет типа данных Int , а AsInt() эквивалентен AsLong() | операторы аргументов | (См. таблицу операторов аргументов для ознакомления с правилами преобразования). | const CString& GetName() | Возвращает имя поля, которому соответствует данный объект. | bool | IsNull() | bool | IsBool() | bool | IsChar() | bool | IsShort() | bool | IsInt() | bool | IsLong() | bool | IsFloat() | bool | IsDouble() | bool | IsNumber() | bool | IsDate() | bool | IsString() | bool | IsBinary() | | Каждый из них возвращает true если поле содержит значение соответствует типу данных. Здесь нет типа данных Number , а IsNumber() возвращает true если IsShort() || IsLong() || IsFloat() || IsDouble(). Здесь нет типа данных Int , а IsInt() возвращает true если IsLong() возвращает true. | Преобразования делаемые методами AsXXX | | Значения в базе данных | | NULL | BOOL | UCHAR | SHORT | LONG | SINGLE | DOUBLE | DATE | STRING | BINARY | AsBool | false | * | * | * | * | * | * | | * | | AsChar | 0x32 | * | * | * | * | * | * | | * | | AsShort | 0 | * | * | * | * | * | * | | * | | AsInt | 0 | * | * | * | * | * | * | | * | | AsLong | 0 | * | * | * | * | * | * | | * | | AsFloat | 0.0 | * | * | * | * | * | * | | * | | AsDouble | 0.0 | * | * | * | * | * | * | | * | | AsDate | null | invalid | invalid | * | * | * | * | * | * | | AsString | empty | * | * | * | * | * | * | * | * | * | AsLongBinary | NULL | | | | | | | | | * | Пустые ячейки, указывают на то, что данное преобразование невозможно. Ячейки, помеченные как * указывают на допустимость данной операции (См. таблицу алгоритмов преобразования). | Conversions made by assignment operators | Тип поля базы данных | Аргумент оператора | | bool | unsigned char | short | int | long | float | double | COleDateTime | String | NULL | | | | | | | | | | BOOL | * | * | * | * | * | * | * | | * | UCHAR | * | * | * | * | * | * | * | | * | SHORT | * | * | * | * | * | * | * | | * | LONG | * | * | * | * | * | * | * | | * | SINGLE | * | * | * | * | * | * | * | | * | DOUBLE | * | * | * | * | * | * | * | | * | DATE | | | | | | | | * | * | STRING | * | * | * | * | * | * | * | * | * | BINARY | | | | | | | | | | Пустые ячейки, указывают на то, что данное преобразование невозможно. Ячейки, помеченные как * указывают на допустимость данной операции (См. таблицу алгоритмов преобразования). | Алгоритмы преобразования | String в Bool | Сравнение первого символа строки с 'T' | Char в Bool | Сравнение символа с 'T' | Bool в String | String = (bVal) ? 'T' : 'F' | Bool в Char | Char = (bVal) ? 'T' : 'F' | String в Number | использование функции atoX() | Number в String | метод CString::Format(), используя соответствующий формат строки | String в Date | метод COleDateTime::ParseDateTime() | Date в String | метод COleDateTime::Format() | Пример использования CODBCRecordset Вам необходимо включить в Ваш проект файлы ODBCRecordset.h и ODBCRecordset.cpp. Обычно я добавляю следующую строчку в мой файл StdAfx.h. #include "ODBCRecordset.h" Далее следует простой код, показывающий как можно использовать CODBCRecordset. CDatabasedb;
CStringcConnect = "ODBC;"; db.Open( NULL, FALSE, FALSE, cConnect, TRUE );
COleDateTimedOrderDate;
CODBCRecordsetrs( &db ); rs.Open( "SELECT * FROM Orders \ WHERE ORDER_DATE > 'jan 1 2000' \ ORDER BY ORDER_DATE" ); for( ; ! rs.IsEOF(); rs.MoveNext() ) {
dOrderDate = rs.GetDate( "ORDER_DATE" ); dOrderDate = rs.Field("ORDER_DATE").AsDate();
dOrderDate = rs("ORDER_DATE"); dOrderDate = rs.Field("ORDER_DATE");
rs.Edit(); rs("ORDER_DATE") = "jan 1 1999"; rs.Field("ORDER_DATE") = "jan 1 1999"; rs.Update(); } Если ORDER_DATE хранится в базе данных как datetime либо совместимым типом данных, то значение будет браться напрямую. Если ORDER_DATE хранится в базе данных как string либо совместимым типом данных (char, varchar), то значение будет преобразовано через метод COleDateTime::ParseDateTime(). Если преобразование не удалось, то dOrderDate будет установлен в COleDatetime::invalid. При работе с базой данных, может возникнуть так, что 2 или более колонок могут иметь одинаковые имена. CODBCRecordset оставляет имя первого столбца нетронутым, но другие повторяющиеся колонки переименованы путём добавления номера этой колонки. Например: SELECT * FROM Orders, Customers WHERE Orders.CUST_ID = Customers.ID Если таблица Orders имеет колонку с именем ID , и Customers имеет колонку с именем ID , то CODBCRecordset переименует ID из Customers в ID2, а все остальные, неповторяющиеся столбцы останутся не тронутыми. Например: Переименуем колонки в ручную, чтобы быть уверенными в именах SELECT Orders.*, Customers.ID as CUSTOMERS_ID FROM Orders, Customers WHERE Orders.CUST_ID = Customers.ID |