Подтвердить что ты не робот

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 в поисковом журнале. Надеюсь, они сделают что-то в этом отношении.

4b9b3361

Ответ 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);
}