Russian Qt Forum
Сентябрь 30, 2024, 22:35 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Запись производного класса в БД  (Прочитано 10223 раз)
DS_tm
Гость
« : Март 21, 2010, 12:51 »

Есть класс:

Код
C++ (Qt)
SomeClass {
 SomeClass(int p1, const QString &p2) : _param1(p1), _param2(p2) {}
 inline int param1() const { return _param1; }
 inline QString param2() const { return _param2; }
private:
 int _param1;
 QString _param2;
};
Q_DECLARE_METATYPE(SomeClass)
 

Хотелось бы обеспечить корректную работу следующего кода:
Код
C++ (Qt)
 QSqlQuery query;
 query.prepare("INSERT INTO table VALUES(?)");
 query.addBindValue(QVariant::fromValue(SomeClass(1, "2"));
 query.exec();
 

В таком виде, без добавлений, понятное дело ничего не работает (как я понимаю из-за отсутсвия авто конвертации в QVariant::String)

Какие есть решения данной проблемы?
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #1 : Март 21, 2010, 14:04 »

Ты хочешь сделать т.н. "сериализацию"?
Запрос по идее должен выглядеть так:
"INSERT INTO table (field_name) VALUES (value)"
Т.е. имя поля ты пропустил. И какой тип данных у этого поля?

Записан

Юра.
DS_tm
Гость
« Ответ #2 : Март 21, 2010, 14:13 »

Тип поля либо String, либо BLOB (для тестов использую sqlite, а там типизация не строгая).
В примере название поля не пропущено, просто таблица с одним полем. Да и даже если таблица с несколькими полями, суть дела это не меняет. Посмотрел как Qt генерит строку на запрос с помощью биндов. Все это упираеться в функцию QString QSqlDriver::formatValue(const QVariant &value). Для значений типа QDate и QTime данная функция формирует строку, для всех остальных вызывает банальный toString(). Но для пользовательского класса toString() вернет QString(), вот в чем проблема.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #3 : Март 21, 2010, 14:55 »

QVariant не имеет метода toColor, однако это не означает, что преобразование невозможно. Посмотри внимательно документацию по QVariant.
И в том числе:
T QVariant::value () const
И ещё QMetaType
« Последнее редактирование: Март 21, 2010, 14:57 от lit-uriy » Записан

Юра.
DS_tm
Гость
« Ответ #4 : Март 21, 2010, 15:11 »

Проблема не в том, что я не могу превести переменную QVariant к своему собственному типу, а в том, что нет способа привести переменную QVariant моего типа к строке! То есть, вызов функции canConvert<QVariant::String>() для переменной созданой с помощью
QVariant::fromValue(SomeClass(...)) будет всегда возвращать false. Просмотрев пару раз всю документацию по QVariant и реализацию функции QVariant::toString() я пришел к выводу, что без правки QVariant это конвертация невозможна. Может кто-нибудь меня поправит? Мне искренне непонятно, почему нельзя было добавить возможность создания функций конвертации пользовательских типов в\из стандартных типов.

Что косаеться метатайп, то это фундамент для QVariant, он ничего не знает о возможности конвертации одного типа в другой.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #5 : Март 21, 2010, 15:42 »

мысль в слух:
А если для твоего класса реализовать функцию toString() и её использовать в твоём коде, т.е. сразу передавать в bind строку?
« Последнее редактирование: Март 21, 2010, 15:45 от lit-uriy » Записан

Юра.
DS_tm
Гость
« Ответ #6 : Март 21, 2010, 15:59 »

Вы имеете ввиду operator QString() const?
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #7 : Март 21, 2010, 16:07 »

Да зачем - просто QString toString() - и вызвать его при бинде строкового поля, а QVariant сам преобразует QString в QVariant

query.addBindValue( SomeClass(1, "2").toString() );
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #8 : Март 21, 2010, 16:10 »

нет, можно просто в твоём классе сделать функцию-член toString(), которая вернёт QString. Ну и fromString(), для обратного действия. При этом интерфейс класса выглядеть будет не красиво, но всё же выход.
Записан

Юра.
DS_tm
Гость
« Ответ #9 : Март 21, 2010, 16:45 »

Да в данном классе можно написать функции fromString и toString, и бинд нормально будет работать с ними, но мне необходима однообразная работа с данными. К примеру:

Код
C++ (Qt)
SomeDbManager::addRecord(QVariantList list) {
 QSqlQuery query;
 query.prepare(QString("INSERT INTO table VALUES(%1)").arg(prepareValues(lilst.size());
 foreach (QVariant value, list) query.addBindValue(value);
 return query.exec();
}
 

Допустим можно проверять перед addBindValue тип:
Код
C++ (Qt)
 if (value.type() == someClassType) addBindValue(value.value<SomeClass>().toString());
 else addBindValue(value);
 

Но при чтении получиться:
Код
C++ (Qt)
SomeDbManager::record(int recId) {
 QSqlQuery query;
 QVariantList list;
 ...
 for (int i = 0; i < rowSize; ++i) {
   list << query.value(i);
 }
 return list;
}
 

И в итоге получаеться, записываемый QVariantList имеет некоторые поля типа SomeClass, а прочитаный только QString
И даже это бы меня устроило, но вот при проверке i-ого элемента (который содержал раньше SomeClass) получившившегося списка получиться:

Код
C++ (Qt)
list.at(i).canConvert<SomeClass>(); // false;
 
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #10 : Март 22, 2010, 00:32 »

Раз хочется такой автоматизации - используйте QDataStream - дщелаете для своего класса соответствующий не член метод для

QDataStream &   operator>> ( QDataStream & stream, CMyClass & class )
QDataStream &   operator<< ( QDataStream & stream, const CMyClass & class )

и для всех других классов которые будут писаться в БД должны они быть переопределены. Для большинства Qt классов это сделано.

Далее используете QBuffer для получения QByteArray ( метод QBuffer::QByteArray &   buffer () ) и уже это пишете в BLOB БД.

Но возможно не очень верно создавать QBuffer и QDataStream для каждого класса... По идее должно работать.
Записан
DS_tm
Гость
« Ответ #11 : Март 22, 2010, 22:00 »

Да, этот вариант будет работать на запись, а вот при чтении необходимо будет точно знать последовательность типов, чтобы вызвать оператор чтения из потока для соответсвующего объекта, и только потом переводить его в QVariant и помещать в список.
Вообщем я пока знаю одно решение, которое изначально использовал, хранить типы колонок таких таблиц в самой бд, и при чтении записи делать обработку для каждого значения, в зависимости от типа. Но оно мне не нравиться лишним запросом к бд, на каждое чтение записи (альтернативно стуктуру можно кешировать програмно, но тогда небольшие расходы памяти появлаються)
В итоге видно с Qt4 вариантов все равно нет. Будем надеяться, что в пятерке расширят возможности QVariant.
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #12 : Март 23, 2010, 17:03 »

Цитировать
В итоге видно с Qt4 вариантов все равно нет. Будем надеяться, что в пятерке расширят возможности QVariant.
варианты есть - надо копать если они не лежат на поверхности

я честно говоря не полностью понял задачу...

есть таблица - в ней поле BLOB где должны лежать классы?
можно сделать отдельный столбец с типом этого класса - и уже спокойно вытаскивать через QDataStream или другим способом - никаких лишних запросов - только 1 доп столбец

если я правильно понял задачу
Записан
DS_tm
Гость
« Ответ #13 : Март 24, 2010, 10:31 »

Ну со столбцом Вы конечно погорячились, наверно все таки имелась ввиду строка Улыбающийся. По сути получаеться обычная таблица, а эта страка есть заголовок. Спасибо, идея интересная, мне что-то в голову не приходило, хроню типы в отдельной таблице.

Вообще абстрактно задача была такой. Необходимо создать инструмент, который позволял бы пользователю (не программисту, а обычному юзеру) создавать наборы данных любых доступных типов. То есть пользователь сначала создает набор параметров, выбирает им тип (из доступных типов а-ля "целове чилос", "список", "бит" и т.д.). Потом, имея этот список, он создает некую сущность (в бд как раз такую таблицу BLOB столбцов) и выбирает из списка, какие параметры у этой сущности будут. Ну а дальше он может создовать, редактировать и удалять записи для этой сущности. Сообственно данные для конечной записи хроняться в QVariantList, а для чтения и редактирования используеться QtPropertyBrowser. Вообщем, такой небольшой редактор БД, для обынчх пользователей, не владеющих Sql.

В итоге еще в том году сделал каркас, потом прикрутил QtPropertyBrowser, все работает и давольно славно, но вот решил произвести небольшой рефакторинг, плюс появилась необходимость хранить сложные классы, так что начал поиск идей по улучшению отдельных компонентов.
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #14 : Март 24, 2010, 18:17 »

Цитировать
Ну со столбцом Вы конечно погорячились, наверно все таки имелась ввиду строка . По сути получаеться обычная таблица, а эта страка есть заголовок.
ничего не понял

я имел ввиду

Table CLASS_STORAGE

ROW_ID | CLASS_TYPE | CLASS_DATA

Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.275 секунд. Запросов: 22.