Android Room:如何使用嵌入的自定义查询

Rel*_*elm 5 java android kotlin android-room android-architecture-components

我有一个 PostDAO,看起来像这样。

@Dao
public interface PostDAO extends DAOTemplate<Post> {
    @Query("SELECT * FROM posts order by time DESC")
    LiveData<List<Post>> getPosts();
}
Run Code Online (Sandbox Code Playgroud)

还有 Post Pojo 存在。

@Keep
@Entity(tableName = "posts")
open class Post : Serializable, Cloneable {
    @NonNull
    @PrimaryKey
    var id: String? = null

    var text: String? = null

    var time: Long = 0
    var uid: String? = null
    @Embedded
    var user: User? = null

    public override fun clone(): Post {
        return super.clone() as Post
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,User对象是@Embedded

和用户的 DAO

@Dao
public interface UserDAO extends DAOTemplate<User> {
@Query("SELECT *,(SELECT sound_time FROM sounds WHERE sound_uid =:id AND " +
                "(sound_time < strftime('%s', 'now'))) AS hasNewMusic    " +
                "FROM users WHERE user_uid = :id")
        LiveData<User> getUser(String id);
}
Run Code Online (Sandbox Code Playgroud)

和用户 Pojo

@Keep
@IgnoreExtraProperties
@Entity(tableName = "users")
class User : ModelTemplate() {
    @NonNull
    @PrimaryKey
    @ColumnInfo(name = "user_uid")
    override var id: String? = null;

    var name: String? = null
    var icon: String? = null

    var hasNewMusic: Boolean = false
}
Run Code Online (Sandbox Code Playgroud)

现在,我希望 Post 对象上的 Embedded user 字段hasNewMusic具有使用 subQuery 填充的字段。

尝试了上述方法,不起作用,并且不确定这是否是解决此问题的方法。

Whi*_*rue 4

首先,SQLite 和 Room 中没有布尔值(正如我所读到的)将 1 和 0 INTEGER 值映射到布尔值的 true 和 false(请参阅Room 数据库中的硬编码布尔查询)。从名字上我可以猜出sound_time它不受 1 和 0 值的限制。因此,请尝试转换sound_time为它。

另外,我认为您滥用了@Embedded注释。它用于将一个表的列放入可以通过某种原因分组的类中。例如这里(@Embedded)是这样写的:

因此,如果您有一个返回街道、纬度、经度的查询,Room 将正确构造一个 Address 类。

因此,您应该修改PostDAO::getPosts()方法以返回用户的列,通过INNER JOIN加上您的巨大选择。我不保证这会起作用,因为我还没有这样做。由于某些原因,这也很糟糕。

或者,您可以保留没有 User 字段的 Post 并创建一个名为 PostWithUser 的实体并使用@Relation注释。哪个更好并在文档中推荐。

更新:

要获取两个实体,请尝试以下操作:

  1. 从帖子中删除用户字段。
  2. 将外键添加到帖子中。我将使用userId, ifuid已经为此使用它:

    @Entity(tableName = "posts",
            foreignKeys = [ForeignKey(
                    entity = Post::class,
                    parentColumns = ["user_id"], //from ColumnInfo of User class
                    childColumns = ["userId"],
                    onDelete = CASCADE)],
            indices = [Index(value = ["userId"]]))
    class Post {
    
        @PrimaryKey
        var id: String? = null
    
        var userId: String? = null
    
        //...else code....
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 制作 PostWithUser 类:

    class PostWithUser {
        @Embedded lateinit var post: Post
        @Embedded lateinit var user: User 
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 制作 PostWithUserDao:

    class PostWithUserDao {
        @Query("select * from post, user where post.userId = user.user_id")
        fun getPostsWithUsers(): List<PostWithUser>
    }
    
    Run Code Online (Sandbox Code Playgroud)

由于我没有设法在此处安装 sound_time 子查询,因此我会在第二个查询中执行此操作,但如果您弄清楚如何执行此操作,我认为它可以工作。

另请参阅:具有一对一关系的房间数据库