英文:
The columns returned by the query do not have the fields even though they are there
问题
以下是DAO方法的翻译:
@Query("SELECT * FROM ChatEntity c JOIN ChatMessageEntity m ON c.id = m.chatId JOIN ChatParticipantEntity p ON p.id = c.ownerId WHERE c.id IN (SELECT id FROM ChatEntity LIMIT :limit OFFSET :offset) ORDER BY m.createdAt DESC")
fun getChats(limit: Int, offset: Int): Flow<List<ChatWithParticipantsAndLastMessage>>
其中ChatWithParticipantsAndLastMessage
是:
data class ChatWithParticipantsAndLastMessage(
@Embedded
val chatEntity: ChatEntity,
@Embedded(prefix = "last_message_")
val lastMessage: ChatMessageEntity,
@Embedded(prefix = "owner_")
val owner: ChatParticipantEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val participants: List<ChatParticipantEntity>
)
对应的@Embedded
对象是:
data class ChatEntity(
@PrimaryKey val id: Int,
val type: String,
val createdAt: Int,
val ownerId: Int,
val participantsCount: Int,
val participantsLimit: Int,
val unreadCount: Int,
val lastMessageId: Int?
)
data class ChatMessageEntity(
val chatId: Int,
val localMessageId: Int,
val createdAt: Int,
val senderId: Int,
val isEdited: Boolean,
val isViewed: Boolean,
val text: String,
val type: String
)
data class ChatParticipantEntity(
@PrimaryKey val id: Int,
val chatId: Int,
val avatarUrl: String?,
val firstName: String,
val lastName: String?,
val lastOnline: Int,
val isOnline: Boolean,
val username: String
)
它们当然都带有@Entity
注解。但是构建失败并显示以下错误信息:
查询返回的列在
ChatWithParticipantsAndLastMessage
中没有字段[chatId,localMessageId,createdAt,senderId,isEdited,isViewed,text,type,id,chatId,firstName,lastOnline,isOnline,username],尽管它们被注解为非空或基本类型。
查询返回的列:[id,type,createdAt,ownerId,participantsCount,participantsLimit,unreadCount,lastMessageId,chatId,localMessageId,createdAt,senderId,isEdited,isViewed,text,type,id,chatId,avatarUrl,firstName,lastName,lastOnline,isOnline,username]
但是,Room认为缺少的所有必需字段实际上都存在。出现了什么问题?
英文:
Having the following DAO method:
@Query("""
SELECT * FROM ChatEntity c
JOIN ChatMessageEntity m ON c.id = m.chatId
JOIN ChatParticipantEntity p ON p.id = c.ownerId
WHERE c.id IN (
SELECT id FROM ChatEntity
LIMIT :limit OFFSET :offset
)
ORDER BY m.createdAt DESC
""")
fun getChats(
limit: Int,
offset: Int
): Flow<List<ChatWithParticipantsAndLastMessage>>
Where ChatWithParticipantsAndLastMessage
is:
data class ChatWithParticipantsAndLastMessage(
@Embedded
val chatEntity: ChatEntity,
@Embedded(prefix = "last_message_")
val lastMessage: ChatMessageEntity,
@Embedded(prefix = "owner_")
val owner: ChatParticipantEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val participants: List<ChatParticipantEntity>
)
And corresponding @Embedded
objects are:
data class ChatEntity(
@PrimaryKey val id: Int,
val type: String,
val createdAt: Int,
val ownerId: Int,
val participantsCount: Int,
val participantsLimit: Int,
val unreadCount: Int,
val lastMessageId: Int?
)
data class ChatMessageEntity(
val chatId: Int,
val localMessageId: Int,
val createdAt: Int,
val senderId: Int,
val isEdited: Boolean,
val isViewed: Boolean,
val text: String,
val type: String
)
data class ChatParticipantEntity(
@PrimaryKey val id: Int,
val chatId: Int,
val avatarUrl: String?,
val firstName: String,
val lastName: String?,
val lastOnline: Int,
val isOnline: Boolean,
val username: String
)
All of them are, of course, annotated with @Entity
. But build fails with error:
>The columns returned by the query does not have the fields [chatId,localMessageId,createdAt,senderId,isEdited,isViewed,text,type,id,chatId,firstName,lastOnline,isOnline,username] in ChatWithParticipantsAndLastMessage even though they are annotated as non-null or primitive.
>Columns returned by the query: [id,type,createdAt,ownerId,participantsCount,participantsLimit,unreadCount,lastMessageId,chatId,localMessageId,createdAt,senderId,isEdited,isViewed,text,type,id,chatId,avatarUrl,firstName,lastName,lastOnline,isOnline,username]
But all required fields that Room considers missing are literally there. What gives?
答案1
得分: 0
让我们给Room提供一个查询管理器,使查询变得简单,就像"SELECT * FROM ChatEntity"一样。
我无法重现这个案例,但是下面的代码可以编译通过。
@Entity
data class ChatEntity(
@PrimaryKey val id: Int,
val type: String,
val createdAt: Int,
val ownerId: Int,
val participantsCount: Int,
val participantsLimit: Int,
val unreadCount: Int,
val lastMessageId: Int?
)
@Entity(primaryKeys = ["chatId", "localMessageId", "senderId"])
data class ChatMessageEntity(
val chatId: Int,
val localMessageId: Int,
val createdAt: Int,
val senderId: Int,
val isEdited: Boolean,
val isViewed: Boolean,
val text: String,
val type: String
)
@Entity
data class ChatParticipantEntity(
@PrimaryKey val id: Int,
val chatId: Int,
val avatarUrl: String?,
val firstName: String,
val lastName: String?,
val lastOnline: Int,
val isOnline: Boolean,
val username: String
)
data class ChatWithParticipantsAndLastMessage(
@Embedded
val chatEntity: ChatEntity,
@Relation(
entity = ChatMessageEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val lastMessage: ChatMessageEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "ownerId",
entityColumn = "id"
)
val owner: ChatParticipantEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val participants: List<ChatParticipantEntity>
)
@androidx.room.Dao
interface ChatDao {
@Transaction
@Query("SELECT * FROM ChatEntity")
fun getChats(): Flow<List<ChatWithParticipantsAndLastMessage>>
}
以上是翻译好的内容。
英文:
Let give a QUERY management to Room - make a Query as simple as SELECT * FROM ChatEntity =>
I can't reproduce the case - but this one below compiles.
@Entity
data class ChatEntity(
@PrimaryKey val id: Int,
val type: String,
val createdAt: Int,
val ownerId: Int,
val participantsCount: Int,
val participantsLimit: Int,
val unreadCount: Int,
val lastMessageId: Int?
)
@Entity(primaryKeys = ["chatId", "localMessageId", "senderId"]) /*can't catch your PrimaryKeys*/
data class ChatMessageEntity(
val chatId: Int,
val localMessageId: Int,
val createdAt: Int,
val senderId: Int,
val isEdited: Boolean,
val isViewed: Boolean,
val text: String,
val type: String
)
@Entity
data class ChatParticipantEntity(
@PrimaryKey val id: Int,
val chatId: Int,
val avatarUrl: String?,
val firstName: String,
val lastName: String?,
val lastOnline: Int,
val isOnline: Boolean,
val username: String
)
data class ChatWithParticipantsAndLastMessage(
@Embedded
val chatEntity: ChatEntity,
@Relation(
entity = ChatMessageEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val lastMessage: ChatMessageEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "ownerId",
entityColumn = "id"
)
val owner: ChatParticipantEntity,
@Relation(
entity = ChatParticipantEntity::class,
parentColumn = "id",
entityColumn = "chatId"
)
val participants: List<ChatParticipantEntity>
)
@androidx.room.Dao
interface ChatDao {
@Transaction
@Query("SELECT * FROM ChatEntity")
fun getChats(
): Flow<List<ChatWithParticipantsAndLastMessage>>
}
答案2
得分: 0
重复的列名是问题的原因。例如,Room无法确定它所看到的chatId
是来自ChatMessageEntity
还是ChatParticipantEntity
。在不更改列名的情况下,解决方案是在查询中使用别名:
// omfg
@Query(
"""
SELECT c.id, c.type, c.createdAt, c.ownerId, c.participantsCount, c.participantsLimit, c.unreadCount,
m.chatId AS last_message_chatId, m.localMessageId AS last_message_localMessageId, m.createdAt AS last_message_createdAt,
m.senderId AS last_message_senderId, m.isEdited AS last_message_isEdited, m.isViewed AS last_message_isViewed,
m.text AS last_message_text, m.type AS last_message_type,
o.id AS owner_id, o.chatId AS owner_chatId, o.avatarUrl AS owner_avatarUrl, o.firstName AS owner_firstName,
o.lastName AS owner_lastName, o.lastOnline AS owner_lastOnline
FROM ChatEntity c
JOIN ChatMessageEntity m ON c.id = m.chatId
JOIN ChatParticipantEntity o ON o.id = c.ownerId
WHERE c.id IN (
SELECT id FROM ChatEntity
LIMIT :limit OFFSET :offset
)
ORDER BY m.createdAt DESC
"""
)
fun getChats(
limit: Int,
offset: Int
): Flow<List<ChatWithParticipantsAndLastMessage>>
这样做很丑陋且容易出错,但我想我们只能接受现实。
英文:
Duplicate column names turned out to be the problem. Room simply doesn't know, for example, which chatId
it is seeing: from ChatMessageEntity
or form ChatParticipantEntity
. Without touching column names themselves, the solution is to use aliases in my query:
// omfg
@Query(
"""
SELECT c.id, c.type, c.createdAt, c.ownerId, c.participantsCount, c.participantsLimit, c.unreadCount,
m.chatId AS last_message_chatId, m.localMessageId AS last_message_localMessageId, m.createdAt AS last_message_createdAt,
m.senderId AS last_message_senderId, m.isEdited AS last_message_isEdited, m.isViewed AS last_message_isViewed,
m.text AS last_message_text, m.type AS last_message_type,
o.id AS owner_id, o.chatId AS owner_chatId, o.avatarUrl AS owner_avatarUrl, o.firstName AS owner_firstName,
o.lastName AS owner_lastName, o.lastOnline AS owner_lastOnline
FROM ChatEntity c
JOIN ChatMessageEntity m ON c.id = m.chatId
JOIN ChatParticipantEntity o ON o.id = c.ownerId
WHERE c.id IN (
SELECT id FROM ChatEntity
LIMIT :limit OFFSET :offset
)
ORDER BY m.createdAt DESC
"""
)
fun getChats(
limit: Int,
offset: Int
): Flow<List<ChatWithParticipantsAndLastMessage>>
This is sooo ugly and error-prone, but we take what we get, I guess.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论