在房间 android 的列上使用忽略

Using ignore on column in Room android

我的数据库 table 是

@Entity
internal data class ConversationEntity(
@PrimaryKey val conversationId: String,
val status: String,
val createdAt: String,
val modifiedAt: String,
val lastMessage: String? = null,
val feedbackType: ChatFeedbackType? = null
)

我想在 lastMessage 上使用 @Ignore,但出现以下错误。

@Entity
internal data class ConversationEntity(
@PrimaryKey val conversationId: String,
val status: String,
val createdAt: String,
val modifiedAt: String,
@Ignore
val lastMessage: String? = null,
val feedbackType: ChatFeedbackType? = null)

我得到的错误

Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).

这里有什么问题?

我的道是

  @Insert(onConflict = OnConflictStrategy.REPLACE)
  abstract suspend fun saveConversations(entities: List<ConversationEntity>)

我目前的数据库版本是6。我是否还需要编写迁移查询来添加忽略?

将这个class用于实体

class ConversationEntity (){

@PrimaryKey
val conversationId: String
val status: String
val createdAt: String
val modifiedAt: String
@Ignore
val lastMessage: String? = null
val feedbackType: ChatFeedbackType? = null

}

当使用 @Ignore 时,@Ignore 不包含在 table 中,因此 Room 需要一个可用于 inserting/extracting 行的构造函数,而不是完整的默认构造函数。

因此您需要添加一个不包含 lastMessage

的 suitable 构造函数

我相信,在解决构造函数问题后,您会遇到一个问题,因为 Conversation 不是 public。您可以通过删除 internal 关键字来解决此问题。

例如

@Entity
data class ConversationEntity(
    @PrimaryKey val conversationId: String,
    val status: String,
    val createdAt: String,
    val modifiedAt: String,
    @Ignore
    val lastMessage: String? = null,
    val feedbackType: ChatFeedbackType? = null) {
    constructor(
        conversationId: String,
        status: String,
        createdAt: String,
        modifiedAt: String,
        feedbackType: ChatFeedbackType):
            this(conversationId,status,createdAt,modifiedAt,null,feedbackType)
}
  • 这假设您有一个用于 ChatFeedbackType 的 TypeConverter

以上为例(feedbackType为了方便使用String)

还有道:-

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(entities: List<ConversationEntity>)

并使用:-

    val conversations = listOf<ConversationEntity>(
        ConversationEntity("Conv1","blah","2021-06-25 09:00:00","2021-06-25 10:00:00","NONE"),
        ConversationEntity("Conv2","blah","2021-06-25 09:00:00","2021-06-25 10:00:00","NONE"),
        ConversationEntity("Conv1","blah","2021-06-26 09:00:00","2021-06-26 10:00:00","NONE")
    )
    dao.insert(conversations)

那么 运行 之后的 ConversationEntity table 是:-

  • 即已添加两行并替换第一行。

然而

忽略 field/variable 使得 Room 永远不会如此有效地填充该值,这使得被忽略的字段在实体中编码时变得毫无用处。

例如,如果您想通过基于查询的计算来填充 lastMessage,举个例子:-

@Query("SELECT *, 'calculated data' AS lastMessage FROM conversationentity")
fun getConversations(): List<ConversationEntity>
  • 您可能认为会用值 calculated data 填充被忽略的 lastMessage field/variable(文字而不是表达式(可能是子查询))
    • 文字已用于 convenience/brevity
  • 但是 Room 会发出警告,例如warning: The query returns some columns [lastMessage] which are not used by .... 并且由于 room 的构造函数 used/selected 是在提取 ConversationEntity 时添加的不完整构造函数,因此计算出的值未放入 lastMessage field/variable 中(即使它可用)。

我建议,如果打算从数据库中填充被忽略的值,您将实体视为部分 class 并将 POJO 作为嵌入实体的完整 class .例如

ConversationEntity 作为 :-

@Entity
data class ConversationEntity(
    @PrimaryKey val conversationId: String,
    val status: String,
    val createdAt: String,
    val modifiedAt: String,
    val feedbackType: String? = null) {
}
    对于 demo/example,
  • String 而不是 ChatFeedbackType

然后有一个 POJO 例如

