问题描述
我已经使用关系在Room中添加了一对多关系.我提到了,用于在Room中编写以下代码进行关联.
I've added one to many relationship in Room using Relation.I referred to this post to write the following code for relation in Room.
该帖子介绍了如何从数据库中读取值,但是将实体存储到数据库中导致userId
为空,这意味着两个表之间没有关系.
The post tells how to read the values from the database but storing the entities into the database resulted in userId
to be empty which means there is no relation between the 2 tables.
我不确定在具有userId
值的情况下将insert
a User
和List of Pet
插入数据库的理想方法是什么.
I'm not sure what is the ideal way to insert
a User
and List of Pet
into the database while having userId
value.
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:
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;
}
现在要从数据库中获取记录,我们使用以下DAO
:
Now to fetch the records from DB we use the following DAO
:
@Dao
public interface UserDao {
@Insert
fun insertUser(user: User)
@Query("SELECT * FROM User")
public List<UserWithPets> loadUsersWithPets();
}
编辑
我已创建此问题 https://issuetracker.google.com/issues/62848977 在问题跟踪器上.希望他们会为此做些事情.
I have created this issue https://issuetracker.google.com/issues/62848977 on the issue tracker. Hopefully they will do something regarding it.
推荐答案
您可以通过将Dao从接口更改为抽象类来实现此目的.
You can do this by changing your Dao from an interface to an abstract class.
@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
You can also go further by having a User
object have an @Ignored List<Pet> pets
@Entity
public class User {
@PrimaryKey
public int id; // User id
@Ignored
public List<Pet> pets
}
,然后Dao可以将UserWithPets
映射到用户:
and then the Dao can map UserWithPets
to 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;
}
这将使您拥有完整的道:
This leaves you with the full 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();
}
您可能想在PetDAO中使用insertAll(List<Pet>)
和insertPetsForUser(User, List<Pet>)
方法...如何划分DAO取决于您! :)
You may want to have the insertAll(List<Pet>)
and insertPetsForUser(User, List<Pet>)
methods in a PetDAO instead... how you partition your DAOs is up to you! :)
无论如何,这只是另一种选择.将您的DAO包装在DataSource对象中也可以.
Anyway, it's just another option. Wrapping your DAOs in DataSource objects also works.
这篇关于Android Room:使用Room插入关系实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!