109 votes

Android Room: Insérer des entités de relation à l'aide de Room

J'ai ajouté beaucoup de relation dans la Chambre à l'aide de la Relation. J'ai fait référence à ce post pour écrire le code suivant pour relation dans la Chambre.

La poste indique comment lire les valeurs de la base de données mais en les stockant les entités dans la base de données a entraîné userId à être vide, ce qui signifie qu'il n'existe pas de relation entre les 2 tables.

Je ne suis pas sûr de ce qui est la façon idéale de l' insert un User et List of Pet dans la base de données tout en ayant userId de la valeur.

1) L'Utilisateur De L'Entité:

@Entity
public class User {
    @PrimaryKey
    public int id; // User id
}

2) Pet Entité:

@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;
}

Maintenant extraire les enregistrements de DB on utilise DAO:

@Dao
public interface UserDao {
    @Insert
    fun insertUser(user: User)

    @Query("SELECT * FROM User")
    public List<UserWithPets> loadUsersWithPets();
}

MODIFIER

J'ai créé ce problème https://issuetracker.google.com/issues/62848977 sur le bug tracker. J'espère qu'ils vont faire quelque chose la concernant.

46voto

Vous pouvez le faire en modifiant votre Dao à partir d'une interface d'une classe abstraite.

@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();
}

Vous pouvez également aller plus loin en ayant un User objet ont un @Ignored List<Pet> pets

@Entity
public class User {
    @PrimaryKey
    public int id; // User id

    @Ignored
    public List<Pet> pets
}

et puis le Dao peut-carte UserWithPets d'Utilisateur:

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;
}

Cela vous laisse avec la pleine 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();
}

Vous voudrez peut-être avoir l' insertAll(List<Pet>) et insertPetsForUser(User, List<Pet>) méthodes dans un PetDAO plutôt... comment partitionner votre DAOs est à vous! :)

De toute façon, c'est juste une autre option. Emballage de votre DAOs dans la source de données d'objets fonctionne également.

45voto

Dipendra Sharma Points 899

Il n'y a pas de solution native avant une mise à jour dans Room Library, mais vous pouvez le faire par un truc. Trouvez ci-dessous mentionné.

  1. Il suffit de créer un utilisateur avec des animaux (ignorer les animaux).

     @Entity
    public class User {
          @PrimaryKey
          public int id; 
    
          @Ignore
          private List<Pet> petList;
    }
     
  2. Créer un animal de compagnie.

     @Entity 
    public class Pet 
    {
        @PrimaryKey
        public int id;     
        public int userId; 
        public String name;
    }
     
  3. Maintenant enfin dans 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;
    }
     

Ceci permet de résoudre votre problème sans créer de POJO UserWithPets.

13voto

tknell Points 691

Comme Room ne gère pas les relations des entités, vous devez définir vous-même les userId sur chaque animal et les enregistrer. Tant qu'il n'y a pas trop d'animaux à la fois, j'utiliserais une méthode insertAll pour rester bref.

 @Dao
public interface PetDao {
    @Insert
    void insertAll(List<Pet> pets);
}
 

Je ne pense pas qu'il existe un meilleur moyen pour le moment.

Pour faciliter la manipulation, j'utiliserais une abstraction dans la couche au-dessus des DAO:

 public void insertPetsForUser(User user, List<Pet> pets){

    for(Pet pet : pets){
        pet.setUserId(user.getId());
    }

    petDao.insertAll(pets);
}
 

6voto

Akshay Chordiya Points 678

Actuellement, il n'existe pas de solution native de ce problème. J'ai créé ce https://issuetracker.google.com/issues/62848977 sur Google outil de suivi et les Composants de l'Architecture de l'Équipe ont dit qu'ils l'ajout d'une solution native ou après v1.0 de la Salle de la bibliothèque.

Solution De Contournement Temporaire:

En attendant, vous pouvez utiliser la solution mentionnée par tknell.

public void insertPetsForUser(User user, List<Pet> pets){

    for(Pet pet : pets){
        pet.setUserId(user.getId());
    }

    petDao.insertAll(pets);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X