Android room relation order by

Database relations with Room

An important part of designing a relational database is splitting the data into related tables and pulling the data together in meaningful ways. Starting with Room 2.2 (now stable) we have support for all possible relations between tables: one-to-one, one-to-many and many-to-many, with one annotation: @Relation .

One-to-one relations

Let’s say that we live in a (sad) world where a person can own only one dog and a dog can have only one owner. This is a one-to-one relation. To model this in a relational database, we create two tables: Dog and Owner , where the Dog table has a reference to the owner id, or the Owner has a reference to a dog id. In Room, we create two entities:

Let’s say that we want to display the list of all dogs and their owners on the screen. To do this, we would create a DogAndOwner data class:

To query this using SQLite, we would need to 1) run two queries: one that gets all owners, and one that gets all dogs based on owner ids and then 2) handle the object mapping.

To get a List using Room, we don’t need to implement the two queries ourselves and handle the object mapping, but rather, use the @Relation annotation.

In our example, since Dog has the owner’s information, we add the @Relation annotation to the dog variable,: specifying that the ownerId column on the parent (i.e. the Owner entity) corresponds to the dogOwnerId :

Our Dao is now simplified to:

Note: Because Room runs the two queries for us under the hood, add the @Transaction annotation, to ensure that this happens atomically.

One-to-many relations

Let’s say that an owner can have multiple dogs (yay!); we’d have a one-to-many relation between Dog and Owner . The database schema we previously defined doesn’t change — we still have the same tables, since the relating key is already in the “many” table of the relationship.

Now, to display the list of owners with their dogs, we need to create a new data class to model this:

To avoid running two separate queries, we can define a one-to-many relation between Dog and Owner , by annotating the List with @Relation as before:

The Dao becomes:

Many-to-many relations

Now suppose we live in a perfect world where an owner can have multiple dogs, and that a dog can have multiple owners. To model this schema, our Dog and Owner tables are not enough. Since a dog can have multiple owners, we need to have multiple entries of the same dog id, matching to different owner ids. Because dogId is the primary key in Dog , we can’t insert multiple dogs with the same id. To overcome this, we need to create an associative table (also known as cross-reference table) that keeps (dogId,ownerId) pairs:

If we now want to get the list of all owners with dogs: List , using just SQLite queries, we need to write two queries: one that gets all owners and one that joins the Dog and the DogOwnerCrossRef tables:

To implement this in Room, we need to update our OwnerWithDogs data class and tell Room that in order to get the Dogs , it needs to use the DogOwnerCrossRef associate table. We reference the table by using a Junction :

In our Dao, we need to select from Owners and return the right data class:

Advanced relation use cases

When using the @Relation annotation, Room infers the entity to use from the type of the annotated property by default. For example, until now we annotated a Dog (or a List ) with @Relation , telling Room how to model the class and which columns to query

Читайте также:  Как синхронизировать айфон с андроидом данные перенос

If we want to return a different object, for example a Pup , that is not an entity but contains some of the fields, we can specify the entity to use in the @Relation annotation:

If we want to return only specific columns from an entity you need to tell Room which these are by defining them in the projection property of the @Relation . For example, let’s say that we just want to get the names of all the dogs in our OwnerWithDogs data class. Since we would need a List , Room can’t deduce whether those strings correspond to the name or to the breed, so we need to specify the column in the projection:

If you want to define a stricter relationship between the dogOwnerId and ownerId , independent of what kind of relation you’re creating, use a ForeignKey constraint between the fields. Keep in mind that SQLite foreign keys define indices and can have cascading triggers that update or delete entries in your tables. So decide whether you want to use foreign keys based on whether you do want this kind of functionality in your database.

Whether you need one-to-one, one-to-many or many-to-many support, Room has you (and your doggos) covered with one annotation: @Relation . Find out more about Room 2.2 features from our Android Dev Summit ’19 talk:

Источник

Android Room: How works One to many relationship + example

Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. One-to-many relationship exists when one row in table A may be linked with many rows in table B, but one row in table B is linked to only one row in table A.

How works room?

The importance of using room to work classes as entities is very powerful but its documentation is very poor on how to work the relations between entities.
To know the basic notions of room you can follow this tutorial https://developer.android.com/training/data-storage/room

Android one to many in room explanation:

For this example using basic concepts of databases and room, first declare their entities Course.java and Student.java:

Course.java is our parent class and we add an id that is auto generated with the @PrimaryKey annotation (autoGenerate = true)

