Пользователь
0,0
рейтинг
21 сентября 2011 в 15:49

Разработка → Qt и SQLite и вообще, программирование БД в Qt tutorial

SQLite*, Qt*
Добрый день.

Ниже пойдет речь о том, как использовать SQLite в Qt. Автор постарался как можно подробнее рассматривать программирование баз данных в Qt.

Об этих двух замечательных продуктах можно прочитать следуя приведенным выше ссылкам, а мы будем конкретно рассматривать программирование БД в Qt, в частности, на примере SQLite. Скажу только, что SQLite несколько отличается от «обычных» баз данных, таких как MySQL тем, что «не обладает» клиент-серверной архитектурой. То есть движок БД не является отдельно работающим процессом, с которым взаимодействует программа. SQLite представляет собой библиотеку, с которой компонуется ваша программа и, таким образом, движок становится составной частью программы. То есть представьте вы решили сохранять все данные, с которыми «сталкивается» ваша программа в обычный файл. В один прекрасный день вы решаете сохранять данные в файле, но организовав это с «реляционной» точки зрения. После этого вы поняли, что новая структура файла должна «распознаваться особым образом». С этого, как минимум, следует, что вам нужно предоставить некоторый API, обеспечивающий связь между этим файлом данных с приложением. В общем, следуя логической постановке приведенного сценария у вас рождается система БД, не требующая сервера БД и собственно, клиента. Получается достаточно быстрая по сравнению с «клиент-серверной» БД система, и сама программа упрощается.

Я состою в дружеских отношениях с Qt и недавно мне понадобилось ее БД функциональность. С MySQL я тоже в достаточно дружеских отношениях и попытался использовать Qt с MySQL в программе, в то время разрабатываемой мной. Имея нехватку времени и нервов, чтоб «связать» MySQL с Qt, решил воспользоваться SQLite, для чего в Qt есть, так сказать, встроенная поддержка, то есть ничего нового установить/конфигурировать не надо было (это не относиться к случаю, если ваш Qt собран с поддержкой «считанных» модулей, без подключения модуля QtSql). И еще, если мне придется установить программу в другой компьютер, я не буду «вынужден» установить сервер MySQL и т.д. (спорная тема — знаю).

FIY


На данный момент я использую программу SQLiteManager для создания БД, таблиц и т.д., использую недавно, но программа сразу понравилась. В моей «рабочей лошадке» установлен(a?) Qt Windows SDK и я использую QtCreator, сразу скажу — просто блеск (не ИМХО, и вправду отличная IDE).

И так, Qt и базы данных


Как уже неявно упомянулось выше, в Qt есть отдельный модуль, предоставляющий удобный «сервис» использования БД — QtSql. Если у вас есть опыт работы с Qt, то о файле .pro вам известно, если нет — познакомьтесь. Помните только, что нужно добавить следующую строку в .pro файл:
QT += sql

Это, чтоб использовать модуль QtSql, а для работы с ее классами, нужно включать одноименный заголовок.
#include <QtSql>

В книгах по Qt говорится о трех уровнях модуля QtSql:
  1. Уровень драйверов
  2. Программный уровень
  3. Уровень пользовательского интерфейса
Уровень драйверов

К уровню драйверов относятся классы для получения данных на физическом уровне, такие, как:
  • QSqlDriver
  • QSqlDriverCreator<T*>
  • QSqlDriverCreatorBase,
  • QSqlDriverPlugin
  • QSqlResult
QSqlDriver является абстрактным базовым классом, предназначенный для доступа к специфичным БД. Важно, что класс не должен быть использован «прямо», взамен нужно/можно воспользоваться QSqlDatabase. Хотя, если вы хотите создать свой собственный драйвер SQL, то можете наследовать от QSqlDriver и реализовать чисто виртуальные, и нужные вам виртуальные функции.
QSqlDriverCreator — шаблонный класс, предоставляющий фабрику SQL драйвера для специфичного типа драйвера. Шаблонный параметр должен быть подклассом QSqlDriver.
QSqlCreatorBase — базовый класс для фабрик SQL драйверов, чтобы возвращать экземпляр специфичного поскласса класса QSqlDriver, который вы хотите предоставить, нужно «перефразировать» метод createObject().
QSqlDatabase несет ответственность за загрузку и управление плагинов драйверов баз данных. Когда база данных добавлена (это делается функцией QSqlDatabase::addDatabase()), необходимый плагин драйвера загружается (используя QSqlDriverPlugin). QSqlDriverPlugin предоставляет собой абстрактный базовый класс для пользовательских QSqlDriver плагинов.
QSqlResult сам говорит о себе (как и все Qt-шные классы), этот класс предоставляет абстрактный интерфейс для доступа к данным специфичных БД. С практической точки зрения мы будем использовать QSqlQuery вместо QSqlResult, поскольку QSqlQuery предоставляет обертку («обобщенную») для БД-специфичных реализации QSqlResult.
Так, поскольку уровень драйверов, как оказалось, актуально использовать при создании собственного драйвера, то привожу пример кода (для наиболее заинтересованных), который может быть использован как каркасс для драйвера:

class XyzResult : public QSqlResult
 {
 public:
     XyzResult(const QSqlDriver *driver)
         : QSqlResult(driver) {}
     ~XyzResult() {}

 protected:
     QVariant data(int /* index */) { return QVariant(); }
     bool isNull(int /* index */) { return false; }
     bool reset(const QString & /* query */) { return false; }
     bool fetch(int /* index */) { return false; }
     bool fetchFirst() { return false; }
     bool fetchLast() { return false; }
     int size() { return 0; }
     int numRowsAffected() { return 0; }
     QSqlRecord record() const { return QSqlRecord(); }
 };

 class XyzDriver : public QSqlDriver
 {
 public:
     XyzDriver() {}
     ~XyzDriver() {}

     bool hasFeature(DriverFeature /* feature */) const { return false; }
     bool open(const QString & /* db */, const QString & /* user */,
               const QString & /* password */, const QString & /* host */,
               int /* port */, const QString & /* options */)
         { return false; }
     void close() {}
     QSqlResult *createResult() const { return new XyzResult(this); }
 };


Программный уровень

Для соединения с базой данных прежде всего нужно активизировать драйвер используя статический метод QSqlDatabase::addDatabase(). Метод получает строку как аргумент, обозначающий идентификатор драйвер СУБД. Нам понадобится «QSQLITE».

QSqlDatabase sdb = QSqlDatabase::addDatabase("QSQLITE");
sdb.setDatabaseName("db_name.sqlite");

if (!sdb.open()) {
       //....
}

У статической функции addDatabase есть перегруженный «брат», получающий не имя драйвера, а сам драйвер(QSqlDriver*).
Соединение осуществляется методом open(). Класс QSqlDatabase представляет соединение с БД. Соединение предоставляет доступ к БД через поддерживаемый драйвер БД. Важно, что можно иметь несколько соединений к одной БД.
Если при соединении (метод open()) возникла ошибка, то получить информацию об ошибке можно через метод QSqlDatabase::lastError() (возвращает QSqlError).

if (!sdb.open()) {
      qDebug() << sdb.lastError().text();
}

Рассмотрим как Qt позволяет исполнять команды SQL. Для этого можно воспользоваться классом QSqlQuery. Класс может быть использована не только для исполнения DML (Data Manipulation Language) выражений, таких, как SELECT, INSERT, UPDATE и DELETE, но и DDL (Data Definition Language) выражений, таких, как CREATE TABLE. Обратите внимание, что может быть выполнена и БД-специфичная команда, не ялвяющийся стандартом SQL (например, для PSQL — «SET DATESTYLE=ISO»).
Удачно выполненные запросы устанавливают состояние запроса в «активный», так, isActive() возвратит true, в противоположном случае состояние устанавливается в неактивное. Запросы оформляются в виде обычной строки, которая передается в конструктор или в метод QSqlQuery::exec(). В первом случае, при передаче конструктору, запуск команды будет производиться автоматически (при конструировании объекта).
Что очень интересно, так это возможность навигации, предоставляемый QSqlQuery. Например, после запроса SELECT можно перемещаться по собранным данным при помощи методов next(), previous(), first(), last() и seek().

QSqlQuery query("SELECT country FROM artist");
while (query.next()) {
         QString country = query.value(0).toString();
         do_something(country);
}

Метод next() позволяет перемащатся на следующую строку данных, а вызов previous() на предыдущую строку, соответственно. first(), last() извлекают, соответственно, первую запись из результата. seek() получает целочисленный индекс, извлекая запись из результата по полученному индексу и «позиционирует запрос» на извлеченную запись. Проверить размер, вернее количество строк данных (результата) можно методом size(). Важно помнить, что первая запись находится в позиции 0, запрос должен быть в активном состоянии, а isSelect() возвращать true (это происходит, если последним запросом был SELECT) перед вызовом метода seek(). О методе seek() более подробно советую прочитать в официальной документации.
Выше упомянули, что если передавать строку запроса в конструктор класса QSqlQuery, то запрос выполнится при создании объекта — при конструировании. Используя метод exec() можно, так сказать, следить за временем выполнения запросов. Конструкция
QSqlQuery query("SELECT country FROM artist");
может быть представлена также так:
QSqlQuery query;
query.exec("SELECT country FROM artist");
Так, exec() получает запрос в виде QString. Выполняя запрос, в случае удачи этот метод возвращает true и устанавливает состояние в активное, в противоположном случае все «противоположное» указанным операциям. Конечно, следует еще и помнить, что строка запроса должна подчиняться синтаксическим правилам запрашиваемой БД (в частности, стандарту SQL).
Что интересно, так после исполнения, запрос позиционируется на инвалидный(ую?) запись, то есть для адекватного использования результатов, необходимо воспользоваться, скажем, методом next().
У метода exec() перегруженная альтернатива, не получающая никаких аргументов. Вызов этого варианта exec() исполняет до этого подготовленный запрос. Обратите внимание — «подготовленный». Для этого предназначен метод prepare(), который возвращает true в случае удачной подготовки запроса.
Важность или, можно сказать, уникальность метода в том, что запрос может содержать «заполнители» для связывания со значениями используая bindValue().
QSqlQuery my_query;
my_query.prepare("INSERT INTO my_table (number, address, age)"
                              "VALUES (:number, :address, :age);");
my_query.bindValue(":number", "14");
my_query.bindValue(":address", "hello world str.");
my_query.bindValue(":age", "37");

Еще можно использовать вариант безымянных параметров:

QSqlQuery my_query;
my_query.prepare("INSERT INTO my_table (number, address, age)"
                              "VALUES (?, ?, ?);");
my_query.bindValue("14");
my_query.bindValue("hello world str.");
my_query.bindValue("37");

И наконец, можно просто использовать подставляемые аргументы, которые предоставляет QString:

QSqlQuery my_query;
my_query.prepare(
          QString("INSERT INTO my_table (number, address, age) VALUES (%1, '%2', %3);")
                          .arg("14").arg("hello world str.").arg("37")
          );

Компилируемый (copy-paste-to-your-ide) пример:

#include <QtGui/QApplication>
#include <QtSql>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QSqlDatabase dbase = QSqlDatabase::addDatabase("QSQLITE");
    dbase.setDatabaseName("my_db.sqlite");
    if (!dbase.open()) {
        qDebug() << "Что-то пошло не так!";
        return -1;
    }

    QSqlQuery a_query;
    // DDL query
    QString str = "CREATE TABLE my_table ("
            "number integer PRIMARY KEY NOT NULL, "
            "address VARCHAR(255), "
            "age integer"
            ");";
    bool b = a_query.exec(str);
    if (!b) {
        qDebug() << "Вроде не удается создать таблицу, провертье карманы!";
    }

    // DML
    QString str_insert = "INSERT INTO my_table(number, address, age) "
            "VALUES (%1, '%2', %3);";
    str = str_insert.arg("14")
            .arg("hello world str.")
            .arg("37");
    b = a_query.exec(str);
    if (!b) {
        qDebug() << "Кажется данные не вставляются, проверьте дверь, может она закрыта?";
    }
    //.....
    if (!a_query.exec("SELECT * FROM my_table")) {
        qDebug() << "Даже селект не получается, я пас.";
        return -2;
    }
    QSqlRecord rec = a_query.record();
    int number = 0,
            age = 0;
    QString address = "";

    while (a_query.next()) {
        number = a_query.value(rec.indexOf("number")).toInt();
        age = a_query.value(rec.indexOf("age")).toInt();
        address = a_query.value(rec.indexOf("address")).toString();

        qDebug() << "number is " << number
                 << ". age is " << age
                 << ". address" << address;
    }

    return app.exec();
}

Для получения результата запроса следует вызвать метод QSqlQuery::value(), в котором необходимо передать номер столбца, для чего в примере воспользовались методом record(). Этот метод возвращает объект класса QSqlRecord, который содержит информацию, относящуюся к запросу SELECT. С помощью вызова QSqlRecord::indexOf() получаем индекс столбца.
Метод value() возвращает значения типа QVariant (класс, объекты которого могут содержать в себе значения разных типов), поэтому вы и преобразовали полученное значение, воспользовавшись методами QVariant::toInt() и QVariant::toString().

Уровень пользовательского интерфейса

Модуль QtSql поддерживает концепцию «Интервью», предоставляя ряд моделей для использования их в представлениях. Чтобы хорошенько познакомиться с этой концепцией — загляните сюда.
В качестве примера, класс QSqlTableModel позволяет отображать данные в табличной и иерархической форме. Как утверждается в литературе, интервью — самый простой способ отобразить данные таблицы, здесь не потребуется цикла для прохождения по строкам таблицы. Вот малюсенький пример:

#include <QtGui/QApplication>
#include <QtSql>
#include <QTableView>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QSqlDatabase dbase = QSqlDatabase::addDatabase("QSQLITE");
    dbase.setDatabaseName("my_db.sqlite");
    if (!dbase.open()) {
        qDebug() << "Что-то не так с соединением!";
        return -1;
    }

    QTableView view;
    QSqlTableModel model;

    model.setTable("my_table");
    model.select();
    model.setEditStrategy(QSqlTableModel::OnFieldChange);

    view.setModel(&model);
    view.show();

    return app.exec();
}

После соединения создается объект табличного представления QTableView и объект табличной модели QSqlTableModel. Методом setTable() устанавливается актуальная база в модели, а вызов select() производит заполнение данными.
Класс QSqlTableModel предоставляет следующие стратегии редактирования (устанавливаемые с помощью setEditStrategy()):
  • OnRowChange — производит запись данных, как только пользователь перейдет к другой строке таблицы.
  • OnFieldChange — производит запись после того, как пользователь перейдет к другой ячейке таблицы.
  • OnManualSubmit — записывает данные по вызову слота submitAll(). Если вызывается слот revertAll(), то данные возвращаются в исходное состояние.

