如何填写房间库中实体的非列字段

Posted

技术标签:

【中文标题】如何填写房间库中实体的非列字段【英文标题】:How to fill non column field of entity in room library 【发布时间】:2018-04-27 04:26:14 【问题描述】:

我有一个类实体如下

@Entity
public class Task     
    private String name; 
    private Integer ParentId;
    private Integer userId;   
    @Ignore
    private int noOfSubTask;

在DAO类中有一个方法getTaskList()

@Dao
public interface TaskDao extends Dao<Task> 

@Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
LiveData<List<Task>> getTaskList();

我要填写 noOfSubTask 的编号由查询的 (SELECT count(*) FROM Task b WHERE a._id = b.ParentId ) 部分给出, 但问题是它不是一个列,所以房间库不会在 dao 实现(自动生成)类中映射它的 getTaskList 方法。

有没有办法使用房间库的 dao 类的任何方法填充实体的非列字段(如我的情况下的 noOfSubTask)?

【问题讨论】:

你要填充哪个值? 查询中从 (SELECT count(*) FROM Task b WHERE a._id = b.ParentId ) 得到的值 @Kevan 提供的答案对您有用吗?它似乎对我不起作用...... 【参考方案1】:

几天前我遇到了同样的问题,并查看了这个帖子。我正在使用 Kotlin data 类来创建数据库实体。鉴于 Kotlin 数据类不能很好地处理继承子类化,这不是一个可行的选择。我的解决方案是在包装类中使用@Embedded关键字,如下:

data class TaskToDisplay(@Embedded
                         var task: Task,
                         var noOfSubTask: Int = 0)

此解决方案不会在数据库中创建额外的列,最重要的是匹配所有 Task 的字段与 Room 的响应列。

【讨论】:

这太棒了,使用包装器可以完全分离出计算列。在我的情况下,我需要它们作为全文搜索的 matchinfo,但不想回到使用 db 游标,谢谢!【参考方案2】:

假设创建一个Task的子类

public class TaskDisplayModel extends Task

@Ignore
private transient int noOfSubTask;


那么你的查询将是

@Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
LiveData<List<TaskDisplayModel >> getTaskList();

【讨论】:

对我来说,这只有在我摆脱 @Ignore 注释时才有效。我认为只要TaskDisplayModel 没有作为要序列化的实体之一提供给您的数据库类,noOfSubTask 字段就不会添加到任何数据库表中。将@Ignore 关闭还可以从查询结果中反序列化,查询结果可以直接来自字段,也可以计算。我还发现 transient 关键字是不必要的,但也许它提供了一些我不知道的好处。 太棒了!不使用@Ignoretransient 也能完美运行。【参考方案3】:

您应该将@Ignore 字段移到构造函数之外,如下所示:

样本数据:

@Entity(primaryKeys = ["id"])
data class User(
    @SerializedName("id")
    val id: Int,

    @SerializedName("name")
    val name: String,

    @SerializedName("age")
    val age: Int
) 
   @Ignore
   val testme: String?

更多详情请参考github discussion

【讨论】:

【参考方案4】:

我正在使用 Kotlin,我遇到了类似的问题,下面是我的解决方法。

    添加附加字段带 ?(问号) 可空,不带 @Ignore 注释

    @Entity(tableName = "task")
    data class Task (
        val name: String,
        val parentId: Integer,
        val userId: Integer,
        val noOfSubTask: Integer?
    )
    

    为每个在 DAO 中选择 Task 的查询添加附加字段(在本例中为 noOfSubTask)。

    @Dao
    interface TaskDao 
        @Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
        fun getTaskList(): LiveData<List<Task>>
    
        @Query("SELECT *, NULL AS noOfSubTask FROM Task WHERE name = :name")
        fun getTask(name: String): LiveData<Task>
    
        ...
    
    

如果这不起作用,您可以尝试最近在 Google I/O 2018 中引入的 RawQuery。

【讨论】:

这将创建一个名为 noOfSubTask 的附加列,这不是最佳的 是的,我也知道这种解决方法不是最佳的,也不干净。但在那个时候,这是我唯一知道的方式。现在可能有更好的解决方案。 由于我也在使用Kotlin和数据类,所以给了回复,请看看它可能对您的项目有用。 好吧,干净和优化的代码总是正确的,但在某些情况下,将其提高到一定水平也有利于更健康的生活。编码愉快!

以上是关于如何填写房间库中实体的非列字段的主要内容,如果未能解决你的问题,请参考以下文章

为在 Sqlite 中具有 LONG 数据类型的字段的表创建房间实体

如何根据唯一值和另一个表单中的值自动填写表单中的字段

Android Studio:房间:错误:找不到字段的吸气剂

处理来自 JPA/DAO 实体的结果中的非 DB 映射字段

如何在房间持久性库中插入图像?

具有连接的实体和存储库中的教义可重用标准