提问人:Naman 提问时间:11/14/2023 更新时间:11/14/2023 访问量:31
使用 IN 运算符查询具有联接列的持久性实体
Query persistence Entity with join column using IN operator
问:
我有一个实体,例如 follow,它与另一个名为 story_id.Story
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "user_story_mapping")
public class UserStoryMapping {
@ManyToOne
@JoinColumn(name = "story_id")
private Story story; // this attribute
@Column(name = "user_id")
private String userId;
@Column(name = "seen_at")
private Date seenAt;
@Transient
private String storyId;
}
我尝试执行的是查询此表,例如
select usm.story_id as storyId from user_story_mapping usm where usm.user_id='Naman' and usm.story_id IN ("8a9f90858871dc9f018abc3fc3dc4e86","ffhy8a9f9abc3fc3dc4e09") and usm.status = 1;
为了在 的帮助下实现这一点,我引用了以下查询常量:javax.persistence.EntityManager#createQuery
public static final String GET_ACTIVE_USER_STORY_MAPPINGS = """
from UserStoryMapping usm \
where ((usm.userId = :userId) and (usm.story IN :storyIds) and (usm.status = 1))
""";
在执行时,这会导致以下异常
…nested exception is java.lang.IllegalArgumentException:
Parameter value element [8a9f90858871dc9f018abc3fc3dc4e86] did not match expected type [entity.core.Story (n/a)]"
如果我将查询更改为
public static final String GET_ACTIVE_USER_STORY_MAPPINGS = """
select usm.story_id as storyId \
from UserStoryMapping usm \
where ((usm.userId = :userId) and (usm.story_id IN :storyIds) and (usm.status = 1))
""";
然后我被卡住了
org.hibernate.QueryException: could not resolve property: story_id of: entity.core.UserStoryMapping [select usm.story_id as storyId\nfrom entity.core.UserStoryMapping usm where ((usm.userId = :userId) and (usm.story_id IN :storyIds) and (usm.status = 1))\n];
答:
错误消息指出了问题:UserStoryMapping.story 映射是指向 Story 的实例,因此 JPA 要求您为使用此映射的查询操作传入 Story 实例,但您却直接传入 ID 值。如果要使用 ID,则需要改用 form 的查询表达式:,以便查询将 ID 值与 Story.Id 列匹配。不过,许多提供程序将执行对 Story 的联接,因为通过使用 usm.story,规范需要对结果进行内部联接功能。"(usm.story.id in :storyIds)"
某些提供程序可能允许将 Story 实例直接传递到查询。对于他们,您可以使用 .这取决于提供程序和映射类型;他们可能会通过从您传入的故事实例中提取 ID 来将其转换为,或者他们可能仅使用该值来引用 usm 中的 FK。"(usm.story IN :storyInstances)"
"(usm.story.id in :storyIds)"
如果要避免连接,并且不依赖于 JPA 提供程序行为或映射细节,那么还可以将外键作为基本映射直接映射到实体中。
@Entity
@Table(name = "user_story_mapping")
public class UserStoryMapping {
@ManyToOne
@JoinColumn(name = "story_id")
private Story story; //this controls the FK, and must always be set
@Column(name = "story_id", insertable=false, updatable=false)
private String storyId;
..
}
然后,当从数据库中读取 UserStoryMapping 实例时,将在实体中设置 storyId,但该值不会用于控制“story_id”外键列 - 该列仍仅由故事 ManyToOne 属性控制。这将允许您在查询中使用 story 属性来访问联接,或者在想要使用不带联接的值时将 storyId 属性用作任何基本映射,从而允许以下形式的表达式:
(usm.storyId IN :storyIds)
评论
usm.story.id