Недавно вышла 2.4.0-alpha04 -версия Room, которая упрощают написание методов DAO и позволяет возвращать данные запросов в формате Map<key,value>. В этом посте мы вспомним про форматы JOIN в SQLite и напишем простой пример, демонстрирующий новую фичу в Room.
Типы Join в SQLite
Для начала, давайте вспомним, что такое join. Join – это возможность объединения двух и более таблиц в одну при помощи команды SELECT и ключевого слова JOIN.
Принцип работы запросов на объединения таблиц в SQL и реляционных базах данных заключается в том, что на основе переданного условия, которое называют предикатом объединения СУБД определяет какие строки из двух таблиц ей нужно объединять.
Вообще, стандарт SQL выделяет гораздо больше модификаторов JOIN:
- INNER JOIN – внутреннее объединение таблиц.
- LEFT JOIN или LEFT OUTER JOIN – левое внешнее объединение таблиц.
- RIGHT JOIN или RIGHT OUTER JOIN – правое внешнее объединение таблиц.
- FULL JOIN – полное объединение таблиц.
- CROSS JOIN – перекрестное объединение таблиц
Но в базах данных SQLite (а соответственно в Room) есть только три вида объединения таблиц.
Давайте рассмотрим первый тип объедения. Например, у нас есть приложения для учёта недвижимости. Соответственно у нас есть 2 сущности: пользователь и квартира:
Таким образом, у нас отношение 1 ко многим, то есть 1 владелец и много квартир. Чтобы сделать запрос к такой БД, состоящей из таких таблиц, можно попробовать:
- Использовать аннотацию @Relation
- Использовать inner join
Первый вариант мог бы выглядеть так. Сначала указываем data класс для получения результата:
data class UserWithApartment( @Embedded val user: User, @Relation( parentColumn = "userId", entityColumn = "ownerId" ) val apartments: List<Apartment> )
Затем в DAO описываем метод получения данных:
@Transaction @Query("SELECT * FROM User") fun getUsersWithAparts():List<UserWithApartment>
Room автоматически, используя аннотацию @Relation вернёт нужные данные.Однако, теперь нам необязательно создавать дополнительный класс-холдер для получения результата. Такой результат мы можем получить, используя inner join. Перепишем приведенный пример выше, используя join:
@Query("SELECT * FROM User JOIN Apartment ON User.userId = Apartment.ownerId") fun getUserAndAparts(): Map<User,List<Apartment>>
Таким образом мы получили всех владельцев и список квартир. При этом мы избежали лишнего класса-холдера – однако теперь SQL-запрос стал сложнее. В данном примере мы делаем join на основе первичного ключа пользователя.
На этом всё, надеюсь этот пример был для вас полезен и вы вспомнили что такое join и как его использовать. Не забудьте присоединиться к нам в Telegram, а на платформе AndroidSchool.ru публикуются полезные материалы для Android-разработчика и современные туториалы.
- Онлайн — интенсив по Android-разработке с code review
- Telegram — канал @android_school_ru где публикуются полезные материалы для Android