data class ConversationEntityPojo (
    @Embedded
    var conversationEntity: ConversationEntity,
    var lastMessage: String?
)
  • 因此,正如您所见,既不需要构造函数也不需要 @Ignore,而是更完整的 POJO。

从之前用于测试的代码开始,但现在使用修改后的实体和 POJO,然后使用以下 @Query 进行演示:-

@Query("SELECT * FROM conversationentity")
fun getConversationsEntityOnly(): List<ConversationEntity>
@Query("SELECT *, 'calculated data' AS lastMessage FROM conversationentity")
fun getConversationsEntityOnlyWithLastMessage(): List<ConversationEntity>
@Query("SELECT * FROM conversationentity")
fun getConversationsPOJO(): List<ConversationEntityPojo>
@Query("SELECT *,'calculated data' AS lastMessage FROM conversationentity")
fun getConversationPOJOWithLastMessage(): List<ConversationEntityPojo>

然后使用 :-

    .... code from  previous example
    dao.insert(conversations)

    for(c: ConversationEntity in dao.getConversationsEntityOnly()) {
        Log.d("CONVINFO",
            "Conversation is ${c.conversationId} " +
                    "status is ${c.status} " +
                    "created ${c.createdAt} " +
                    "modified ${c.modifiedAt} "
                     // CANT DO THIS AS ENTITY doesn't have lastMessage field "lastmessage ${c.lastMessage}"
            )
    }
    for (c: ConversationEntity in dao.getConversationsEntityOnlyWithLastMessage()) {
        Log.d("CONVINFO",
            "Conversation is ${c.conversationId} " +
                    "status is ${c.status} " +
                    "created ${c.createdAt} " +
                    "modified ${c.modifiedAt} "
            // CANT DO THIS AS ENTITY doesn't have lastMessage field "lastmessage ${c.lastMessage}"
        )
    }
    for(c: ConversationEntityPojo in dao.getConversationsPOJO()) {
        Log.d("CONVINFO",
            "Conversation is ${c.conversationEntity.conversationId} " +
                    "status is ${c.conversationEntity.status} " +
                    "created ${c.conversationEntity.createdAt} " +
                    "modified ${c.conversationEntity.modifiedAt} " +
                    "lastmessage ${c.lastMessage}") /* Will not be populated as lastMessage is not available in extracted data*/
    }
    for(c: ConversationEntityPojo in dao.getConversationPOJOWithLastMessage()) {
        Log.d("CONVINFO",
            "Conversation is ${c.conversationEntity.conversationId} " +
                    "status is ${c.conversationEntity.status} " +
                    "created ${c.conversationEntity.createdAt} " +
                    "modified ${c.conversationEntity.modifiedAt} " +
                    "lastmessage ${c.lastMessage}") /* can be used */
    }

那么结果就是:-

2021-06-27 12:26:38.919 D/CONVINFO: Conversation is Conv2 status is blah created 2021-06-25 09:00:00 modified 2021-06-25 10:00:00 
2021-06-27 12:26:38.919 D/CONVINFO: Conversation is Conv1 status is blah created 2021-06-26 09:00:00 modified 2021-06-26 10:00:00 


2021-06-27 12:26:38.920 D/CONVINFO: Conversation is Conv2 status is blah created 2021-06-25 09:00:00 modified 2021-06-25 10:00:00 
2021-06-27 12:26:38.920 D/CONVINFO: Conversation is Conv1 status is blah created 2021-06-26 09:00:00 modified 2021-06-26 10:00:00 


2021-06-27 12:26:38.924 D/CONVINFO: Conversation is Conv2 status is blah created 2021-06-25 09:00:00 modified 2021-06-25 10:00:00 lastmessage null
2021-06-27 12:26:38.924 D/CONVINFO: Conversation is Conv1 status is blah created 2021-06-26 09:00:00 modified 2021-06-26 10:00:00 lastmessage null


2021-06-27 12:26:38.926 D/CONVINFO: Conversation is Conv2 status is blah created 2021-06-25 09:00:00 modified 2021-06-25 10:00:00 lastmessage calculated data
2021-06-27 12:26:38.927 D/CONVINFO: Conversation is Conv1 status is blah created 2021-06-26 09:00:00 modified 2021-06-26 10:00:00 lastmessage calculated data