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.
Simplemente crea un usuario con mascotas (ignorar mascotas).
@Entity public class User { @PrimaryKey public int id; @Ignore private List<Pet> petList; }
Crear mascota.
@Entity public class Pet { @PrimaryKey public int id; public int userId; public String name; }
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.