13

Ich habe eine Beziehung in Raum mit Relation hinzugefügt. Ich bezog mich auf this post, um den folgenden Code für die Beziehung in Raum zu schreiben.Android Room: Einfügen von Relationsentitäten mit dem Raum

Der Post sagt, wie man die Werte aus der Datenbank liest, aber die Entitäten in der Datenbank gespeichert userId leer zu sein bedeutet, dass es keine Beziehung zwischen den 2 Tabellen gibt.

Ich bin mir nicht sicher, was der ideale Weg ist, ein User und List of Pet in die Datenbank insert während userId Wert.

1) User-Entity:

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

2) Pet Entity:

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

nun die Datensätze aus DB wir die Verwendung holen folgende DAO:

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

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

EDIT

ich dieses Problem geschaffen haben https://issuetracker.google.com/issues/62848977 auf der issue tracker. Hoffentlich werden sie etwas dagegen tun.

Antwort

5

Da Raum nicht die Beziehungen der Entitäten verwaltet, müssen Sie die userId auf jedem Haustier selbst einstellen und speichern. Solange es nicht zu viele Tiere auf einmal gibt, würde ich eine insertAll Methode verwenden, um es kurz zu halten.

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

Ich glaube nicht, dass es im Moment einen besseren Weg gibt.

Um die Handhabung zu erleichtern, ich eine Abstraktion in der Schicht oberhalb der DAOs verwenden würde:

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

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

    petDao.insertAll(pets); 
} 
+0

Ich versuchte das gleiche mit 'Stream'. Ich hoffe nur, dass es einen besseren Weg gibt, es zu tun. –

+0

Ich glaube nicht, dass es einen besseren Weg gibt, da die Dokumentation besagt, dass sie absichtlich Referenzen aus der Bibliothek entfernt haben: https://developer.android.com/topic/libraries/architecture/room.html#no-object- Referenzen – tknell

+0

Ich habe dieses Problem https://issuetracker.google.com/issues/62848977 auf dem Issue Tracker erstellt. Hoffentlich werden sie etwas dagegen tun. –

1

Derzeit keine native Lösung ist für dieses Problem. Ich habe diese https://issuetracker.google.com/issues/62848977 auf Google Problem Tracker erstellt und das Architecture Components Team sagte, dass sie eine native Lösung in oder nach v1.0 von Room-Bibliothek hinzufügen wird.

Vorübergehende Lösung:

der Zwischenzeit können Sie die Lösung von tknell erwähnt verwenden.

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

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

    petDao.insertAll(pets); 
} 
9

Sie können dies tun, indem Sie Ihr Dao von einer Schnittstelle in eine abstrakte Klasse ändern.

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

Sie auch weiter mit einem User Objekt haben eine @Ignored List<Pet> pets

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

    @Ignored 
    public List<Pet> pets 
} 

und dann kann das Dao Karte UserWithPets auf Benutzer gehen können:

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

Dies lässt Sie mit der vollen 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(); 
} 

Vielleicht möchten Sie die insertAll(List<Pet>) und insertPetsForUser(User, List<Pet>) Methoden in einem PetDAO stattdessen haben ... wie Sie Ihre DAOs partitionieren, bleibt Ihnen überlassen! :)

Wie auch immer, es ist nur eine andere Option. Das Wrapping Ihrer DAOs in DataSource-Objekten funktioniert ebenfalls.

+0

Großartige Idee, die Bequemlichkeitsmethode in abstrakte Klasse anstelle der Schnittstelle zu setzen. –

2

Es gibt keine native Lösung bis zu einem Update in der Raumbibliothek, aber Sie können dies mit einem Trick tun. Finden Sie unten erwähnt.

  1. Erstellen Sie einfach einen Benutzer mit Haustieren (Ignoriere Haustiere).

    @Entity 
    public class User { 
         @PrimaryKey 
         public int id; 
    
         @Ignore 
         private List<Pet> petList; 
    } 
    
  2. Haustier erstellen.

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

Ihr Problem ohne die Schaffung UserWithPets POJO durch diese gelöst werden.

+0

Ich mag dieses, weil es die UserWithPets POJO vermeidet. Mit Standardmethoden kann das DAO auch eine Schnittstelle sein. Einziger Nachteil ist, dass insertUser() und insertPetList() öffentliche Methoden sind, aber nicht von einem Client verwendet werden sollten. Vor dem Namen dieser Methoden habe ich einen Unterstrich eingefügt, um zu zeigen, dass sie nicht verwendet werden sollten, wie oben gezeigt. – guglhupf

Verwandte Themen