Android Room: Вставьте объекты отношения, используя Room
Я добавил одно-много отношений в комнате, используя Relation.
Я ссылался на этот пост, чтобы написать следующий код для связи в Комнате.
Сообщение сообщает, как читать значения из базы данных, но хранить объекты в базе данных, в результате чего userId
будет пустым, что означает отсутствие связи между двумя таблицами.
Я не уверен, что является идеальным способом для insert
a User
и List of Pet
в базе данных, имея значение userId
.
1) Пользовательский объект:
@Entity
public class User {
@PrimaryKey
public int id; // User id
}
2) Entity Pet:
@Entity
public class Pet {
@PrimaryKey
public int id; // Pet id
public int userId; // User id
public String name;
}
3) UserWithPets POJO:
// Note: No annotation required at this class definition.
public class UserWithPets {
@Embedded
public User user;
@Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class)
public List<Pet> pets;
}
Теперь для извлечения записей из БД мы используем следующий DAO
:
@Dao
public interface UserDao {
@Insert
fun insertUser(user: User)
@Query("SELECT * FROM User")
public List<UserWithPets> loadUsersWithPets();
}
ИЗМЕНИТЬ
Я создал эту проблему https://issuetracker.google.com/issues/62848977 в поисковом журнале. Надеюсь, они сделают что-то в этом отношении.
Ответы
Ответ 1
Вы можете сделать это, изменив свой Дао от интерфейса к абстрактному классу.
@Dao
public abstract class UserDao {
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
_insertAll(pets);
}
@Insert
abstract void _insertAll(List<Pet> pets); //this could go in a PetDao instead...
@Insert
public abstract void insertUser(User user);
@Query("SELECT * FROM User")
abstract List<UserWithPets> loadUsersWithPets();
}
Вы также можете пойти дальше, имея объект User
, имеющий @Ignored List<Pet> pets
@Entity
public class User {
@PrimaryKey
public int id; // User id
@Ignored
public List<Pet> pets
}
а затем Дао может отобразить UserWithPets
для пользователя:
public List<User> getUsers() {
List<UserWithPets> usersWithPets = loadUserWithPets();
List<User> users = new ArrayList<User>(usersWithPets.size())
for(UserWithPets userWithPets: usersWithPets) {
userWithPets.user.pets = userWithPets.pets;
users.add(userWithPets.user);
}
return users;
}
Это дает вам полное Dao:
@Dao
public abstract class UserDao {
public void insertAll(List<User> users) {
for(User user:users) {
if(user.pets != null) {
insertPetsForUser(user, user.pets);
}
}
_insertAll(users);
}
private void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
_insertAll(pets);
}
public List<User> getUsersWithPetsEagerlyLoaded() {
List<UserWithPets> usersWithPets = _loadUsersWithPets();
List<User> users = new ArrayList<User>(usersWithPets.size())
for(UserWithPets userWithPets: usersWithPets) {
userWithPets.user.pets = userWithPets.pets;
users.add(userWithPets.user);
}
return users;
}
//package private methods so that wrapper methods are used, Room allows for this, but not private methods, hence the underscores to put people off using them :)
@Insert
abstract void _insertAll(List<Pet> pets);
@Insert
abstract void _insertAll(List<User> users);
@Query("SELECT * FROM User")
abstract List<UserWithPets> _loadUsersWithPets();
}
Возможно, вы захотите иметь методы insertAll(List<Pet>)
и insertPetsForUser(User, List<Pet>)
в PetDAO... как вы разделяете свои DAO, зависит от вас!:)
Во всяком случае, это еще один вариант. Также работает обтекание ваших DAO в объектах DataSource.
Ответ 2
Поскольку Room не управляет отношениями сущностей, вы должны установить userId
на каждое домашнее животное самостоятельно и сохранить их. До тех пор, пока сразу не будет слишком много домашних животных, я бы использовал метод insertAll
, чтобы он был коротким.
@Dao
public interface PetDao {
@Insert
void insertAll(List<Pet> pets);
}
В настоящий момент я не думаю, что есть лучший способ.
Чтобы упростить обработку, я бы использовал абстракцию в слое над DAO:
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}
Ответ 3
В библиотеке комнат нет встроенного решения, но вы можете сделать это с помощью трюка. Найдите ниже.
-
Просто создайте пользователя с домашними животными (игнорируйте домашних животных).
@Entity
public class User { @Основной ключ public int id;
@Ignore
private List<Pet> petList;
}
-
Создать Pet.
@Entity
public class Pet
{
@PrimaryKey
public int id;
public int userId;
public String name;
}
-
Теперь, наконец, в UserDao.
@Insert
public abstract void insertUser(User user);
@Insert
public abstract void insertPetList(List<Pet> pets);
@Query("SELECT * FROM User WHERE id =:id")
public abstract User getUser(int id);
@Query("SELECT * FROM Pet WHERE userId =:userId")
public abstract List<Pet> getPetList(int userId);
public void insertUserWithPet(User user) {
List<Pet> pets = user.getPetList();
for (int i = 0; i < pets.size(); i++) {
pets.get(i).setUserId(user.getId());
}
insertPetList(pets);
insertUser(user);
}
public User getUserWithPets(int id) {
User user = getUser(id);
List<Pet> pets = getPetList(id);
user.setPetList(pets);
return user;
}
Ваша проблема может быть решена этим без создания UserWithPets POJO.
Ответ 4
В настоящее время для этой проблемы существует нет встроенного решения. Я создал этот https://issuetracker.google.com/issues/62848977 для отслеживания проблем Google, и команда разработчиков архитектуры сообщила, что добавит собственное решение в или после версии 1.0 Библиотека комнат.
Временное обходное решение:
Между тем вы можете использовать решение, упомянутое tknell.
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}