Я использую SQLite в приложении для Android, в котором, помимо прочего, хранится таблица, в которой записывается настроение пользователя. Схема таблицы показана ниже.
CREATE TABLE moods
(
dow INTEGER,
tsn INTEGER,
lato INTEGER,
agitation TEXT DEFAULT '{}',
preoccupancy TEXT DEFAULT '{}',
tensity TEXT DEFAULT '{}',
taps TEXT DEFAULT '{}'
);
В отличие, скажем, от Postgres, SQLite не имеет выделенного типа хранилища jsonb. Цитировать
Backwards compatibility constraints mean that SQLite is only able to store values that are NULL, integers, floating-point numbers, text, and BLOBs. It is not possible to add a sixth "JSON" type.
Документация по расширению SQLite JSON1
В процессоре командной строки SQLite я могу заполнить эту таблицу с помощью простого оператора INSERT, такого как этот
INSERT INTO moods (dow,tsn,lato,agitation,preoccupancy,tensity,taps)
VALUES(1,0,20,'{"A2":1}','{"P4":2}','{"T4":3}','{"M10":4}');
поскольку он принимает как одинарные, так и двойные кавычки для строк.
Чтобы сделать то же самое в моем гибридном приложении для Android, я делаю следующее
String ag = JOString("A" + DBManage.agitation,1);
String po = JOString("P" + (DBManage.preoccupancy + 15),1);
String te = JOString("T" + DBManage.tensity,1);
который возвращает такие строки, как {"P4":2} и т. д. Мой следующий шаг:
ContentValues cv = new ContentValues();
cv.put("dow",0);
cv.put("tsn",1);
cv.put("lato",2);
cv.put("agitation",ag);
cv.put("preoccupancy",po);
cv.put("tensity",te);
long rowid = db.insert("moods",null,cv);
который работает. Однако, изучив сохраненные значения, я обнаружил, что то, что было внесено, на самом деле
{"dow":0,"tsn":5,"lato":191,"tensity":"{\"T0\":1}","agitation":"
{\"A1\":1}","preoccupancy":"{\"P15\":1}","taps":"{}"}]
Если я не понимаю чего-то здесь, лежащая в основе ContentValues.put или реализация SQLiteDatabase.insert взяли на себя задачу избежать цитируемых строк. Возможно, этого следовало ожидать, учитывая, что преимущество перехода по маршруту SQLiteDatabase.insert с ContentValues заключается в защите от атак SQL-инъекций. Однако в данном случае это помеха, а не помощь.
Если не выполнять необработанный SQL через execSQL, есть ли другой способ поместить JSON в таблицу базы данных SQLite?
Я должен добавить, что просто заменив двойные кавычки одинарными кавычками
String ag = JOString("A" + DBManage.agitation,1);
ag = ag.replaceAll("\"","'");
не сработает, т.к. последующая попытка извлечь JSON из таблицы
SELECT ifnull((select json_extract(preoccupancy,'$.P4') from moods where dow = '1' AND tsn = '0'),0);
приведет к ошибке искаженный JSON, выдаваемой расширением SQLite JSON1.
Эммм ... не знаю, насколько этот комментарий уместен. Если бы мне не удалось использовать SQLite JSON1, я бы задал этот вопрос. 1. JSON1 по умолчанию доступен на Androiid, 2. Я использую версию SQLCipher, в которой он наверняка включен. Я не спрашиваю "почему мой JSON не работает?"
можно иметь методы для моделей данных, такие как .fromJson() или .toContentValues() ... также полезен Jackson Object Mapper. json_extract() не всегда возвращает только значения: sqlite.org/json1.html#the_json_extract_function.
см. github.com/eugenp/tutorials/tree/master/jackson ... особенно «Пользовательский сериализатор», «Пользовательский десериализатор» (который может быть проще контролировать, чем шаблоны извлечения.
расширение JSON1 можно включить только с опцией времени сборки
SQLITE_ENABLE_JSON1... скорее всего, даже недоступно на Android. попробуйте GSON: mvnrepository.com/artifact/com.google.code.gson/gson/2.8.5