База данных Realm на Android: Начало
Realm, библиотека хранения от MongoDB, позволяет легко хранить объекты локально. В этом туториале вы создадите приложение с именем PetRealm. Оно использует базу данных Realm для хранения информации о домашних животных и владельцах. Приложение позволяет пользователю добавлять домашних животных для поиска нового дома, добавлять владельцев и показывать список домашних животных, уже взятых из приюта. У него есть возможность назначать для питомца своего владельца.
В ходе этого туториала вы узнаете о:
- База данных Realm
- Схема и сущности
- Вставка объектов
- Запрос и удаление объектов
- Отношения между сущностями
- Realm Studio
- Сравнение Realm и Room
Начало Работы
Загрузите материалы, нажав кнопку “Скачать Материалы”. Откройте Android Studio Arctic Fox или новее и импортируйте стартовый проект.
Ниже краткое описание работы каждого пакета:
- common: содержит классы, используемые в разных разделах приложения.
- di: Здесь вы найдете классы для внедрения зависимостей.
- owners: содержит классы, связанные с владельцами.
- pets: содержит классы, связанные с домашними животными.
- realm: Здесь вы найдете все классы, относящиеся к Realm.
Соберите и запустите приложение. Вы увидите экран с панелью навигации внизу, кнопку для добавления животных и спиннер (или селектор) вверху.
Нажмите на кнопку и вы увидите экран для добавления животных, как показано ниже:
Закройте экран и нажмите на иконку Adopted pets (Принятые питомцы) на панели навигации. Вы увидите следующий пустой экран:
Наконец, нажмите на иконку Owners (Владельцы) на нижней панели навигации. Она откроет экран для владельцев. Нажмите кнопку add (Добавить) и вы увидите следующий экран:
Приложение практически пустое. Пришло время узнать о Realm и использовать его, чтобы приложение заработало.
Представляем Realm
Пришло время начать свое путешествие по Realm (в пер.: 1. Королевство, Царство; 2. Область, Сфера).
Хоть это может прозвучать как-то магически…, база данных Realm - это система управления базой данных объектов. Этот тип базы данных представляет свои сущности как объекты.
Важно: Realm ACID-совместимый. Это означает, что база данных Realm устанавливает:
- Атомарность: путем группировки всех операций в транзакции. Если какая-либо из операций завершается неудачно, база данных откатывает все операции.
- Последовательность: проверяя все изменения с помощью схемы.
- Изоляция: разрешая только одну операцию записи за раз.
- Долговечность: за счет немедленного сохранения любых изменений на диск.
Чтобы начать пользоваться Realm, важно изучить некоторые концепции, чтобы понять, как он работает.
Понимание Realm
Realm - это набор связанных объектов, имеющих предопределенную схему. В одном приложении может быть несколько таких наборов. Каждый realm может иметь разные разрешения и может включать разные типы данных или объекты.
Схема - это набор правил, определяющий типы данных, которые может хранить база данных. Вы определяете эту схему как набор полей и их типов данных в одном или нескольких объектах, называемых объектами Realm.
Объект Realm считывает и записывает данные в базу данных и из нее. База данных хранит эти объекты. Они всегда содержат самые свежие значения.
У каждой схемы есть версия. Изменение схемы состоит из добавления или удаления поля или добавления нового realm объекта. Чтобы сообщить базе данных, что изменилось в схеме, вы должны увеличить версию схемы и создать миграцию.
Теперь, когда вы знаете эти основные концепции, пора начать использовать Realm. В следующем разделе вы добавите Realm в пробный проект.
Инициализация Realm
Откройте build.gradle файл проекта. В разделе зависимостей добавьте следующую строку после зависимости navigation-safe-args-gradle-plugin:
classpath "io.realm:realm-gradle-plugin:10.6.0"
Откройте build.gradle файл модуля, чтобы применить плагин. Добавьте следующую строку после последнего примененного плагина:
apply plugin: 'realm-android'
Заметка
При данной установке Realm будут добавлены все зависимости Realm. Однако можно добавить только те, которые необходимы вашему приложению. Вы можете обратиться к официальной документации, чтобы узнать, как это реализовать.
Нажмите sync now (синхронизировать сейчас), чтобы синхронизировать проект. После завершения синхронизации откройте PetApplication.kt и добавьте следующую строку в onCreate(), импортировав io.realm.Realm:
Realm.init(this)
Эта строка инициализирует Realm и делает его доступным во всем приложении. Теперь вы можете получить экземпляр Realm и начать добавлять объекты и делать запросы.
Realm также нуждается в RealmConfiguration для настройки базы данных. Откройте PetsModule.kt из di - пакета и, импортировав io.realm.RealmConfiguration, добавьте следующий код:
// 1.
private val realmVersion = 1L
@Singleton
@Provides
fun providesRealmConfig(): RealmConfiguration =
// 2.
RealmConfiguration.Builder()
.schemaVersion(realmVersion)
.build()
- Объявите переменную с версией для этой схемы.
- Используйте RealmConfiguration.Builder(), чтобы установить версию схемы и установить RealmConfiguration.
Пришло время создать и запустить приложение. Оно работает, но по-прежнему показывает пустые экраны. Создание схемы будет первым шагом в добавлении функциональности в приложение.
Создание Схемы
PetRealm использует две сущности: домашние животные и владельцы. Эти сущности создают схему базы данных. На следующей диаграмме показаны эти две сущности вместе с их полями.
У обеих сущностей есть id для идентификации каждого элемента, что делает его первичным ключом. Как видите, существует сочетание типов данных String, int и boolean, а также поля NULL и NOT NULL. Вам необходимо определять эту информацию в каждом realm объекте.
Заметка
Realm поддерживает разные типы полей. Полный список этих полей можно найти в официальной документации.
Для начала вы создадите объект с питомцами. В пакете realm создайте новый класс и назовите его PetRealm.kt. Добавьте следующий код:
// 1.
open class PetRealm(
@PrimaryKey // 2.
var id: String = ObjectId().toHexString(), // 3.
@Required // 4.
var name: String = "",
@Required
var petType: String = "",
var age: Int = 0,
var isAdopted: Boolean = false,
@DrawableRes
var image: Int? = null // 5.
): RealmObject() // 6.
Импортируйте androidx.annotation.DrawableRes, io.realm.RealmObject, io.realm.annotations.PrimaryKey, io.realm.annotations.Required и org.bson.types.ObjectId.
В этом коде:
- Вам нужно объявить каждый класс сущности open, а каждое поле как var.
- @PrimaryKey указывает, что поле ID является первичным ключом.
- Realm предоставляет ObjectId() для создания уникальных идентификаторов для каждого объекта. Вы будете использовать его шестнадцатеричное представление.
- @Required указывает, что для поля требуется значение. Добавьте эту аннотацию к name и petType.
- Для полей, допускающих значения null, можно использовать типы, допускающие значение null, и назначить null в качестве значения по умолчанию.
- Каждая сущность должна быть RealmObject().
Создайте класс в пакете realm и назовите его OwnerRealm.kt. Добавьте следующий код:
open class OwnerRealm(
@PrimaryKey
var id: String = ObjectId().toHexString(),
@Required
var name: String = "",
@DrawableRes
var image: Int? = null
) : RealmObject()
Импортируйте androidx.annotation.DrawableRes, io.realm.RealmObject, io.realm.annotations.PrimaryKey, io.realm.annotations.Required и org.bson.types.ObjectId.
С помощью этого кода вы добавляете сущность OwnerRealm в базу данных Realm.
Скомпилируйте и запустите приложение. За кулисами Realm добавляет в схему PetRealm и OnwerRealm. Однако вы по-прежнему будете видеть пустой экран.
Теперь, когда вы создали схему, пора вставить несколько объектов.
Вставка объектов в Realm
Вставка объектов в базу данных - часть записывающих транзакций Realm. Все операции должны происходить в транзакции. Транзакция - это группа операций чтения и записи, которые Realm выполняет как одну операцию. Каждая операция в транзакции должна быть успешной для успешного завершения транзакции. Если какая-либо операция завершается неудачно, то вся транзакция завершается неудачно.
Откройте файл PetDatabaseOperations.kt в realm пакете. Добавьте в конструктор класса следующий параметр:
private val config: RealmConfiguration
С помощью этой строки вы предоставляете RealConfiguration этому классу.
Измените insertPet() следующим образом:
suspend fun insertPet(name: String, age: Int, type: String, image: Int?) {
// 1.
val realm = Realm.getInstance(config)
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 3.
val pet = PetRealm(name = name, age = age, petType = type, image = image)
// 4.
realmTransaction.insert(pet)
}
}
Импортируйте io.realm.Realm, io.realm.kotlin.executeTransactionAwait и kotlinx.coroutines.Dispatchers.
В этом коде вы:
- Получаете экземпляр Realm, используя RealmConfiguration.
- Используете executeTransactionAwait() с Dispatchers.IO, чтобы выполнить транзакцию в фоновом потоке и дождаться ее завершения.
- Создаете новый объект PetRealm.
- Вставляете новый объект PetRealm.
Решающим фактором является использование экземпляра Realm, который в приведенном выше коде называется realmTransaction, предоставленный в лямбда-функции для вставки вновь созданного объекта.
Скомпилируйте и запустите приложение. Нажмите кнопку Add и добавьте нового питомца следующим образом:
Нажмите Add Pet (Добавить питомца) и вы добавите нового питомца в базу данных. Здесь вы должны мне поверить, т.к. приложение еще ничего не отображает.
Добавьте код, чтобы вставить владельца. Откройте OwnerDatabaseOperations.kt и добавьте в его конструктор следующий параметр:
private val config: RealmConfiguration
Эта строка предоставляет RealmConfiguration этому классу.
Измените insertOwner() следующим образом:
suspend fun insertOwner(name: String, image: Int?) {
// 1.
val realm = Realm.getInstance(config)
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 3.
val owner = OwnerRealm(name = name, image = image)
// 4.
realmTransaction.insert(owner)
}
}
Этот код выполняет те же действия, что и при добавлении питомца:
- Получает экземпляр Realm.
- Использует executeTransactionAwait().
- Создает новый объект.
- Вставляет его в базу данных.
Скомпилируйте и запустите приложение. Нажмите кнопку Owners (Владельцы). Добавьте имя и выберите изображение долгим нажатием на него, как показано ниже:
Нажмите Add Owner (Добавить владельца). И вам снова придется поверить мне, что вы добавили нового владельца в базу данных.
Не волнуйтесь. Следующий шаг - это научиться запрашивать базу данных и отображать информацию.
Запрос Realm
Realm предоставляет механизм запросов, который позволяет находить, фильтровать и сортировать объекты. Каждый результат запроса - это живой объект. Это означает, что он содержит самые свежие данные, и, если вы решите изменить результат, он изменит сохраненный объект.
Откройте PetDatabaseOperations.kt. Добавьте следующий код в конец класса:
private fun mapPet(pet: PetRealm): Pet {
return Pet(
name = pet.name,
age = pet.age,
image = pet.image,
petType = pet.petType,
isAdopted = pet.isAdopted,
id = pet.id
)
}
mapPet() сопоставляет объект PetRealm с UI объектом Pet.
Измените retrievePetsToAdopt() следующим образом:
suspend fun retrievePetsToAdopt(): List {
// 1.
val realm = Realm.getInstance(config)
val petsToAdopt = mutableListOf()
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
petsToAdopt.addAll(realmTransaction
// 3.
.where(PetRealm::class.java)
// 4.
.findAll()
// 5.
.map {
mapPet(it)
}
)
}
return petsToAdopt
}
Чтобы получить питомцев, готовых к новому дому, вы:
- Получаете экземпляр Realm.
- Используете executeTransactionAwait().
- Используете where (PetRealm :: class.java) для получения объектов PetRealm.
- findAll() выполняет запрос и возвращает каждый объект PetRealm.
- Сопоставляете PetRealm с объектами Pet.
Теперь, когда вы в ударе, откройте OwnerDatabaseOperations.kt и измените retrieveOwners() следующим образом:
suspend fun retrieveOwners(): List {
// 1.
val realm = Realm.getInstance(config)
val owners = mutableListOf()
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
owners.addAll(realmTransaction
// 3.
.where(OwnerRealm::class.java)
// 4.
.findAll()
// 5.
.map { owner ->
Owner(
name = owner.name,
image = owner.image,
id = owner.id
)
}
)
}
return owners
}
Чтобы получить владельцев, вы:
- Получаете экземпляр Realm.
- Используете executeTransactionAwait().
- Используйте where (OwnerRealm :: class.java) для получения объектов OwnerRealm.
- findAll() выполняет запрос.
- Сопоставляете OwnerRealm с объектами Owner.
Теперь соберите и запустите приложение. Вы увидите животных, которых вы добавили ранее. Если же вы перейдете к экрану Owners, то увидите добавленного вами владельца:
Отличная работа! Теперь вы можете видеть данные из базы данных. Однако, есть ошибка, и вы можете сделать пару улучшений.
Фильтрация Результатов
Ошибка в получении домашних животных заключается в том, что запрос возвращает всех домашних животных: которых уже забрали (Adopted Pets) и которые в процессе ожидания своих новых владельцев (Pets to Adopt). Но Realm предоставляет операторы фильтрации, которые помогают фильтровать результаты на основе определенных значений.
В PetDatabaseOperations.kt измените retrievePetsToAdopt(), добавив следующую строку после .where():
.equalTo("isAdopted", false)
Это действие вернет только те экземпляры PetRealm, которые содержат isAdopted как false.
Теперь измените retrieveAdoptedPets() следующим образом:
suspend fun retrieveAdoptedPets(): List {
val realm = Realm.getInstance(config)
val adoptedPets = mutableListOf()
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
adoptedPets.addAll(realmTransaction
.where(PetRealm::class.java)
.equalTo("isAdopted", true)
.findAll()
.map {
mapPet(it)
}
)
}
return adoptedPets
}
Чтобы получить уже отданных владельцам питомцев, isAdopted должно быть true.
Теперь вы можете реализовать фильтр по типу Pet в списке “Pets to Adopt”. Измените retrieveFilteredPets() следующим образом:
suspend fun retrieveFilteredPets(petType: String): List {
val realm = Realm.getInstance(config)
val filteredPets = mutableListOf()
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
filteredPets.addAll(realmTransaction
.where(PetRealm::class.java)
// 1.
.equalTo("isAdopted", false)
// 2.
.and()
// 3.
.beginsWith("petType", petType)
.findAll()
.map {
mapPet(it)
}
)
}
return filteredPets
}
Этот код выполняет транзакцию для получения объектов PetRealm. Фильтрация работает следующим образом:
- Условие для фильтрации объектов PetRealm, для которых isAdopted установлено как false.
- and() - логический оператор, указывающий, что результат должен соответствовать обоим условиям. Здесь вы можете найти список всех логических операторов, поддерживаемых Realm.
- Условие для фильтрации объектов PetRealm, у которых есть поле petType с указанным значением.
После выполнения запроса и сопоставления результатов с объектами Pet, метод возвращает список домашних животных выбранного petType.
Соберите и запустите приложение. Добавьте в список различные виды домашних животных, как показано на изображении ниже:
В селекторе вверху выберите тип питомца:
Отлично! Вы исправили ошибку и реализовали функцию фильтрации. Теперь вы можете добавить небольшое улучшение для списка владельцев.
Сортировка Результатов
Иногда вам требуется отсортировать результаты запросов до того, как они отобразятся на экране. Перейдите к OwnerDatabaseOperations.kt и добавьте следующую строку в запрос в retrieveOwners() после .findAll():
.sort("name", Sort.ASCENDING)
Импортируйте io.realm.Sort.
Эта операция сортирует результаты по имени в возрастающем порядке.
Соберите и запустите приложение. Добавьте других владельцев в список. Вы увидите владельцев, отсортированных по именам, как на следующем изображении:
У каждого владельца отображается количество животных, которыми он владеет, но на данный момент это число равно нулю. Как вы можете получить количество питомцев используя Realm?
Выполнение Расчетов
Еще одно значение, которое вам нужно отобразить, - это количество домашних животных, которые есть у каждого владельца. У Realm есть разные агрегатные операторы. Данные операторы просматривают список объектов Realm и вычисляют значение.
Откройте OwnerDatabaseOperations.kt и добавьте следующий код:
private fun getPetCount(realm: Realm, ownerId: String): Long {
// 1.
return realm.where(PetRealm::class.java)
// 2.
.equalTo("owner.id", ownerId)
// 3.
.count()
}
В этом коде вы:
- Запрашиваете realm, чтобы получить объекты PetRealm.
- Используете owner.id для фильтрации по идентификатору владельца.
- Считаете количество питомцев у владельца с помощью .count()
Измените создание Owner в retrieveOwner(), добавив numberOfPets:
Owner(
name = owner.name,
image = owner.image,
id = owner.id,
numberOfPets = getPetCount(realmTransaction, owner.id)
)
Теперь у вас есть домашние животные, готовые обрести новый дом и сами владельцы. Пора позволить хозяевам взять себе домашних животных.
Добавление Отношений
Realm предоставляет способ реализации отношений «один к одному», «один ко многим» и обратных отношений.
Определение Отношений “Один к Одному”
Отношения «один к одному» - это когда объект связан не более чем с одним экземпляром другого объекта. В PetRealm это происходит с питомцем, у которого может быть не более одного владельца, как показано на следующей диаграмме:
Откройте PetRealm.kt и добавьте в конструктор класса следующий параметр:
var owner: OwnerRealm? = null
Эта строка сообщает объекту PetRealm, что у него может быть не более одного OwnerRealm. Но в этой базе данных есть еще одна взаимосвязь: один владелец может иметь несколько домашних животных.
Определение Отношений "Один ко Многим"
Отношение «один ко многим» - это когда один объект связан с несколькими объектами. Это сценарий, когда один владелец может иметь несколько домашних животных, как показано на следующей диаграмме:
Откройте OwnerRealm.kt и добавьте в конструктор класса следующий параметр:
var pets: RealmList = RealmList()
Импортируйте io.realm.RealmList.
RealmList позволяет OwnerRealm иметь отношение «один ко многим» с PetRealm.
Отличная работа! Вы реализовали две взаимосвязи в PetRealm. Однако Realm предлагает третий тип отношений, который может облегчить вашу жизнь.
Использование Обратных Отношений
Реализованные вами отношения однонаправленные. Это означает, что когда вы получите результаты запроса для домашних животных, их владельцы не будут отображаться в результатах. Это небольшая проблема, потому что вы должны указать владельца питомца в списке “Adopted pets”.
Для решения этой проблемы Realm предоставляет обратные отношения. Перейдите на PetRealm.kt и замените параметр owner в конструкторе следующими строками:
@LinkingObjects("pets") // 1.
val owner: RealmResults? = null // 2.
Импортируйте io.realm.annotations.LinkingObjects и io.realm.RealmResults.
Чтобы добавить обратную связь, вам необходимо:
- Добавить аннотацию @LinkingObjects, передав в качестве параметра имя поля, к которому вы добавляете связь. Поле в OwnerRealm, которое вы хотите связать, - это pets.
- Поле должно быть val и иметь тип RealmResults.
Теперь, благодаря этому улучшению, вы можете получать информацию об OwnerRealm в запросе PetRealm.
Пришло время собрать и запустить приложение. О, нет! Приложение вылетает. Взглянув на Logcat, вы обнаружите следующую ошибку:
Process: com.raywenderlich.android.petrealm, PID: 16049
io.realm.exceptions.RealmMigrationNeededException: Migration is required due to the following errors:
- Property 'OwnerRealm.pets' has been added.
После добавления новых полей вам необходимо создать миграцию, чтобы сообщить базе данных, что изменилось.
Перенос Базы Данных
Realm сопоставляет каждое состояние схемы базы данных с определенной версией. Если эта схема изменится, как это было при добавлении отношений в предыдущем разделе, версию необходимо увеличить. Вы также должны указать Realm, как обрабатывать различия в схеме, создавая миграцию.
Создайте новый файл в пакете realm и назовите его Migrations.kt. Добавьте следующий код:
// 1.
val migration = RealmMigration { realm, oldVersion, newVersion ->
// 2.
if (oldVersion == 1L) {
// 3.
val ownerSchema = realm.schema.get("OwnerRealm")
val petSchema = realm.schema.get("PetRealm")
// 4.
petSchema?.let {
ownerSchema?.addRealmListField("pets", it)
}
}
}
Импортируйте io.realm.RealmMigration.
Чтобы добавить миграцию, вам необходимо:
- Создать val типа RealmMigration.
- Определите, что делать при каждом изменении версии. oldVersion будет содержать значение предыдущей версии схемы.
- Получите каждую схему, которую нужно изменить.
- ownerSchema требуется новое поле RealmList типа PetRealm. Используйте addRealmListField() с именем поля и типом схемы, который нужен полю.
Откройте PetsModule.kt в пакете di. Увеличьте версию схемы как здесь:
private val realmVersion = 2L
Измените provideRealmConfig() следующим образом:
RealmConfiguration.Builder()
.schemaVersion(realmVersion)
.migration(migration)
.build()
Используйте migration(), чтобы добавить миграцию. Если вы соберете и запустите приложение, оно снова запустится. Все работает как и ожидалось. Пришло время для самого важного шага: забрать домой братьев наших меньших.
Обновление Объектов
Чтобы обновить объекты Realm, вам необходимо запросить объект, который вы хотите обновить, и присвоить новые значения.
Чтобы забрать питомца, isAdopted должно измениться на true, и он будет назначен владельцу. Откройте OwnerDatabaseOperations.kt и измените updatePets() следующим образом:
suspend fun updatePets(petId: String, ownerId: String) {
val realm = Realm.getInstance(config)
// 1.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 2.
val pet = realmTransaction
.where(PetRealm::class.java)
.equalTo("id", petId)
.findFirst()
// 3.
val owner = realmTransaction
.where(OwnerRealm::class.java)
.equalTo("id", ownerId)
.findFirst()
// 4.
pet?.isAdopted = true
// 5.
owner?.pets?.add(pet)
}
}
В этом коде вы:
- Добавляете транзакцию, чтобы запустить операцию записи.
- Делаете запрос на счастливого питомца.
- Делаете запрос хозяина, который заберет питомца.
- Обновите значение isAdopted.
- Добавляете счастливчика в список питомцев владельца.
Откройте PetDatabaseOperations.kt и измените mapPet() следующим образом:
private fun mapPet(pet: PetRealm): Pet {
return Pet(
name = pet.name,
age = pet.age,
image = pet.image,
petType = pet.petType,
isAdopted = pet.isAdopted,
id = pet.id,
ownerName = pet.owner?.firstOrNull()?.name
)
}
Вы можете воспользоваться преимуществом ранее использованных отношений и добавить имя владельца к каждому принятому питомцу.
Соберите и запустите приложение. Нажмите Adopt Me (Прими меня) у любого питомца и выберите хозяина. Позвольте одному владельцу забрать несколько питомцев. Перейдите к экрану Adopted Pets (Принято питомцев), и вы увидите этих счастливчиков:
Откройте экран Owners. Вы можете увидеть, сколько каждый владелец забрал животных.
Прекрасная работа! Вы помогли домашним животным найти хозяина. Однако бывают случаи, когда домашнее животное убегает или хозяин больше не хочет держать животное. В этом случае у вас должна быть возможность удалить их из приложения.
Удаление Объектов
Откройте PetDatabaseOperations.kt и измените removePet() следующим образом:
suspend fun removePet(petId: String) {
val realm = Realm.getInstance(config)
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 1.
val petToRemove = realmTransaction
.where(PetRealm::class.java)
.equalTo("id", petId)
.findFirst()
// 2.
petToRemove?.deleteFromRealm()
}
}
Чтобы удалить объект, вам необходимо:
- Запросите объект, который вы хотите удалить. Этот запрос должен быть в транзакции.
- Используйте deleteFromRealm() в этом объекте, чтобы удалить его из базы данных.
Для удаления взаимосвязанных объектов требуется дополнительный шаг. Откройте OwnerDatabaseOperations.kt и обновите removeOwner() следующим образом:
suspend fun removeOwner(ownerId: String) {
val realm = Realm.getInstance(config)
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 1.
val ownerToRemove = realmTransaction
.where(OwnerRealm::class.java)
.equalTo("id", ownerId)
.findFirst()
// 2.
ownerToRemove?.pets?.deleteAllFromRealm()
// 3.
ownerToRemove?.deleteFromRealm()
}
}
Вы должны:
- Запросить владельца, которого вы хотите удалить.
- Использовать deleteAllFromRealm(), чтобы удалить всех домашних животных, которые есть у владельца.
- Наконец, удалите объект Владелец.
Создайте и запустите приложение и удалите каких-нибудь домашних животных и владельцев. Вы увидите, что при удалении владельца, так же удаляются и его питомцы.
Теперь PetRealm готов. Однако, каким образом можно выполнить отладку в базе данных Realm?
Использование Realm Studio
Realm Studio - это визуальный инструмент, который помогает просматривать, редактировать и создавать базы данных Realm. Зайдите на сайт Realm Studio, скачайте и установите версию 11.1.0.
В Android Studio перейдите в меню Вид ▸ Инструменты Windows ▸ Проводник Устройства. В раскрывшемся списке выберите эмулятор, который вы используете. Перейдите к файлам data ▸ data ▸ com.raywenderlich.android.petrealm ▸ files. Здесь вы можете найти базу данных с именем default.realm, как показано на следующем изображении:
Щелкните правой кнопкой мыши имя файла Realm и выберите Сохранить как. Выберите место на вашем компьютере и сохраните файл. Теперь откройте Realm Studio и нажмите Open Realm file. Перейдите к сохраненному файлу и выберите его. Первой вы увидите схему OwnerRealm:
В нем вы можете увидеть текущие значения ID, имени, изображения и домашних животных. Как видите, значение pets - это список идентификаторов питомцев.
Выберите PetRealm на левой боковой панели, и вы увидите следующее:
Нажмите Создать PetRealm в правом верхнем углу и добавьте следующего питомца:
Нажмите Создать, и вы увидите, что новое домашнее животное добавлено в базу данных.
Другие операции, которые вы можете выполнять в Realm Studio:
- Создание новых классов
- Добавление свойств к существующим классам
- Запрос классов
Если вы хотите узнать больше о Realm Studio, посмотрите официальную документацию.
Теперь, когда вы узнали о Realm, пора поговорить о Room, одной из самых популярных библиотек хранения в Android. В чем разница между Room и Realm?
Сравнение Realm с Room
Jetpack предоставляет Room, библиотеку хранения данных, которая негласно использует SQLite.
В Room можно хранить только примитивные типы и строки. Вы можете использовать type converters для преобразования объекта в примитивные типы и сохранения его в базе данных. Например, если вам нужно сохранить Date, сначала вы должны преобразовать ее в Long.
Room не позволяет объектам сущностей ссылаться друг на друга. Это означает, что при работе с отношениями необходимо создавать промежуточные классы для моделирования этих отношений между сущностями. Здесь вы можете найти дополнительную информацию об отношениях в Room.
С другой стороны, Realm сама обрабатывает сохранение объекта. Это означает, что вы можете хранить примитивные типы, строки и любые типы объектов и списков. Каждый объект должен быть экземпляром RealmObject.
Как вы узнали в разделе отношений, вы можете использовать обратные отношения для получения данных связанной сущности. Вам не нужно выполнять несколько запросов, чтобы получить нужную информацию.
В Realm есть и другие расширенные функции, такие как:
- Создание приложений Realm для синхронизации данных в реальном времени между разными платформами.
- Использование служб приложений для проверки подлинности и управления разрешениями.
- Безупречная работа с MongoDB.
База данных Realm позволяет хранить объекты и получать к ним доступ локально. Вы можете вставлять данные, запрашивать, фильтровать и сортировать результаты, обновлять и удалять объекты. Она также обеспечивает простой способ создания отношений между сущностями.