Думаю, пост подошел к послесловию, и мне просто осталось надеется, что кто-то найдет здесь то, что искал, а кому-то информация понадобится «на потом».
@Dehumanizer
карма
66,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (56)

  • 0
    А полнотекстовый поиск они встроили или до сих пор отключают?
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Не нужен, потому что плох, или потому что ему там не место?
        • НЛО прилетело и опубликовало эту надпись здесь
          • +2
            Реальный пример:

            База > 40 000 записей.
            Средний объем записи — 2-3 Кб plain text.

            Поиск < 1c.
            Файл БД на диске.

            имхо, в Thunderbird «наведенные» проблемы от общей реализации.
            • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                FTS3 реально быстр. Он быстрее, чем аналогичные LIKE запросы (проверял лично).
                Однако, это накладывает ограничения на структуру таблицы. Подробнее можно ознакомиться по линку выше. Вообще, говорят, что SQLite надо уметь готовить.
                • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Использую FTS4. Он декларируется как еще более быстрый.
                  Может увеличить размер индекса на 1-2% (макс 10% если записи очень маленькие).
                  Плюс в нем появилась возможность полноценно считать релевантность, за счет доп. информации в индексе.
              • 0
                Но как только начал писать и читать одновременно, всё тут же стало очень грустно, база просто залочилась. А жаль.

                Да, в плане многопользовательской(многопоточной) работы на запись sqlite не подходит. Но если надо один раз много записать, а потом быстро читать — вполне.

                К слову, из бесплатных альтернатив встраиваемого fts-поиска знаю только Apache CLucene. Его кстати Qt использует в Assistant.
    • 0
      По умолчанию отключен. Как и раньше, надо пересобирать с парой дефайнов, чтобы включить.
  • 0
    А что там у QtSql с асинхронностью?
    • 0
      Доступ к БД является синхронным по умолчанию, остается воспользоваться потоками, запихивая запросы в них.
      • 0
        Это печально… Может все-же есть нормальный неблокирующий путь с сигнлами-слотами?
        • 0
          По правде еще не пробовал такой сценарий, думаю хорошая «идея», начну прямо сейчас.
  • 0
    А вы не разбирались с возможностью скажем так «репликации» sqlite базы :memory: в файловый аналог? Есть такая фича или надо самому писать?
    • НЛО прилетело и опубликовало эту надпись здесь
    • +1
      Думаю вы об этом:
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection1");
      db.setDatabaseName(":memory:");
      if (!db.open()) {          
          return false;
      }
      

      • +1
        :), видимо не успел)))
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Paging он сам делает внутри, на сколько я знаю.
    • 0
      Я не нашел такой возможности из коробки и посему писал сам.
    • 0
      Эта возможность реализуется через SQLite Online Backup API. Там и пример есть, как раз того, что Вам нужно.
  • 0
    Как параметру присвоить NULL-значение? (У меня на PyQt не получилось; так и не понял, почему)
    • +1
      Может QVariant() попробовать?
    • 0
      QVariant(QVariant::Int)
  • +3
    Какие люди падкие на халяву. Описали какие-то простейшие вещи которые есть в офф референсе, и сделали пару простейших примеров. Абсолютно не затронута работа в connections, транзакции, про использование varchar в sqlite это бред(вы даже не удосужились прочесть референс внимательно). И интересно что вас не срослось MySQL сервером? Если чесно вот такие профанские статьи очень удручают хабр стал совсем не торт…
    • +6
      Увидев посты, написанные вами, тут же осознал, что я написал «никчемный» пост, простите пожалуйста, больше не буду. А вы продолжайте писать ваши великолепные посты.
      • +3
        Достойный ответ. Уж извините, что мне испаганили карму(за комментарии с орфографическими и синтаксическими ошибками) настолько, что написать хоть что-то не представляется возможным. Не на этом ресурсе по крайней мере. По существу что-нибудь можете сказать? А именно, что в вашей статье такого что нельзя почерпнуть просто пробежавшись глазами по референсу? предисловие, в котором написано «Автор постарался как можно подробнее рассматривать программирование баз данных в Qt.»? Уберите это и не позорьтесь. За ссылки на вики тоже отдельное спасибо, очень позновательно… Честно, если нокия отдаст вам и вам подобным халявщикам n950 мне будет очень обидно… К слову чтобы дать понять, что я не просто так бодаюсь, я работаю на нокию(именно «на», а не «в»). Подключить только используемые классы, кстати, вы не пробовали кстати? По скольку ограничен в возможностях ответ товарищу на комментарий habrahabr.ru/blogs/qt_software/128836/#comment_4264513: Если поле поддерживает NULL в базе данных(при создании таблицы задается), то в C++ Qt при записи значения надо указать QVariant() — в референсе опятьже написано об этом. Референс Qt, если его прочитать, а не просто «потыкаться», вообще много о чем раскажет, и такие вот и подобные статьи не нужны будут.
        • +3
          1. Есть люди плохо знающие английский! Ваш английской референс им не так поможет.
          2. Я и не обещал рассказать что-то новое.
          3. Я рассказал то, что «узнал» во время опытов с моим приложением, а это достойно, как минимум, внимания.
          4. Не думаю, что я позорюсь из-за поста, если вам не помог, может даже вызвал отвращение, другим может пригодится.
          5. Мне пофигу высказывания вроде «тупой пост!!!», «а че книги не читаете!!!»(ведь там все написано), «ты знаком с технологией Х пару часов! хаа-хаа!». Не нравится — напиши лучше, больше, красивее — не в Хабре, так в другом месте — укажи линк, буду рад.
          6. Получив линк от вас — не значит, что я был не прав, просто пункт 5-й дает вам шанс объяснится за ваши «никчемные» комментарии.
          7. Мое любимое. Сейчас все кому не лень могут работать в/на Нокию, одному мне известны более 10-и «очень обычных, средних» программистов, которые недавно попали в фирму Нокиа. Может им уже «хана», может я ошибаюсь, но «Нокиа» — это вам не «Гугл»!
          • 0
            > Сейчас все кому не лень могут работать в/на Нокию, одному мне известны более 10-и «очень обычных, средних» программистов, которые недавно попали в фирму Нокиа.
            Речь идет о людях, достаточно близко знакомых со мной.
        • +2
          Знаю, что у вас нет возможности быстро ответить из-за кармы, так что это не проблема, я ни куда не спешу. Это не сарказм, просто, чтоб другие не подумали, что вы «сдались», так, на всякий случай))
    • +2
      >Если чесно вот такие профанские статьи очень удручают хабр стал совсем не торт…

      А всё почему? А потому что максимум, чем утруждают себя «не-профаны», так это комментами про то, что хабр не торт, а не написанием «правильных» статей.
      • +1
        я тоже считаю эту статью «слишком поверхностной», что ли, и опять же не узнал из нее ничего нового. и самому писать такие статьи не хочется, т.к. опять же мало кому они принесут пользу :)
        сам я просто не знаю о чем писать, увы, мне кажется все в Qt очевидным уже, может подскажете какую-нибудь интересную для хабровчан тему по Qt? мог бы освятить
        • 0
          ну и очевидно, чтобы эта тема не вынуждала меня повторять то, что уже написано в официальной документации, ибо считаю это явной глупостью (:
          • 0
          • +1
            Документация — она большая. Думаю, мало кто из тех, кто сейчас активно программирует на Qt, изучил её всю. А значит о некоторых вещах может попросту не подозревать, причём даже не знать о самом их существовании.
            • +1
              А зачем изучать ее всю? Она для того и написана чтобы ей пользоваться по необходимости. Для этого же создан assistant с отличной навигацией, индекстом и поиском. Надо понимать основы, когда что-то не знешь можно спросить, лучшее место для этого Qt Developer Network, не говорящие по-ангkийски смогут найти там русскоговорящую группу и задавать свои вопросы там, огромное количество профессионалов (в том числе сертифицированных специалистов и самих разработчиков Qt) достаточно быстро подскажут вам направление в котором стоит начинать исследования или читать документацию, и помогут решить проблему. Присоединяйтесь. (Нет я не работаю в/на нокию и это не пиар)
              • 0
                Понятно, что когда нужно что-то конкретное, то идёшь и смотришь по мере необходимости, но разработчик, повторяю, "… о некоторых вещах может попросту не подозревать, причём даже не знать о самом их существовании".
        • +1
          Да мало ли тем, которые не были затронуты: мета-объекты, особенности механизма слотов-сигналов в многопоточных программах, трюки с .pro-файлами (платформо-специфичные блоки, переменные окружения, и т.д.), канвас (который ныне QGraphicsView) и разного рода манипуляции с его объектами…

          P.S.: и я вас умоляю: осветить (т.е. «пролить свет»)! Процесс «освящения» обычно включает в себя размахивание кадилом и брызги святой водой — я сомневаюсь, что вы собирались делать именно это %)
  • +2
    Встроенные средства в QT4 для работы с СУБД скорее демонстрация, а не решения которыми должен пользоваться разработчик. Обычно Model/View архитектура позволяет быстро и без особых затрат сделать все, что надо для интерфейса к СУБД если воспользоватся готовыми библиотеками на C/C++ из открытых источников.

    Я работаю на PyQT4. В Python отлично сделана работа с различными СУБД, а SQLite вообще встроен.
  • 0
    Да очень многие «удобные классы» в Qt ( например QSql(Relational)TableModel ) пригодятся вам, лишь в отдельных случаях когда их реализация четко подходит под вашу текущую задачу. Но за что мне нравиться кьют, стоит посмотреть на уровень ниже (опустившись до абстрактных предков) и можно реализовать почти любую архитектуру приложения, написав подходящие вам аналоги «удобных классов».
    Например реализовать работу одной модели с бд имеющей (1:M), (M-N) связи, стандартная QSql(Relational)TableModel такого к сожалениу не может.
  • +1
    И наконец, можно просто использовать подставляемые аргументы, которые предоставляет QString

    Но лучше всё-таки использовать bindValue.
    QString не знает о том, что иногда нужно экранировать параметры SQL запроса
  • +1
    SQLite конечно отличная штука, но вот использование регистронезависимого LIKE с UTFными строками требует страшных танцев с бубном и то не всегда приводит к требуемым результатам.
    • 0
      #define SQLITE_ENABLE_ICU
      не помог?
  • 0
    В догонку напишите пожалуйста актуальную инструкции по сборке драйвера SQLite с поддержкой ICU (aka регистронезависимого like/upper/lower) для windows и linux.
    • +2
      Хотел топиком, да кармы не хватило.

      Сборка в Windows Qt-плагина sqlite с поддержкой регистронезависимого LIKE дле UTF8-символов не из ASCII-таблицы.

      Скачиваем Qt 4.7.4.
      Устанавливаем в C:\Qt\4.7.4.
      Скачиваем исходники sqlite 3.7.8.
      Распаковываем в C:\soft\sqlite-src.
      Скачиваем бинарники icu 4.8.
      Распаковываем в C:\soft\icu-bin.

      Изменяем содержимое C:\Qt\4.7.4\src\3rdparty\sqlite.pri

      CONFIG(release, debug|release):DEFINES *= NDEBUG
      DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_ICU
      INCLUDEPATH += $$PWD/sqlite \
      $$SQLITE_DIR/src
      win32 {
      INCLUDEPATH += $$ICU_DIR/include
      }
      unix {
      INCLUDEPATH += $$ICU_DIR/common
      }
      SOURCES += $$PWD/sqlite/sqlite3.c \
      $$SQLITE_DIR/ext/icu/icu.c
      LIBS += -L$$ICU_DIR/lib

      win32 {
      LIBS += -licuuc \
      -licuin
      }

      unix {
      LIBS += -lcudata \
      -lcui18n \
      -lcuuc
      }

      Открываем Qt 4.7.4 Command Prompt
      C:\Qt\4.7.4>cd C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\
      C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite>qmake sqlite.pro ICU_DIR=«C:\soft\icu-bin» SQLITE_DIR=«C:/soft/sqlite-src»
      C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite>nmake all

      … компиляция…

      В подпапках debug и release получаем соответствующие бинарники.

      Помимо qsqlite4.dll с приложением надо будет поставлять файлы:
      icudt48.dll
      icuin48.dll
      icuuc48.dll
      из каталога C:\soft\icu-bin\bin\
      pastebin.com/raw.php?i=qtLTr7me
      • 0
        Если сейчас хватает, то просится топиком))
        • +2
          Не хватает :(.
          Дополнил инструкцией для Linux. Пока в черновиках лежит.
      • 0
        К сожалению не собирается при помощи стандартного входящего в поставку Qt Creator MinGW/GCC.
        Вываливает гору предпреждений и ошибок :(

        Может всё же есть способ? (читай как: а-а-а-а помогите!!!)
        • 0
          Для MinGW как минимум другие бинарники icu нужны. На сайте готовых нет — значит надо собирать самому. Попробую.
        • 0
          В общем со сборкой библиотеки ICU под Windows с помощью MinGW есть проблемы.

          Почему бы Вам не воспользоваться компилятором от Microsoft?
          Можно поставить бесплатную Express-версию Visual Studio.
          • 0
            Хех. В экспресс версии нет возможности подключить Qt add-in.
            Да и вообще, кошерно использовать то, что предоставляет Qt/Nokia и работает более-менее одинаково на всех платформах.
            Вобщем так и останется SQLite в Qt только малоприменимой игрушкой :(
            • 0
              Хех. В экспресс версии нет возможности подключить Qt add-in.

              И что? Вы же собирались роботать в QtCreator.
              Ставите MSVS Express. Запускаете QtCreator, настраиваете его на компилятор от MSVS.

              Да и вообще, кошерно использовать то, что предоставляет Qt/Nokia и
              работает более-менее одинаково на всех платформах.

              Nokia предоставляет библиотеку Qt. Это кроссплатформенный продукт. И работать с ним лучше теми средствами, которые наиболее естественны для конкретной платформы. В случае Windows это MSVS и ее компилятор.

              Вобщем так и останется SQLite в Qt только малоприменимой игрушкой :(

              Многие с Вами не согласятся.
  • 0
    М. Шлее читали?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.