Android room update or insert

Android room update or insert

Room is one of the best Android persistence libraries, it provides a robust and efficient database layer. However, being built over SQLite, it can hide away some gotchas.

Having worked with Realm and ORMLite previously, I was used to having an Insert or Update operation (also known as Upsert ) which allows for inserting or updating data in a single line of code. The way it works is simple. If data with the same primary key already exists, update the existing row, otherwise insert a new row.

Naturally the first thing I did when starting with Room , was to look for its equivalent. Most of the examples I found used this method:

So what’s the problem?

Say you have an Owner table with a foreign key pointing towards a Cat table, with a cascade delete attribute ( onDelete = ForeignKey.CASCADE ). It won’t be long before some cats start mysteriously disappearing!

This is down to the way OnConflictStrategy.REPLACE works. Instead of being a true upsert operation it does something different under the hood. If the primary key is found in the database, instead of updating the row, SQLite deletes the row and then inserts a new row.

In most cases this isn’t a problem, but since Owner has a foreign key towards Cat , with cascade delete, SQLite will delete the Cat s along with the Owner . When the Owner is reinserted the Cat s are not.

So what’s the solution?

Room and SQLite do not have any built-in methods to upsert a row, but you can add your own. You can make all of the Room Dao s extend a BaseDao which can contain our upsert method insertOrUpdate . In fact there are two, one for single objects, and one for lists of objects.

Now when you update an Owner they won’t lose their Cat s 😻

Источник

Урок 7. Room. Insert, Update, Delete, Transaction

В этом уроке рассмотрим подробнее аннотации Insert, Update и Delete. А также узнаем, как использовать транзакции в Room.

Полный список уроков курса:

Insert

Аннотация Insert — это простой способ вставить объект в базу данных. Мы уже использовали ее в примерах прошлых уроков.

Использование этой аннотации выглядит так:

В Dao интерфейсе описываем метод, который на вход принимает Entity объект. К методу добавляем аннотацию Insert и Room сгенерирует необходимый код в реализации этого интерфейса.

Давайте посмотрим, какие еще возможности у нас есть.

Вставка нескольких объектов

Мы можем передавать в метод не один, а несколько объектов, используя varargs

Также, это может быть список:

Или это вообще может быть любой Iterable:

При вызове этого метода вы можете использовать массив или коллекцию.

Получение id

При вставке метод Insert может возвращать id только что добавленной записи. Для этого надо описать метод так, чтобы он возвращал long.

Если в Employee есть числовой первичный ключ, то именно его значение вы и получите.

В случае добавления нескольких записей, необходимо использовать long[]

Режимы вставки

Рассмотрим ситуацию, когда мы вставляем в таблицу запись, но обнаруживается, что запись с таким ключом там уже есть. По умолчанию мы получим ошибку: SQLiteConstraintException: UNIQUE constraint failed. И ничего в базу не запишется.

Но это можно поменять с помощью параметра onConflict.

В режиме REPLACE старая запись будет заменена новой. Этот режим хорошо подходит, если вам надо вставить запись, если ее еще нет в таблице или обновить запись, если она уже есть.

Также есть режим IGNORE. В этом режиме будет оставлена старая запись и операция вставки не будет выполнена.

Читайте также:  Android для телевизора jvc

Более подробно об этих режимах можно прочесть здесь.

Update

Эта аннотация аналогична Insert, но она не вставляет, а обновляет объекты в бд.

Так же, как и с Insert мы можем использовать коллекции и varargs, чтобы обновлять несколько объектов сразу.

Update ищет в бд запись по ключу. Если не найдет, то ничего не произойдет. Если найдет, то обновит все поля, а не только те, которые мы заполнили в Entity объекте.

Мы можем получить количество обновленных записей. Для этого опишите метод так, чтобы он возвращал int.

Как и Insert, Update поддерживает параметр onConflict.

Delete

Методы с аннотацией Delete будут удалять объекты.

В Delete методах мы также можем использовать коллекции и varargs, чтобы удалять несколько объектов сразу.

Delete ищет в бд запись по ключу.

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

Аннотации Insert, Update и Delete позволяют выполнить простые операции. Для более сложных действий необходимо использовать SQL запросы: INSERT, UPDATE и DELETE. Это можно сделать с помощью аннотации Query. В следующем уроке мы рассмотрим эту возможность.

Транзакции

Аннотация @Transaction позволяет выполнять несколько методов в рамках одной транзакции.

Рассмотрим пример, когда нам нужно добавить объекты Car и Employee:

EmployeeCarDao — отдельный Dao объект для работы с комбинацией Car и Employee. В нем описываем методы для вставки объектов по отдельности, а затем оба этих метода вызываем в одном методе с аннотацией Transaction. В итоге вставятся либо оба объекта, либо, в случае возникновения ошибки, ни один из них.

Обратите внимание, что в этом случае Dao — не интерфейс, а абстрактный класс.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Полный список

В этом уроке рассмотрим подробнее аннотации Insert, Update и Delete. А также узнаем, как использовать транзакции в Room.

Полный список уроков курса:

Insert

Аннотация Insert — это простой способ вставить объект в базу данных. Мы уже использовали ее в примерах прошлых уроков.

Использование этой аннотации выглядит так:

В Dao интерфейсе описываем метод, который на вход принимает Entity объект. К методу добавляем аннотацию Insert и Room сгенерирует необходимый код в реализации этого интерфейса.

Давайте посмотрим, какие еще возможности у нас есть.

Вставка нескольких объектов

Мы можем передавать в метод не один, а несколько объектов, используя varargs

Также, это может быть список:

Или это вообще может быть любой Iterable:

При вызове этого метода вы можете использовать массив или коллекцию.

Получение id

При вставке метод Insert может возвращать id только что добавленной записи. Для этого надо описать метод так, чтобы он возвращал long.

Если в Employee есть числовой первичный ключ, то именно его значение вы и получите.

В случае добавления нескольких записей, необходимо использовать long[]

Режимы вставки

Рассмотрим ситуацию, когда мы вставляем в таблицу запись, но обнаруживается, что запись с таким ключом там уже есть. По умолчанию мы получим ошибку: SQLiteConstraintException: UNIQUE constraint failed. И ничего в базу не запишется.

Но это можно поменять с помощью параметра onConflict.

В режиме REPLACE старая запись будет заменена новой. Этот режим хорошо подходит, если вам надо вставить запись, если ее еще нет в таблице или обновить запись, если она уже есть.

Также есть режим IGNORE. В этом режиме будет оставлена старая запись и операция вставки не будет выполнена.

Более подробно об этих режимах можно прочесть здесь.

Update

Эта аннотация аналогична Insert, но она не вставляет, а обновляет объекты в бд.

Читайте также:  Grand theft auto san andreas android без мода

Так же, как и с Insert мы можем использовать коллекции и varargs, чтобы обновлять несколько объектов сразу.

Update ищет в бд запись по ключу. Если не найдет, то ничего не произойдет. Если найдет, то обновит все поля, а не только те, которые мы заполнили в Entity объекте.

Мы можем получить количество обновленных записей. Для этого опишите метод так, чтобы он возвращал int.

Как и Insert, Update поддерживает параметр onConflict.

Delete

Методы с аннотацией Delete будут удалять объекты.

В Delete методах мы также можем использовать коллекции и varargs, чтобы удалять несколько объектов сразу.

Delete ищет в бд запись по ключу.

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

Аннотации Insert, Update и Delete позволяют выполнить простые операции. Для более сложных действий необходимо использовать SQL запросы: INSERT, UPDATE и DELETE. Это можно сделать с помощью аннотации Query. В следующем уроке мы рассмотрим эту возможность.

Транзакции

Аннотация @Transaction позволяет выполнять несколько методов в рамках одной транзакции.

Рассмотрим пример, когда нам нужно добавить объекты Car и Employee:

EmployeeCarDao — отдельный Dao объект для работы с комбинацией Car и Employee. В нем описываем методы для вставки объектов по отдельности, а затем оба этих метода вызываем в одном методе с аннотацией Transaction. В итоге вставятся либо оба объекта, либо, в случае возникновения ошибки, ни один из них.

Обратите внимание, что в этом случае Dao — не интерфейс, а абстрактный класс.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Урок 5. Room. Основы

Библиотека Room предоставляет нам удобную обертку для работы с базой данных SQLite. В этом уроке рассмотрим основы. Как подключить к проекту. Как получать, вставлять, обновлять и удалять данные.

Полный список уроков курса:

Подключение к проекту

В build.gradle файл проекта добавьте репозитарий google()

В build.gradle файле модуля добавьте dependencies:

Если у вас студия ниже 3.0 и старые версии Gradle и Android Plugin, то подключение будет выглядеть так:

Room имеет три основных компонента: Entity, Dao и Database. Рассмотрим их на небольшом примере, в котором будем создавать базу данных для хранения данных по сотрудникам (англ. — employee).

При работе с Room нам необходимо будет писать SQL запросы. Если вы не знакомы с ними, то имеет смысл прочесть хотя бы основы.

Entity

Аннотацией Entity нам необходимо пометить объект, который мы хотим хранить в базе данных. Для этого создаем класс Employee, который будет представлять собой данные сотрудника: id, имя, зарплата:

Класс помечается аннотацией Entity. Объекты класса Employee будут использоваться при работе с базой данных. Например, мы будем получать их от базы при запросах данных и отправлять их в базу при вставке данных.

Этот же класс Employee будет использован для создания таблицы в базе. В качестве имени таблицы будет использовано имя класса. А поля таблицы будут созданы в соответствии с полями класса.

Аннотацией PrimaryKey мы помечаем поле, которое будет ключом в таблице.

В следующих уроках мы рассмотрим возможности Entity более подробно.

В объекте Dao мы будем описывать методы для работы с базой данных. Нам нужны будут методы для получения списка сотрудников и для добавления/изменения/удаления сотрудников.

Описываем их в интерфейсе с аннотацией Dao.

Методы getAll и getById позволяют получить полный список сотрудников или конкретного сотрудника по id. В аннотации Query нам необходимо прописать соответствующие SQL-запросы, которые будут использованы для получения данных.

Обратите внимание, что в качестве имени таблицы мы используем employee. Напомню, что имя таблицы равно имени Entity класса, т.е. Employee, но в SQLite не важен регистр в именах таблиц, поэтому можем писать employee.

Читайте также:  Не могу включить камеру android

Для вставки/обновления/удаления используются методы insert/update/delete с соответствующими аннотациями. Тут никакие запросы указывать не нужно. Названия методов могут быть любыми. Главное — аннотации.

В следующих уроках мы рассмотрим возможности Dao и его аннотаций более подробно.

Database

Аннотацией Database помечаем основной класс по работе с базой данных. Этот класс должен быть абстрактным и наследовать RoomDatabase.

В параметрах аннотации Database указываем, какие Entity будут использоваться, и версию базы. Для каждого Entity класса из списка entities будет создана таблица.

В Database классе необходимо описать абстрактные методы для получения Dao объектов, которые вам понадобятся.

Практика

Все необходимые для работы объекты созданы. Давайте посмотрим, как использовать их для работы с базой данных.

Database объект — это стартовая точка. Его создание выглядит так:

Используем Application Context, а также указываем AppDatabase класс и имя файла для базы.

Учитывайте, что при вызове этого кода Room каждый раз будет создавать новый экземпляр AppDatabase. Эти экземпляры очень тяжелые и рекомендуется использовать один экземпляр для всех ваших операций. Поэтому вам необходимо позаботиться о синглтоне для этого объекта. Это можно сделать с помощью Dagger, например.

Если вы не используете Dagger (или другой DI механизм), то можно использовать Application класс для создания и хранения AppDatabase:

Не забудьте добавить App класс в манифест

В коде получение базы будет выглядеть так:

Из Database объекта получаем Dao.

Теперь мы можем работать с Employee объектами. Но эти операции должны выполняться не в UI потоке. Иначе мы получим Exception.

Добавление нового сотрудника в базу будет выглядеть так:

Метод getAll вернет нам всех сотрудников в List

Получение сотрудника по id:

Обновление данных по сотруднику.

Room будет искать в таблице запись по ключевому полю, т.е. по id. Если в объекте employee не заполнено поле id, то по умолчанию в нашем примере оно будет равно нулю и Room просто не найдет такого сотрудника (если, конечно, у вас нет записи с >

Аналогично обновлению, Room будет искать запись по ключевому полю, т.е. по id

Давайте для примера добавим еще один тип объекта — Car.

Описываем Entity объект

Теперь Dao для работы с Car объектом

Будем считать, что нам надо только читать все записи, добавлять новые и удалять старые.

В Database необходимо добавить Car в список entities и новый метод для получения CarDao

Т.к. мы добавили новую таблицу, изменилась структура базы данных. И нам необходимо поднять версию базы данных до 2. Но об этом мы подробно поговорим в Уроке 12. А пока можно оставить версию равной 1, удалить старую версию приложения и поставить новую.

UI поток

Повторюсь, операции по работе с базой данных — синхронные, и должны выполняться не в UI потоке.

В случае с Query операциями мы можем сделать их асинхронными используя LiveData или RxJava. Об этом еще поговорим в следующих уроках.

В случае insert/update/delete вы можете обернуть эти методы в асинхронный RxJava. В моем блоге есть статья на эту тему.

Также, вы можете использовать allowMainThreadQueries в билдере создания AppDatabase

В этом случае вы не будете получать Exception при работе в UI потоке. Но вы должны понимать, что это плохая практика, и может добавить ощутимых тормозов вашему приложению.

Переход на Room

Если вы надумали с SQLite мигрировать на Room, то вот пара полезных ссылок по этой теме:

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью