Класс CODBCRecordset
В обычном 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:
Класс CDBField | |||||||||||||||||||||||||
Конструкторы | Здесь не присутствует конструкторов public. CDBField нельзя использовать без CODBCRecordset, так как внутренние структуры и объекты доступны через методы CODBCRecordset. | ||||||||||||||||||||||||
| Каждый из этих методов делает соответствующее преобразование, в зависимости от возвращаемых значений и типов данных. (См. таблицу методов AsXXX, для более детального ознакомления с правилами преобразования). Здесь нет типа данных Int , а AsInt() эквивалентен AsLong() | ||||||||||||||||||||||||
операторы аргументов | (См. таблицу операторов аргументов для ознакомления с правилами преобразования). | ||||||||||||||||||||||||
const CString& GetName() | Возвращает имя поля, которому соответствует данный объект. | ||||||||||||||||||||||||
| Каждый из них возвращает true если поле содержит значение соответствует типу данных. Здесь нет типа данных Number , а IsNumber() возвращает true если IsShort() || IsLong() || IsFloat() || IsDouble(). Здесь нет типа данных Int , а IsInt() возвращает true если IsLong() возвращает true. |
Значения в базе данных | ||||||||||
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 | * | ||||||||
Пустые ячейки, указывают на то, что данное преобразование невозможно. Ячейки, помеченные как * указывают на допустимость данной операции (См. таблицу алгоритмов преобразования). |
Тип поля базы данных | Аргумент оператора | ||||||||
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.
/////////////////////////////////////////////////////////////////////////////
CDatabase db;
// Соединение с ODBC с всплявающим диалогом ODBC
CString cConnect = "ODBC;";
db.Open( NULL, // DSN
FALSE, // Эксклюзивно
FALSE, // Только чтение (ReadOnly)
cConnect, // строка ODBC Connect
TRUE // используем курсор
);
COleDateTime dOrderDate;
CODBCRecordset rs( &db );
rs.Open( "SELECT * FROM Orders \
WHERE ORDER_DATE > 'jan 1 2000' \
ORDER BY ORDER_DATE" );
for( ; ! rs.IsEOF(); rs.MoveNext() )
{
// Далее на Ваш выбор. Вы можете выбрать способ,
// которым будете получать значения
//
// Здесь возвращается значение COleDateTime
dOrderDate = rs.GetDate( "ORDER_DATE" );
dOrderDate = rs.Field("ORDER_DATE").AsDate();
// Здесь делается неявный запрос в 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();
} // for(....
/////////////////////////////////////////////////////////////////////////////
Если 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