tutorial studio room jetpack example android android-room android-architecture-components architecture-components

jetpack - room android studio



Sala Android: Insertar entidades de relaciĆ³n usando Sala (4)

Actualmente no hay una solución nativa para este problema. He creado este https://issuetracker.google.com/issues/62848977 en el rastreador de problemas de Google y el Equipo de Componentes de Arquitectura dijo que agregarán una solución nativa en o después de la versión 1.0 de la biblioteca de Room.

Solución temporal:

Mientras tanto puedes usar la solución mencionada por .

public void insertPetsForUser(User user, List<Pet> pets){ for(Pet pet : pets){ pet.setUserId(user.getId()); } petDao.insertAll(pets); }

He añadido una a muchas relaciones en la sala usando Relation . Me referí a este post para escribir el siguiente código de relación en la sala.

La publicación explica cómo leer los valores de la base de datos, pero el almacenamiento de las entidades en la base de datos hizo que userId estuviera vacío, lo que significa que no hay relación entre las 2 tablas.

No estoy seguro de cuál es la forma ideal de insert un User y una List of Pet en la base de datos mientras se tiene el valor userId .

1) Entidad del usuario:

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

2) Entidad de la mascota:

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

Ahora para obtener los registros de la base de datos usamos el siguiente DAO :

@Dao public interface UserDao { @Insert fun insertUser(user: User) @Query("SELECT * FROM User") public List<UserWithPets> loadUsersWithPets(); }

EDITAR

He creado este problema https://issuetracker.google.com/issues/62848977 en el rastreador de problemas. Esperemos que hagan algo al respecto.


Como Room no administra las relaciones de las entidades, debe configurar el userId de userId en cada mascota y guardarlas. Siempre y cuando no haya demasiadas mascotas a la vez, utilizaré un método insertAll para que sea breve.

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

No creo que haya una mejor manera en este momento.

Para facilitar el manejo, usaría una abstracción en la capa sobre los DAO:

public void insertPetsForUser(User user, List<Pet> pets){ for(Pet pet : pets){ pet.setUserId(user.getId()); } petDao.insertAll(pets); }


No hay una solución nativa hasta cualquier actualización en la biblioteca de salas, pero puede hacerlo por un truco. Encuentra a continuación mencionado.

  1. Simplemente crea un usuario con mascotas (ignorar mascotas).

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

  2. Crear mascota.

    @Entity public class Pet { @PrimaryKey public int id; public int userId; public String name; }

  3. Ahora finalmente en 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; }

Su problema se puede resolver con esto sin crear UserWithPets POJO.


Puede hacerlo cambiando su Dao de una interfaz a una clase abstracta.

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

También puede ir más lejos haciendo que un objeto User tenga una @Ignored List<Pet> pets

@Entity public class User { @PrimaryKey public int id; // User id @Ignored public List<Pet> pets }

y luego el Dao puede asignar UserWithPets a User:

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

Esto te deja con el Dao completo:

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

Es posible que desee tener los insertAll(List<Pet>) e insertPetsForUser(User, List<Pet>) en un PetDAO ... ¡la partición de sus DAO depende de usted! :)

De todos modos, es solo otra opción. Envolver sus DAOs en objetos DataSource también funciona.