Relation을 사용하여 Room에 일대 다 관계를 추가했습니다 . 이 게시물 을 참조하여 Room의 관계에 대한 다음 코드를 작성했습니다.
게시물은 데이터베이스에서 값을 읽는 방법을 알려 주지만 엔티티를 데이터베이스에 저장 userId
하면 두 테이블간에 관계가 없음을 의미합니다.
나는 확실히 할 수있는 이상적인 방법이 무엇인지 모르겠어요 및 하면서 데이터베이스에 값입니다.insert
User
List of Pet
userId
1) 사용자 엔티티 :
@Entity
public class User {
@PrimaryKey
public int id; // User id
}
2) 애완 동물 개체 :
@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;
}
이제 DB에서 레코드를 가져 오기 위해 다음을 사용합니다 DAO
.
@Dao
public interface UserDao {
@Insert
fun insertUser(user: User)
@Query("SELECT * FROM User")
public List<UserWithPets> loadUsersWithPets();
}
편집하다
이슈 트래커 에이 이슈 https://issuetracker.google.com/issues/62848977 을 만들었습니다 . 바라건대 그들은 그것에 대해 뭔가를 할 것입니다.
답변
Dao를 인터페이스에서 추상 클래스로 변경하여이를 수행 할 수 있습니다.
@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();
}
또한 User
개체에@Ignored List<Pet> pets
@Entity
public class User {
@PrimaryKey
public int id; // User id
@Ignored
public List<Pet> pets
}
그런 다음 Dao는 UserWithPets
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;
}
이것은 당신에게 완전한 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();
}
당신은이 할 수 insertAll(List<Pet>)
및 insertPetsForUser(User, List<Pet>)
대신 PetDAO의 방법을 … 당신이 당신의 DAO를 분할 방법까지입니다! 🙂
어쨌든, 그것은 다른 선택 일뿐입니다. DAO를 DataSource 개체로 래핑하는 것도 작동합니다.
답변
Room Library에서 업데이트 할 때까지는 기본 솔루션이 없지만 트릭으로이를 수행 할 수 있습니다. 아래에서 언급 한 내용을 찾으십시오.
-
애완 동물이있는 사용자 만들기 (애완 동물 무시). getter 및 setter를 추가하십시오. 나중에 ID를 수동으로 설정해야하며
autogenerate
.@Entity public class User { @PrimaryKey public int id; @Ignore private List<Pet> petList; }
-
애완 동물을 만듭니다.
@Entity public class Pet { @PrimaryKey public int id; public int userId; public String name; }
-
UserDao는 인터페이스 대신 추상 클래스 여야합니다. 그런 다음 마지막으로 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; }
UserWithPets POJO를 만들지 않고도 이것으로 문제를 해결할 수 있습니다.
답변
룸은 엔티티의 관계를 관리하지 않기 때문에 userId
각 펫에 대해 직접 설정하고 저장해야합니다. 한 번에 애완 동물이 너무 많지 않은 한 insertAll
짧게 유지 하는 방법을 사용합니다 .
@Dao
public interface PetDao {
@Insert
void insertAll(List<Pet> pets);
}
현재로서는 더 좋은 방법이 없다고 생각합니다.
처리를 더 쉽게하기 위해 DAO 위의 레이어에서 추상화를 사용합니다.
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}
답변
현재이 문제에 대한 기본 해결책 은 없습니다 . 이 https://issuetracker.google.com/issues/62848977 을 Google의 문제 추적기에 만들었고 아키텍처 구성 요소 팀은 Room 라이브러리 v1.0 또는 그 이후에 기본 솔루션을 추가 할 것이라고 말했습니다.
임시 해결 방법 :
한편 tknell에서 언급 한 솔루션을 사용할 수 있습니다 .
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}
답변
이제 v2.1.0에서 Room은 중첩 된 관계가있는 모델에 적합하지 않은 것 같습니다. 이를 유지하려면 많은 상용구 코드가 필요했습니다. 예 : 목록의 수동 삽입, 로컬 ID 생성 및 매핑.
이 관계 매핑 작업은 Requery https://github.com/requery/requery에 의해 즉시 수행됩니다. 또한 Enum 삽입에 문제가 없으며 URI와 같은 다른 복잡한 유형에 대한 일부 변환기가 있습니다.
답변
비교적 간단한 해결 방법으로 제대로 삽입 할 수있었습니다. 내 엔티티는 다음과 같습니다.
@Entity
public class Recipe {
@PrimaryKey(autoGenerate = true)
public long id;
public String name;
public String description;
public String imageUrl;
public int addedOn;
}
@Entity
public class Ingredient {
@PrimaryKey(autoGenerate = true)
public long id;
public long recipeId;
public String name;
public String quantity;
}
public class RecipeWithIngredients {
@Embedded
public Recipe recipe;
@Relation(parentColumn = "id",entityColumn = "recipeId",entity = Ingredient.class)
public List<Ingredient> ingredients;
자동 증가 값에 대해 autoGenerate를 사용하고 있습니다 (long은 purpoes와 함께 사용됨). 내 해결책은 다음과 같습니다.
@Dao
public abstract class RecipeDao {
public void insert(RecipeWithIngredients recipeWithIngredients){
long id=insertRecipe(recipeWithIngredients.getRecipe());
recipeWithIngredients.getIngredients().forEach(i->i.setRecipeId(id));
insertAll(recipeWithIngredients.getIngredients());
}
public void delete(RecipeWithIngredients recipeWithIngredients){
delete(recipeWithIngredients.getRecipe(),recipeWithIngredients.getIngredients());
}
@Insert
abstract void insertAll(List<Ingredient> ingredients);
@Insert
abstract long insertRecipe(Recipe recipe); //return type is the key here.
@Transaction
@Delete
abstract void delete(Recipe recipe,List<Ingredient> ingredients);
@Transaction
@Query("SELECT * FROM Recipe")
public abstract List<RecipeWithIngredients> loadAll();
}
엔티티를 연결하는 데 문제가 있었고 자동 생성 “recipeId = 0″이 항상 발생했습니다. 레시피 엔티티를 먼저 삽입하면 문제가 해결되었습니다.