当前位置: 首页 > 知识库问答 >
问题:

Android房间:使用房间插入关系实体

芮祺
2023-03-14

我在房间使用关系中添加了一对多关系。我引用这篇文章是为了编写以下房间关系代码。

这篇文章讲述了如何从数据库中读取值,但将实体存储到数据库中会导致用户ID为空,这意味着这两个表之间没有关系。

我不确定在具有用户ID值的情况下,将用户和宠物列表插入数据库的理想方法是什么。

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)用户带宠物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在问题追踪器上。希望他们能对此做点什么。

共有3个答案

冯德宇
2023-03-14

由于Room不管理实体的关系,您必须自己在每只宠物上设置userId并保存它们。只要一次没有太多宠物,我会使用插入所有方法来保持简短。

@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);
}
计阳泽
2023-03-14

在Room Library中没有任何更新之前没有本机解决方案,但您可以通过一个技巧来做到这一点。找到下面提到的。

>

  • 只需创建一个有宠物的用户(忽略宠物)。添加getter和setter。请注意,我们以后必须手动设置Id,并且不能使用自动生成。

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

    用户道应该是一个抽象类而不是接口。最后在你的用户道中。

    @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。

  • 费凯康
    2023-03-14

    您可以通过将您的道从接口更改为抽象类来做到这一点。

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

    您还可以让用户对象有一个被忽略的列表

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

    然后Dao可以将用户与宠物映射到用户:

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

    您可能需要插入所有(列表

    无论如何,这只是另一种选择。将您的DAO包装在DataSource对象中也可以。

     类似资料:
    • 我用这个房间已经有一段时间了。我来自mysql的背景,您必须检查查询和其他内容的值。在room中,我发现这有点复杂,因为到目前为止,我可以将dao insert查询声明为void,或者只要返回rowId,如果返回long,我就必须编写一个侦听器来通知UI成功/失败。我的问题是,这是否必要?我是否需要insert/updates/deletes的返回值,或者这些查询是否保证成功?

    • 我可以使用RxJava添加一行,如下所示, 道: DB操作后如何获取行id?

    • 在许多应用中,有必要将用户划分为可以一并处理的几个子集。最好的例子是,一个包含多个房间的聊天应用,当用户收到他所在的房间的消息,而不会收到其他人所在房间的消息。Flask-SocketIO支持通过join_room()和leave_room()函数来支持房间的概念: from flask_socketio import join_room, leave_room @socketio.on('j

    • 我想实现Android房间持久性。这是我的DAO接口。 出于某种原因,我有以下编译错误: 错误:可观察的查询返回类型(LiveData、Flowable、DataSource、DataSourceFactory等)只能与直接或间接(例如通过@关系)访问至少一个表的SELECT查询一起使用。对于@RawQuery,您应该通过observedEntities字段指定要观察的表的列表。公开摘要andro

    • 所以我需要从插入函数中取回插入项目的ID。包括来自Google的消息来源在内的多个消息来源都表示,可以通过作为@插入带注释DAO函数的返回值的单执行此操作。不幸的是,编译总是以以下方式退出: 我试着改成也许 我的代码如下所示: 我完全不知道是什么导致了这一切。那么,我做错了什么?如果这只是一个bug,那么在我的活动和这个活动数据的上下文中获取id的解决方法是什么? 更新:找到了一个非常奇怪的解决方

    • 我使用的是socket.io/node.js/express。当我使用socket.join(“room”)加入socket.io房间时,它会注册该房间,但用户只加入“room”。 这个命令显示了所有的房间,它同时返回'room'和'',尽管我从未创建过'room: 任何帮助都将不胜感激,这是非常奇怪的行为:( 编辑:以下是相关的服务器代码