13

Dodałem jeden do wielu relacji w pokoju przy użyciu Relation. Odwołałem się do this post, aby wpisać następujący kod dla relacji w pokoju.Android Room: Wstaw obiekty relacji używając Room

Post informuje, jak odczytać wartości z bazy danych, ale zapisanie encji w bazie danych spowodowało, że userId było puste, co oznacza, że ​​nie ma relacji między 2 tabelami.

Nie jestem pewien, co jest idealnym sposobem na insertUser i List of Pet do bazy danych, mając jednocześnie userId wartość.

Podmiot 1) Użytkownik:

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

2) Zwierzęta Podmiot:

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

teraz, aby pobrać rekordy z DB używamy po DAO:

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

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

EDIT

Stworzyłem ten problem https://issuetracker.google.com/issues/62848977 na trackerze emisyjnej. Mam nadzieję, że coś z tym zrobią.

Odpowiedz

5

Jako pokój nie zarządza Relacjami podmiotów, musisz ustawić userId na każdym zwierzaku samemu i zapisać je. Dopóki nie ma zbyt wielu zwierząt na raz, użyłbym metody insertAll, aby było krótko.

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

Nie sądzę, że w tej chwili jest lepszy sposób.

Aby uczynić obsługę łatwiejsze, użyję abstrakcję w warstwie powyżej DAOs:

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

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

    petDao.insertAll(pets); 
} 
+0

Próbowałem tego samego używając 'Stream'. Mam tylko nadzieję, że jest lepszy sposób na zrobienie tego. –

+0

Nie sądzę, że istnieje lepszy sposób, ponieważ dokumentacja mówi, że celowo pozostawił referencje z biblioteki: https://developer.android.com/topic/libraries/architecture/room.html#no-object- referencje – tknell

+0

Utworzyłem ten problem https://issuetracker.google.com/issues/62848977 w narzędziu do śledzenia problemów. Mam nadzieję, że coś z tym zrobią. –

1

Obecnie istnieje nie natywne rozwiązanie tego problemu. Stworzyłem ten https://issuetracker.google.com/issues/62848977 w narzędziu do śledzenia błędów Google, a zespół ds. Komponentów architektury powiedział, że doda rozwiązanie natywne w wersji 1.0 biblioteki Pokój lub później.

Tymczasowe Obejście:

Tymczasem można użyć roztworu wzmiankowanym przez tknell.

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

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

    petDao.insertAll(pets); 
} 
9

Możesz to zrobić, zmieniając swojego Dao z interfejsu na klasę abstrakcyjną.

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

Można też pójść dalej przez posiadające User obiektu mają @Ignored List<Pet> pets

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

    @Ignored 
    public List<Pet> pets 
} 

a następnie Dao może odwzorowywać UserWithPets do użytkownika:

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

To pozostawia nam z pełnym 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(); 
} 

Być może zechcesz zamiast tego zastosować metody z PetDAO ... w jaki sposób dzielisz swoje DAO od Ciebie! :)

W każdym razie to tylko kolejna opcja. Zawijanie DAO w obiektach DataSource również działa.

+0

Świetny pomysł, aby umieścić metodę wygody w klasie abstrakcyjnej zamiast interfejsu. –

2

Nie ma natywnego rozwiązania do czasu aktualizacji w bibliotece pokoju, ale można to zrobić za pomocą lewy. Znajdź poniżej wymienione.

  1. Po prostu stwórz użytkownika ze zwierzętami (zignoruj ​​zwierzęta).

    @Entity 
    public class User { 
         @PrimaryKey 
         public int id; 
    
         @Ignore 
         private List<Pet> petList; 
    } 
    
  2. Stwórz zwierzaka.

    @Entity 
    public class Pet 
    { 
        @PrimaryKey 
        public int id;  
        public int userId; 
        public String name; 
    } 
    
  3. Teraz w końcu w 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; 
    } 
    

Twój problem może być rozwiązany przez to bez tworzenia UserWithPets POJO.

+0

Podoba mi się ten, ponieważ unika on POJO UserWithPets. Dzięki zastosowaniu domyślnych metod DAO może być również interfejsem. Jedynym minusem jest to, że metody insertUser() i insertPetList() są metodami publicznymi, ale nie powinny być używane przez klienta. Podkreślam przed nazwą tych metod, aby pokazać, że nie powinny być używane, jak pokazano powyżej. – guglhupf