In the child class Student.java an attribute must be added that contains the id of the parent class, in this case id_fkcourse and the annotation @ForeigKey will be used to make the relationship between entities.

To do this, create a new data class where each instance holds an instance of the parent entity and a list of all corresponding child entity instances. Add the @Relation annotation to the instance of the child entity, with parentColumn set to the name of the primary key column of the parent entity and entityColumn set to the name of the column of the child entity that references the parent entity’s primary key.

Add Dao interface:

It’s important to mention that the @Transaccion annotation should be used. One method will be for the course and another for the list of assigned students.
Continuing with the MVVM pattern we already have to have our classes for ViewModel and Repository:

In order for the inserting process not to conflict with the main thread we must add an asynchronous class that handles it.

In the for instruction we assign each student the id of the course that was inserted. This id is generated automatically and we only have to obtain it by assigning a long data type to the result.
This snippet is very important what understand because manage the relationship.
Viewmodel class:

Finally these are the classes that are in charge of managing the relationship of one to many. The CourseWithStudents class is very important since it handles the relationship at the entity level linking both course models with their students.

Источник

Использование Room @Relation с помощью ORDER BY

Я пробую библиотеку Room, которая, кстати, очень впечатляет!

Читайте также:  Как использовать андроид как роутера

Таким образом, у меня есть два @Entity и один POJO, который состоит из двух объектов.

Моя первая сущность =>

Моя вторая сущность с внешним ключом =>

Мой POJO с @Relation

Все это отлично работает с моими @Dao и репозиториями.

Но я хочу, чтобы мой список @Relation был заказан по дате, и я не хочу, чтобы StepEntity реализовал Comparable и создал Collections.sort().

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

Я знаю, что OP сказал нет в Collection.Sort(), но, учитывая обстоятельства, кажется, это самый чистый подход. Как я сказал выше, я думаю, что лучше избегать необходимости делать отдельные запросы каждый раз, когда данные должны быть доступны. Сначала реализуем Comparable.

И теперь для его использования добавьте оболочку метода в существующую @Relation POJO

Я не думаю, что есть встроенный способ сделать это в текущей версии комнаты.

Я могу предложить два возможных решения.

Вместо POJO с @Relation просто используйте два отдельных запроса для получения ваших объектов. Таким образом, вы можете заказать экземпляры StepEntity именно так, как вам нравится. Когда вы получаете ColisEntity и все упорядоченные соответствующие записи StepEntity , вы можете ColisWithSteps объект ColisWithSteps в вашем слое репо и вернуть его. Вы можете создать представление базы данных, которое заказывает записи StepEntity в желаемом порядке, а затем использовать этот ответ Views in Room, чтобы иметь возможность использовать его.

Я думаю, что вариант 1 является лучшим в вашем случае — да, он будет включать в себя два запроса, но по крайней мере он не нарушит ваши миграции БД, и вы сможете использовать Room в своих интересах.

Источник

Использование @Relation комнаты с ORDER BY

Я пробую Библиотеку комнаты, которая, кстати, очень впечатляет!

Итак, у меня есть два @Entity и один POJO, который состоит из двух сущностей.

Моя первая сущность =>

Моя вторая сущность с внешним ключом =>

Мой POJO с @Relation

Все это прекрасно работает с моими @Dao и репозиториями.

Но я хочу, чтобы мой @ Relation List был упорядочен по дате, и я не хочу, чтобы StepEntity реализовал Comparable и создал Collections.sort ().

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

4 ответа

Я не думаю, что есть встроенный способ сделать это в текущей версии Room.

Я могу предложить два возможных решения.

  1. Вместо POJO с @Relation просто используйте два отдельных запроса для получения ваших объектов. Таким образом, вы можете упорядочить ваши экземпляры StepEntity именно так, как вам нравится. Когда вы получите ColisEntity и все упорядоченные соответствующие StepEntity записи, вы можете создать ColisWithSteps объект в вашем слое репо и вернуть его.
  2. Вы можете создать представление базы данных, упорядочивающее StepEntity записей в нужном порядке, а затем использовать этот ответ Виды в комнате, чтобы иметь возможность использовать его.

Я думаю, что вариант 1 является лучшим в вашем случае — да, он будет включать использование двух запросов, но, по крайней мере, он не нарушит миграцию вашей БД, и вы сможете использовать Room в своих интересах.

У меня была такая же проблема, вот решение:

Вот пример, который объясняет, что делает INNER JOIN:

Для запроса данных из нескольких таблиц вы используете предложение INNER JOIN. Предложение INNER JOIN объединяет столбцы из коррелированных таблиц.

Предположим, у вас есть две таблицы: A и B.

A имеет столбцы a1, a2 и f. B имеет столбцы b1, b2 и f. Таблица A ссылается на таблицу B, используя столбец внешнего ключа с именем f. Для каждой строки в таблице A предложение INNER JOIN сравнивает значение столбца f со значением столбца f в таблице B. Если значение столбца f в таблице A равно значению столбца f в таблице B, он объединяет данные из столбцов a1, a2, b1, b2 и включает эту строку в набор результатов.

Я знаю, что OP сказал нет. Collection.Sort (), но, учитывая обстоятельства, это кажется самым чистым подходом. Как я уже говорил выше, я думаю, что лучше избегать необходимости выполнять отдельные запросы каждый раз, когда необходимо получить доступ к данным. Сначала реализуем Comparable.

А теперь, чтобы использовать его, добавьте метод-обертку в существующий @Relation POJO

Читайте также:  Пошаговая инструкция прошивки android

Вот рабочее решение для применения сортировки с Relation в комнате v1.0.0.

Источник

Урок 10. Room. Запрос из нескольких таблиц. Relation

В этом уроке рассмотрим, как получать данные из нескольких таблиц. А также разберемся, как использовать аннотацию Relation.

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

Для примера будем использовать две таблицы: сотрудники и отделы. Каждый сотрудник прикреплен к какому-либо отделу.

Entity объект для отделов:

Entity объект для сотрудников:

В поле departmentId хранится id отдела, к которому прикреплен сотрудник.

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

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

Т.к. поле name есть в обоих таблицах, то для отдела переименовываем его в department_name

Обратите внимание на тип объектов, который мы будем получать от этого метода. Это EmployeeDepartment. Нам нужно создать этот объект, и указать в нем все поля, которые мы ожидаем получить от запроса.

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

Relation

Аннотация Relation также позволяет делать запросы из нескольких таблиц, но структура результата будет немного другой. И нам самим не придется писать сложные запросы. Room все сделает за нас.

Давайте представим, что нам надо получить список отделов. И к каждому отделу должен прилагаться список сотрудников.

Структура для этих данных будет выглядеть так:

Это не Entity, а обычный класс. В полях id и name будут данные отдела.

В employees будет список сотрудников этого отдела. Для этого мы помечаем список аннотацией Relation, и Room сам заполнит его для нас. Давайте разбираться, как именно Room поймет, что он должен поместить в этот список. Откуда он будет брать данные и по какому условию?

Тип данных списка — это Employee. Это Entity объект, для него в базе данных создана таблица. Из этой таблицы Room и будет читать данные по сотрудникам. В параметрах parentColumn и entityColumn указываем названия полей, которые участвуют в условии выборки данных. В результате, Room будет искать сотрудников, у которых entityColumn (т.е. department_id) равен parentColumn (т.е. id) отдела. Все найденные сотрудники окажутся в employees.

По требованиям Room, тип employees должен быть List или Set.

Осталось описать метод в Dao:

Это простой запрос, который вытащит необходимые данные по отделу. А запрос по сотрудникам для каждого отдела сделает за нас Room.

В классе DepartmentWithEmployees мы используем поля id и name для данных по отделу. Но класс Department имеет точно такую же структуру — id и name. Поэтому мы в DepartmentWithEmployees можем заменить эти поля на одно поле с типом Department и аннотацией Embedded:

Предположим, что нам нужны не все данные по сотрудникам, а только некоторые поля. Например, name и salary. Создаем под них класс:

И используем его, как тип в Relation-списке

А чтобы Room знал, откуда брать данные по сотрудникам, указываем Entity класс Employee в параметре entity.

Relation может быть вложенным. Т.е. в нашем примере класс EmployeeNameAndSalary также может содержать в себе Relation, который будет для каждого сотрудника собирать, например, список техники, записанной на него.

Relation не может быть использован в Entity классах, только в обычных. Relation поле не может задаваться через конструктор. Оно должно быть public или иметь public set-метод.

Relation + Transaction

При использовании Relation, Room выполняет несколько запросов, чтобы собрать все данные. Имеет смысл выполнять все эти запросы в одной транзакции, чтобы получить корректные данные. Для этого можно использовать аннотацию Transaction

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

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

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

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

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

Источник

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