Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Разработка баз данных _ Qt + SQLite

Автор: Dimix 24.11.2010, 14:44

Я новичек в программировании средствами Qt да еще и с использованием SQLite. Прошу сильно не критиковать.

Проблема такова.
Существует главная БД, и N - количество дополнительных БД. В главной БД содержатся имена дополнительных БД. Делаю запрос по выбраному имени из главной БД и присваиваю имя переменной. Закрываю свою главную БД. И осуществляю соединение с БД имя которой содержится в переменной. Получаю.

QSqlQuery::exec: database not open

Я напливал на это оповещение и решил продолжить. Пытаюсь добавить в нее запись (ничего не происходит). Начинаю добавлять запись в Главную БД (соединение с которой разрывал) оно добавляет без проблем. (имена баз все разные) ОБЪЯСНИТЕ НОВИЧКУ. Спасибо!

Автор: panter_dsd 24.11.2010, 15:30

Код приведи закрытия подключения и открытия нового.

Автор: Dimix 24.11.2010, 16:05

Цитата(panter_dsd @ 24.11.2010, 15:30) *
Код приведи закрытия подключения и открытия нового.


private:
class QListWidget* list;
class QString namelist;
class QString namedb;
class QSqlDatabase db;
private slots:
       void listClicked();
/***************************/
//Добавляю имена из главной БД
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("masterdb");
    db.setHostName();
    db.setUserName("1");
    db.setPassword("1");
    if (!db.open()){
    db.lastError().text();
            }
    QSqlQueryModel model;
    model.setQuery("SELECT name FROM table");
    for (int i = 0; i < model.rowCount(); ++i) {
    namelist = model.record(i).value("name").toString();    
    list->addItem(namelist);
    }
/******************************/
void Action::listClicked()
{
    namedb=list->currentItem()->text();
    db.close();
    db.removeDatabase("QSQLITE");

    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(namedb.toUtf8());
    db.setHostName();
    db.setUserName("1");
    db.setPassword("1");
    if (!db.open()){
    db.lastError().text();
            }


Вроде все. Просто я там говнокода напечатал. ОЧЕНЬ МНОГО.

Автор: panter_dsd 24.11.2010, 16:50

Не храни db, ты всегда можешь его получить. Вот так примерно должно быть:

void Action::listClicked()
{
    const QString& namedb = list->currentItem()->text();
    QSqlDatabase db = QSqlDatabase::database ();
    db.close();
    db.setDatabaseName(namedb);
    db.setHostName();
    db.setUserName("1");
    db.setPassword("1");
    if (!db.open()){
    db.lastError().text();
            }

Автор: Dimix 24.11.2010, 17:12

В этой строке же нужно указать какой тип БД я хочу использовать?

QSqlDatabase db = QSqlDatabase::database ();

А в чем разница хранения?
Еще заметил такую проблему вроде создаю запароленные БД, а могу открыть их без пароля. Как правильно?
при создании
db.setUserName("1");
db.setPassword("1");

а при открытии так
db.open("1", "1");



Автор: panter_dsd 24.11.2010, 17:15

SQLite не поддерживает пароли.

QSqlDatabase::database () - указатель на дефолтное подключение. Т.е. когда ты делаешь addDatabase создается соединение, к которому ты из любого участка программы сможешь получить доступ через QSqlDatabase::database (). Так же можешь задать имя соединению:

...................
QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE", "YOUR_CONNECTION);
.............................................
QSqlDatabase db = QSqlDatabase::database ("YOUR_CONNECTION);

Автор: Dimix 24.11.2010, 17:49

Цитата(panter_dsd @ 24.11.2010, 17:15) *
...................
QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE", "YOUR_CONNECTION);
.............................................
QSqlDatabase db = QSqlDatabase::database ("YOUR_CONNECTION);

Помоему я чет не правильно делаю у меня с дефолтным подключением пишет что БД не открыта. Но суть не в этом.
Другими словами почему я подключаюсь к готовой БД SQLite и могу получить из нее данные, а дисконектнутся с ней и подключится к другой для просмотра данных у меня не получается (остается активна первая подключенная БД).

Автор: panter_dsd 24.11.2010, 17:51

Значит что-то ее держит. Модель какая-нибудь.

Автор: Dimix 24.11.2010, 18:09

Цитата(panter_dsd @ 24.11.2010, 18:51) *
Значит что-то ее держит. Модель какая-нибудь.

Это наверное самый правильный вариант. А как отрубить модель от базы?

Автор: panter_dsd 24.11.2010, 20:01

Попробуй метод clear ().

Автор: Dimix 25.11.2010, 13:50

Ничего не помогает. Может кто то знает еще какие либо варианты почему не получается?

Автор: BRE 25.11.2010, 14:10

Цитата(Dimix @ 25.11.2010, 13:50) *
Ничего не помогает. Может кто то знает еще какие либо варианты почему не получается?

Нужно почитать документацию по QSqlDatabase вообще и про:
void QSqlDatabase::removeDatabase ( const QString & connectionName ) [static]
в частности.
Обратить внимание какой параметр принимает этот метод и посмотреть пример в документации к этому методу, как правильно удалять соединение.

Автор: 512es 2.12.2010, 18:33

Привьём пожалуй любовь к QtSql =))
Сделай вот так:

void Action::listClicked()
{
    QString namedb = list->currentItem()->text();
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",namedb);
    db.setDatabaseName(namedb);
    if (!db.open()) {
        qDebug() << db.lastError().text();
        db.close();
        return 0;
    }
}

bool getDBlist()
{
    { // не спроста тут мы взяли всё это в скобки
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","masterdb");
        db.setDatabaseName("masterdb");
        if (!db.open()) {
            qDebug() << db.lastError().text();
            db.close();
            return 0;
        }
    }
    // сейчас база данных открыта, но переменная db удалена
    
    QSqlQuery q(QSqlDatabase::database("masterdb")); // вот так можно обратиться к открытому соединению
    if (!q.exec("SELECT name FROM table;")) return 0;
    while (q.next()) list->addItem(q.value(0).toString());
    
    // суть в том, чтобы сейчас не было НИ ОДНОЙ живой переменной указывающей на db
    if (QSqlDatabase::contains("masterdb")) { // masterdb - это имя подключения к бд. такое же как и то, которое мы указали при создании соединения
        if (QSqlDatabase::database("masterdb").isOpen()) QSqlDatabase::database("masterdb").close();
        QSqlDatabase::removeDatabase("masterdb");
    }
    return 1;
}


ещё кажись понадобится q.clear() перед закрытием бд..

Автор: Dimix 7.12.2010, 15:14

Проблема вот такого плана

существует виджет QLineEdit
создаю БД по обращению к функции

bool maindbCreate()
{
    QSqlDatabase maindbCreate = QSqlDatabase::addDatabase("QSQLITE");
    maindbCreate.setDatabaseName("base.db");
    maindbCreate.setHostName("localhost");
    maindbCreate.setUserName("user");
    maindbCreate.setPassword("password");
    if(!maindbCreate.open()){
        maindbCreate.lastError().text();
        QSqlDatabase::removeDatabase("QSQLITE");
    }else{
        maindbCreate.close();
        QSqlDatabase::removeDatabase("QSQLITE");
        return false;
    };
    return true;
}

создаю Таблицу по обращению к функции
bool maindbCreateTable()
{
    QSqlDatabase maindbCreateTable = QSqlDatabase::addDatabase("QSQLITE");
    maindbCreateTable.setHostName("localhost");
    maindbCreateTable.setDatabaseName("base.db");
    if(!maindbCreateTable.open("user", "password")){
        maindbCreateTable.lastError().text();
        QSqlDatabase::removeDatabase("QSQLITE");
    }else{
    QSqlQuery queryMaindbCreateTable;
    queryMaindbCreateTable.exec("CREATE TABLE user (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(20));");
    queryMaindbCreateTable.clear();
    maindbCreateTable.close();
    QSqlDatabase::removeDatabase("QSQLITE");
    return false;
    };
return true;
}

