Android Room:如何使用自定义查询嵌入式数据库

5
我有一个PostDAO,长这样。
@Dao
public interface PostDAO extends DAOTemplate<Post> {
    @Query("SELECT * FROM posts order by time DESC")
    LiveData<List<Post>> getPosts();
}

并且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
    }
}

正如您所看到的,User 对象是 @Embedded 的。

而 User 的 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);
}

用户模型类

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

现在,我希望在Post对象中的Embedded用户字段上填充一个名为“hasNewMusic”的子查询字段。尝试了上述方法,但不起作用,也不确定这是否是正确的做法。
1个回答

4
首先,SQLite 和 Room(据我所知)中不存在布尔类型,它们将 1 和 0 的 INTEGER 值映射为布尔类型的 true 和 false(请参见在 Room 数据库中硬编码布尔查询)。从名称可以猜测 sound_time 不限于 1 和 0 的值。因此,请尝试将 sound_time 转换为布尔类型。

此外,我认为你误用了 @Embedded 注解。它用于将一个表的列放入可以按某种原因分组的类中。例如,在这里 (@Embedded) 中写道:

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

因此,您应该修改 PostDAO::getPosts() 方法来通过 INNER JOIN 加上巨大的 select 返回 User 的列。我不保证这会起作用,因为我没有做过。而且出于某些原因,这样做是不好的。

或者,您可以将 Post 保留为没有 User 字段的实体,并创建一个名为 PostWithUser 的实体并使用 @Relation 注解。这是更好和推荐的文档建议。

更新:

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

  1. Remove User field from post.
  2. Add ForeignKey to Post. I'll use userId, if uid is already for that use it instead:

    @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....
    
    }
    
  3. Make PostWithUser class:

    class PostWithUser {
        @Embedded lateinit var post: Post
        @Embedded lateinit var user: User 
    }
    
  4. Make PostWithUserDao:

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

由于我没有在这里处理sound_time子查询,所以我将在第二个查询中处理它,但是如果您想出如何处理它,我认为它可以起作用。

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


关于关系,不要认为它在这里起作用,因为它是一对多的。 - Relm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接