Android Room: как моделировать отношения?
Я только начал работать с комнатой, и хотя все кажется довольно интуитивным, я в настоящее время не совсем понимаю, как именно я могу обращаться с отношениями.
Поскольку SQLite является реляционной базой данных, вы можете указать отношения между объектами. Хотя большинство библиотек ORM позволяют объектам объектов ссылаться друг на друга, Room явно запрещает это. Даже если вы не можете использовать прямые отношения, Room все еще позволяет вам определять ограничения внешнего ключа между объектами. (Источник: https://developer.android.com/topic/libraries/architecture/room.html#no-object-references)
- Как вы должны моделировать привязку От многих до многих или От одного до большого?
- Как это будет выглядеть на практике (например, DAOs + Entities)?
Ответы
Ответ 1
Вы можете использовать аннотацию @Relation
для обработки отношений в комнате.
Удобная аннотация, которая может быть использована в Pojo автоматически fetch. Когда Pojo возвращается из запроса, все его отношений также вызывается Room.
См. документ.
(в документе Google есть путающие примеры. Я написал шаги и некоторые основные объяснения в моем другом ответе. проверить)
Ответ 2
Я создал простой метод удобства, который вручную заполняет отношения от одного до многих.
Например, если у вас есть один к другому между страной и городом, вы можете использовать этот метод, чтобы вручную заполнить свойство cityList в стране.
/**
* @param tableOne The table that contains the PK. We are not using annotations right now so the pk should be exposed via a getter getId();
* @param tableTwo The table that contains the FK. We are not using annotations right now so the Fk should be exposed via a getter get{TableOneName}Id(); eg. getCountryId();
* @param <T1> Table One Type
* @param <T2> Table Two Type
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
private static <T1, T2> void oneToMany(List<T1> tableOne, List<T2> tableTwo) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String tableOneName = tableOne.get(0).getClass().getSimpleName();
String tableTwoName = tableTwo.get(0).getClass().getSimpleName();
for (T1 t1 :
tableOne) {
Method method = t1.getClass().getMethod("getId");
Integer pkId = (Integer) method.invoke(t1);
List<T2> listForCurrentId = new ArrayList<>();
for (T2 t2 : tableTwo) {
Method fkMethod = t2.getClass().getDeclaredMethod("get".concat(tableOneName).concat("Id"));
Integer fkId = (Integer) fkMethod.invoke(t2);
if (pkId == fkId) {
listForCurrentId.add(t2);
}
}
Method tableTwoList = t1.getClass().getMethod("set".concat(tableTwoName).concat("List"), List.class);
tableTwoList.invoke(t1, listForCurrentId);
}
}
Вот как я его использую.
SystemDefaults systemDefaults = new SystemDefaults();
return Single.zip(systemDao.getRoles(), systemDao.getCountries(), systemDao.getCities(), (roles, countries, cities) -> {
systemDefaults.setRoles(roles);
*ConvenienceMethods.oneToMany(countries,cities);*
systemDefaults.setCountries(countries);
return systemDefaults;
});