【问题标题】:JPQL: Validation fails for Query with JoinJPQL:使用加入的查询验证失败
【发布时间】:2020-12-03 03:54:07
【问题描述】:

我正在努力让查询在 JPQL 中工作。

我有以下实体(精简):

对话
一个对话有很多消息。
一个对话有多个用户对话。

@Entity
@Table(name = "conversations")
data class Conversation(
    @Column(nullable = false)
    var createdAt: LocalDateTime = LocalDateTime.now(),

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: IDType = 0
) {
    @OneToMany(mappedBy = "conversation")
    lateinit var messages: MutableSet<Message>

    @OneToMany(mappedBy = "conversation")
    lateinit var userConversation: MutableSet<UserConversation>
}

留言
许多消息都有一个对话。

@Entity
@Table(name = "messages")
data class Message(
    @Column(nullable = false)
    var createdAt: LocalDateTime = LocalDateTime.now(),

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: IDType = 0
) {
    @ManyToOne(cascade = [CascadeType.MERGE], optional = false)
    @JoinColumn(name = "conversation_id", nullable = false)
    lateinit var conversation: Conversation
}

用户对话
许多 UserConversation 有一个 Conversation。

@Entity
@Table(name = "user_conversations")
data class UserConversation(
    @Column(nullable = false)
    var createdAt: LocalDateTime = LocalDateTime.now(),

    @Column(nullable = false)
    var allowHistory: Boolean = true,

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: IDType = 0
) {
    @ManyToOne(cascade = [CascadeType.MERGE], optional = false)
    @JoinColumn(name = "conversation_id", nullable = false)
    lateinit var conversation: Conversation
}

为了帮助您了解这些实体:想想频道或群聊。
对话就是这样一个群体。
一条消息被发布到该组。
UserConversation 描述了用户与此类组之间的关系。

我要实现的场景:
如果用户不允许查看对话历史记录,则只应显示他加入后的消息。

本机解决方案如下所示:

SELECT     messages.*, user_conversations.*
FROM       messages

INNER JOIN user_conversations
        ON messages.conversation_id = user_conversations.conversation_id

WHERE      user_conversations.id IN (42) # I might want to fetch multiple userConversations at once
AND        messages.created_at >= IF(user_conversations.allow_history, messages.created_at, user_conversations.created_at)

我想将它放在 JPA 存储库中。
因为我首先要获取消息,所以我想把它放到我的 MessageRepository 中(这不是必须的)。

稍后我需要能够将 userConversations 链接到他们的消息,因此我尝试引入自定义结果:

// query here
fun findAllByUserConversationIdIn(userConversationIds: Collection<IDType>): Collection<UserConversationMessage>

interface UserConversationMessage {
    val message: Message
    val userConversation: UserConversation
}

这是我想出的 JPQL:

SELECT
    m as message,
    uc as userConversation
FROM
    Message m
INNER JOIN UserConversation uc
    ON uc.conversation.id = m.conversation.id
WHERE uc.id IN (?1)
AND m.createdAt >= CASE WHEN uc.allowHistory THEN m.createdAt ELSE uc.createdAt END

但验证失败。

你能帮帮我吗?

干杯

【问题讨论】:

  • 有什么例外?
  • @Andronicus ``` 原因:java.lang.IllegalArgumentException:查询方法公共抽象 java.util.Collection fin.message.datasource.MessageRepository.findAllByUserConversationIdIn(java.util.Collection) 的验证失败)!在 org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:93) ~[spring-data-jpa-2.2.5.RELEASE.jar:2.2.5.RELEASE] 在 org.springframework。 data.jpa.repository.query.SimpleJpaQuery.(SimpleJpaQuery.java:63) ~[spring-data-jpa-2.2.5.RELEASE.jar:2.2.5.RELEASE] at (...) `` `

标签: hibernate kotlin spring-data-jpa spring-data


【解决方案1】:

这很容易。 我的 JPQL 实际上并没有那么糟糕。 错误就在这里:

AND m.createdAt >= CASE WHEN uc.allowHistory THEN m.createdAt ELSE uc.createdAt END

应该是

AND m.createdAt >= CASE WHEN uc.allowHistory = 1 THEN m.createdAt ELSE uc.createdAt END

我很惊讶这个查询实际上返回了我想要的。

【讨论】:

    猜你喜欢
    • 2017-11-22
    • 2018-02-23
    • 2018-06-26
    • 2011-09-17
    • 2014-02-11
    • 2014-07-11
    • 2021-04-12
    • 1970-01-01
    • 2018-09-23
    相关资源
    最近更新 更多