Локальное хранение данных – SQL

Добавлено 14 мая 2022 в 23:45

Qt Quick поддерживает API локального хранилища, известное из веб-браузеров как «local storage API». Этот API доступен через import QtQuick.LocalStorage 2.0.

Как правило, он сохраняет содержимое в базе данных SQLite в месте, зависимом от системы, в файле с уникальным идентификатором на основе заданного имени и версии базы данных. Существующие базы данных невозможно перечислить или удалить. Вы можете найти место хранения из QQmlEngine::offlineStoragePath().

Вы используете API, сначала создавая объект базы данных, а затем создавая транзакции в базе данных. Каждая транзакция может содержать один или несколько запросов SQL. Транзакция будет откатываться, когда SQL-запрос не будет выполнен внутри транзакции.

Например, для чтения из простой таблицы заметок с текстовым столбцом вы можете использовать локальное хранилище следующим образом:

import QtQuick
import QtQuick.LocalStorage 2.0

Item {
    Component.onCompleted: {
        const db = LocalStorage.openDatabaseSync("MyExample", "1.0", "Example database", 10000)
        db.transaction( function(tx) {
            const result = tx.executeSql('select * from notes')
            for(let i = 0; i < result.rows.length; i++) {
                print(result.rows[i].text)
            }
        })
    }
}

Сумасшедший прямоугольник

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

скриншот приложения

Ниже показана основа примера. Он содержит прямоугольник с названием crazy, который можно перетаскивать и который показывает в виде текста свое текущее положение по осям x и y.

Item {
    width: 400
    height: 400

    Rectangle {
        id: crazy
        objectName: 'crazy'
        width: 100
        height: 100
        x: 50
        y: 50
        color: "#53d769"
        border.color: Qt.lighter(color, 1.1)
        Text {
            anchors.centerIn: parent
            text: Math.round(parent.x) + '/' + Math.round(parent.y)
        }
        MouseArea {
            anchors.fill: parent
            drag.target: parent
        }
    }
    // ...

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

Теперь мы хотели бы добавить, чтобы позиция x/y прямоугольника хранилась внутри базы данных SQL. Для этого нам нужно добавить функции для работы с базой данных: init, read и store. Эти функции вызываются при завершении создания компонента и при его уничтожении.

import QtQuick
import QtQuick.LocalStorage 2.0

Item {
    // ссылка на объект базы данных
    property var db

    function initDatabase() {
        // инициализируем объект базы данных
    }

    function storeData() {
        // сохраняем данные в БД
    }

    function readData() {
        // читаем и применяем данные из БД
    }

    Component.onCompleted: {
        initDatabase()
        readData()
    }

    Component.onDestruction: {
        storeData()
    }
}

Вы также можете извлечь код работы с БД в собственную JS-библиотеку, которая выполняет всю логику. Это было бы предпочтительным способом, если логика становится более сложной.

В функции инициализации базы данных мы создаем объект БД и обеспечиваем создание таблицы SQL. Обратите внимание, что функции базы данных довольно разговорчивы, так что вы можете следить за ними в консоли.

function initDatabase() {
    // инициализируем объект базы данных
    print('initDatabase()')
    db = LocalStorage.openDatabaseSync("CrazyBox", "1.0", "A box who remembers its position", 100000)
    db.transaction( function(tx) {
        print('... create table')
        tx.executeSql('CREATE TABLE IF NOT EXISTS data(name TEXT, value TEXT)')
    })
}

Затем приложение вызывает функцию чтения для чтения существующих данных из базы данных. Здесь нам нужно различать, есть ли уже данные в таблице. Чтобы проверить это, мы смотрим, сколько строк вернул запрос select.

function readData() {
    // читает и применяет данные из БД
    print('readData()')
    if(!db) { return }
    db.transaction(function(tx) {
        print('... read crazy object')
        const result = tx.executeSql('select * from data where name="crazy"')
        if(result.rows.length === 1) {
            print('... update crazy geometry')
            // получаем столбец значений
            const value = result.rows[0].value
            // преобразуем в JS-объект
            const obj = JSON.parse(value)
            // применяем к объекту
            crazy.x = obj.x
            crazy.y = obj.y
        }
    })
}

Мы ожидаем, что данные хранятся в строке JSON в столбце value. Это не типично для SQL, но прекрасно работает с кодом JS. Таким образом, вместо того, чтобы хранить x, y как свойства в таблице, мы сохраняем их как полный объект JS, используя методы JSON stringify/parse. В итоге мы получаем корректный JS-объект со свойствами x и y, которые мы можем применить к нашему сумасшедшему прямоугольнику.

Чтобы сохранить данные, нам нужно различать случаи обновления и вставки. Мы используем обновление, когда запись уже существует, и вставку, если записи с именем "crazy" не существует.

function storeData() {
    // сохраняет данные в БД
    print('storeData()')
    if(!db) { return }
    db.transaction(function(tx) {
        print('... check if a crazy object exists')
        var result = tx.executeSql('SELECT * from data where name = "crazy"')
        // подготавливаем объект для сохранения в формате JSON
        var obj = { x: crazy.x, y: crazy.y }
        if(result.rows.length === 1) { // используем обновление
            print('... crazy exists, update it')
            result = tx.executeSql('UPDATE data set value=? where name="crazy"', [JSON.stringify(obj)])
        } else { // используем вставку
            print('... crazy does not exists, create it')
            result = tx.executeSql('INSERT INTO data VALUES (?,?)', ['crazy', JSON.stringify(obj)])
        }
    })
}

Вместо того, чтобы выбирать весь набор записей, мы могли бы также использовать функцию подсчета SQLite, например, SELECT COUNT(*) from data where name = "crazy", которая возвращает одну строку с количеством строк, затронутых запросом select. В противном случае это обычный код SQL. В качестве дополнительной возможности мы используем привязку SQL значения в запросе с помощью ?.

Теперь вы можете перетаскивать прямоугольник, и когда вы выходите из приложения, база данных сохраняет положение x/y и применяет его при следующем запуске приложения.

Теги

GUI / Графический интерфейс пользователяJavaScriptQMLQtQtQuickSQLSQLiteБаза данныхПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.