пытаюсь заполнить таблицу по обращению к функции
bool maindbInsert()
{
    QSqlDatabase maindbInsert = QSqlDatabase::addDatabase("QSQLITE");
    maindbInsert.setHostName("localhost");
    maindbInsert.setDatabaseName("base.db");
    if(!maindbInsert.open("user", "password")){
        maindbInsert.lastError().text();
        QSqlDatabase::removeDatabase("QSQLITE");
    }else{
    QSqlQuery queryMaindbInsert;
    queryMaindbInsert.exec("INSERT INTO (name) VALUES ('"+editCreateName->text()+"');");
    queryMaindbInsert.clear();
    maindbInsert.close();
    QSqlDatabase::removeDatabase("QSQLITE");
    return false;
    };
return true;
}

Она ругается на editCreateName->text() вот что пишет : error: ‘editCreateName’ was not declared in this scope
Как надо правильно ПОМОГИТЕ!

Автор: Алексей1153 7.12.2010, 22:09

наверное, не зря ругается, и так оно и есть :) Попробуй

ui->editCreateName->text()

Автор: Dimix 8.12.2010, 15:56

Цитата(Алексей1153 @ 7.12.2010, 22:09) *
наверное, не зря ругается, и так оно и есть :) Попробуй

ui->editCreateName->text()


Я эту проблему решил вот так
void maindbCreate();
void maindbCreateTable();

и т.п.

Вопрос возник такого плана. Как получить выделенную строку в QTableView?

Автор: Dimix 8.12.2010, 16:57

Цитата(Dimix @ 8.12.2010, 15:56) *
Вопрос возник такого плана. Как получить выделенную строку в QTableView?

Разобрался
QSqlTableModel model;
model.setTable("coming");
model.select();
model.removeRow(view->currentIndex().row());

Автор: Litkevich Yuriy 8.12.2010, 20:30

Цитата(Dimix @ 8.12.2010, 18:57) *
Разобрался
QSqlTableModel model;
model.setTable("coming");
model.select();
model.removeRow(view->currentIndex().row());
это не соответствует вопросу. так ты удалишь выделенную строку.


Автор: 512es 8.12.2010, 20:40

Dimix, если честно вообще ничего в твоём примере не понял.. советую перечитать его (код) ещё раз самому и попытаться представить логику. что и как делается. очень много противоречий и ненужных действий..

Автор: Dimix 8.12.2010, 20:55

Почему не соотвецтвует вопросу :mellow: . Я же не говорил для чего мне нужно узнать выделенную строку. А по коду вроде ясно что view это аргумент QTableView.

view->currentIndex().row()

Незнаю я не вижу в коде ненужных действий.
P. S. Все время програмировал на Delphi поэтому я новичек в Qt да и впринципе в С++.
Может логика и неправильная но во всяком случае я другого решения не нашел.
А текущий пример работает (ну пока проблем небыло :) ).

Автор: 512es 8.12.2010, 21:05

1) склайту не нужно указывать HostName, UserName и Password

2) в чём суть функции maindbCreate()? по сути она вообще ничего не делает

3) maindbCreate.lastError().text() в maindbCreate() это вообщем то возвращаемая переменная. в твоём примере не используется.

4) не правильно:

queryMaindbInsert.exec("INSERT INTO (name) VALUES ('"+editCreateName->text()+"');");

Для подстановки значений в запрос есть специальная функция prepare():
queryMaindbInsert.prepare("INSERT INTO (name) VALUES (?);");
queryMaindbInsert.addBindValue(ui->editCreateName->text());
if (!queryMaindbInsert.exec()) {qDebug() << queryMaindbInsert.lastError().text(); return;}


