【问题标题】: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 提供的答案对您有用吗?它似乎对我不起作用......

标签: java android sqlite android-room android-architecture-components


【解决方案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,我遇到了类似的问题,下面是我的解决方法。

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

      @Entity(tableName = "task")
      data class Task (
          val name: String,
          val parentId: Integer,
          val userId: Integer,
          val noOfSubTask: Integer?
      )
      
    2. 为每个在 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和数据类,所以给了回复,请看看它可能对您的项目有用。
    • 好吧,干净和优化的代码总是正确的,但在某些情况下,将其提高到一定水平也有利于更健康的生活。编码愉快!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多