5)
CREATE TABLE user (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(20));

инсертить так как ты делаешь в эту таблицу не получится. id при вставке не задаёшь. возможно ты хотел сделать так:
id INTEGER PRIMARY KEY AUTOINCREMENT


6) создаёшь базу QSqlDatabase::addDatabase("QSQLITE"); а удаляешь QSqlDatabase::removeDatabase("QSQLITE"); -- так нельзя. при создании не указываешь имя соединения, только драйвер. а удаляешь по неизвестному имени соединения "QSQLITE". по имени драйвера то нельзя удалять. должно ругаться на ошибки.

7) мне показалось или ты и правда пытаешься создавать и удалять соединения с бд каждый раз? почитай мой пример ещё раз внимательнее

Автор: Dimix 10.12.2010, 13:17

Цитата
Мне показалось или ты и правда пытаешься создавать и удалять соединения с бд каждый раз? почитай мой пример ещё раз внимательнее

Я и вправде создаю и удаляю каждый раз драйвер БД. Почему я так решил! У меня работа с данными пользователь может заполнять и удалять их (я сделал как 100% вариант сохранения данных так как соединение и драйвер БД являются отруюленными ошибки при аварийном завершении не будет) Я новичек и еще несильно понимаю как правильно...
У меня срочный вопрос.
В БД существует поле Дата. Как сделать ильтр по заданному пользователем диапазону.
Пример:
___Дата____|К-во|_Чего_
01, 01, 2010 | 100 | литров
06, 02, 2010 | 200 | литров
01, 01, 2011 | 300 | литров

Вывести с 01, 02, 2010 по 01, 06, 2010 года

Автор: Dimix 10.12.2010, 17:55

Цитата
В БД существует поле Дата. Как сделать фильтр по заданному пользователем диапазону.
Пример:
___Дата____|К-во|_Чего_
01, 01, 2010 | 100 | литров
06, 02, 2010 | 200 | литров
01, 01, 2011 | 300 | литров

Вывести с 01, 02, 2010 по 01, 06, 2010 года

Тип данных у поля date DATA.

QString ddBegin, mmBegin, yyBegin, ddEnd, mmEnd, yyEnd;
ddBegin="01";mmBegin="02";yyBegin="2010";
ddEnd="01";mmEnd="06";yyEnd="2010";
QSqlQueryModel* model = new QSqlQueryModel;
model->setQuery("SELECT * FROM coming WHERE date >='"+ddBegin+", "+mmBegin+", "+yyBegin+"'and date <='"+ddEnd+", "+mmEnd+", "+yyEnd+"';");


Автор: 512es 10.12.2010, 22:14

Dimix, почитай доки про склайт. совершенно безопасно сохранять постоянное подключение к бд. мало того, база данных умеет работать и с несколькими пользователями одновременно.
это тебе не xml-ки.
кроме того, что то мне подсказывает что создание множества баз данных в твоём случае тоже не обосновано.

вот напимер. в моём проекте всего одна база склайта, причём, подключаюсь я к одному и тому же файлу двумя коннектами в разных потоках. тоесть, можно сказать, два пользователя, которые постоянно пишут и читают. размер базы планируется сотни м.б. более десяти таблиц. и всё отлично работает!

советую пересмотреть концепцию)

Автор: Dimix 13.12.2010, 2:07

Возникла проблема такого характера. Нужно изменить запись в базе данных. Пример.
ID | NAME | LOOK
1 | TOM | 1
2 | JON | 0
Поле LOOK это типо просматривался пользователь или нет
Мне нужно чтоб когда я посмотрю пользователя JON его LOOK стал 1
Я думал просто забирать все данные и записывать их по новому а удалять типо по ID но если я удалю TOM то ID JON останется всеравно 2.
Помогите!

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)