【问题标题】:JPA EmbeddedId with @OneToMany - can't make query with JOIN to work带有@OneToMany 的 JPA EmbeddedId - 无法使用 JOIN 进行查询
【发布时间】:2019-08-09 19:55:44
【问题描述】:

我们正在构建一个约会计划程序。我们有很多客人,每个客人都可以访问许多事件:实体“Guest”和“Event”。这是一个多对多的中间实体,称为“EventGuestRelation”。它具有带有两个整数外键列的@EmbeddedId,可以正常保存,并且内置的 JPArepository 方法运行正常。

问题是当我查询 EventGuestRelation 的存储库时。 我无法让程序返回包含特定事件或特定访客的 EventGuestRelations。 只是零。为简洁起见,我在此处显示有关 Event 的查询。

我试过了

@Query("SELECT r.event FROM EventGuestRelation r WHERE r.event= :event")    
public List<EventEntity> getEventIdsForEvent(@Param(value = "event") EventEntity event); 

public List<EventGuestRelation> findByEvent(EventEntity event);

两者都产生 SQL:

Hibernate: 
    select
        evententit1_.id as id1_3_,
    ...
    from
        user_event_guest eventguest0_ 
    inner join
        eventlist evententit1_ 
            on eventguest0_.event_sub=evententit1_.id 
    where
        eventguest0_.event_sub=?

正确的实体:

@Entity
@Table
public class EventEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    ...

    @OneToMany(mappedBy = "event" , cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) 
    @JsonBackReference 
    private Set<EventGuestRelation> subscriptions = new HashSet<>();
    ...

中间实体:

@Entity
@Table
public class EventGuestRelation {

    @Embeddable
    public static class EventGuestId implements Serializable {

        @Column(name = "EVENT_ID")
        protected Integer eventId;
        ... 
    }

    @EmbeddedId
    protected EventGuestId id = new EventGuestId();

    @ManyToOne 
    @JoinColumn(name = "event_sub", insertable = false, updatable = false)
    private EventEntity event;
    ...

省略了左侧实体(来宾)。

存储库:

public interface EventGuestRepository extends JpaRepository<EventGuestRelation, EventGuestId> {

及部分测试方法:

private final UserEntity ALYSSA = new UserEntity();
private final EventEntity GUESTING = new EventEntity();
private final EventGuestRelation AGUESTING = new EventGuestRelation();
userRepo.save(ALYSSA); // cascades to intemediate entity, checked;
AGUESTING.subscribe(ALYSSA, GUESTING); //bidirectional relation setter

List<EventEntity> eventsII = eventGuestRepo.getEventIdsForEvent(GUESTING);
        assertEquals(eventsII.size(), 1); // fails

我可以通过这种次优方式解决问题:

   Set<EventGuestRelation> subscriptions = ALYSSA.getSubscriptions();
   Set<EventEntity> events = subscriptions.stream().map(s -> s.getEvent()).collect(Collectors.toSet())

但显然这不如直接查询数据库那么优雅。

任何帮助将不胜感激。 附言和 SICP 的 Alyssa 一样。 一些吉祥物只是拒绝默默无闻。

【问题讨论】:

  • 您的数据库中有event_guest_relation 表吗?
  • 是的,当然。我的行动计划是用模拟数据填充数据库并手动编写所需的查询;然后检查 JPA 生成的查询是否不同。
  • 我通过从中间实体的 OneToMany 映射中删除 insertableupdatable 使查询 @Query("SELECT r.userGuest FROM EventGuestRelation r WHERE r.event = :event") public List&lt;UserEntity&gt; getGuestsForEvent (@Param(value = "event") EventEntity event); 起作用。现在我要介绍什么样的问题?

标签: spring-data-jpa many-to-many jpql


【解决方案1】:

连接列的名称必须与嵌入主键中列的对应名称相同。我错过了。因此,我的中间实体在数据库中有 4 列而不是 2。这导致查询返回空值。 在我使名称相等后,查询就起作用了。

已更正的中间实体在嵌入键中具有: @Column(name = "GUEST_ID") protected Integer userGuestId;

在连接列中: @ManyToOne @JoinColumn(name = "GUEST_ID", insertable = false, updatable = false) private UserEntity guest;

【讨论】:

    【解决方案2】:

    我从未与@Embeddable 实体合作过。也许,您可以使用Spring-Data docs 这篇文章中的一些有用的东西,但作为备用计划,我认为您始终可以使用原生 SQL 重写您的查询。

    @Query(value = "SELECT e FROM event_guest_relation AS egr JOIN event AS e ON egr.event_id = e.id WHERE egr.event_id = :eventId", nativeQuery = true)
    public List<EventEntity> getEventIdsForEvent(@Param(value = "eventId") Integer eventId);
    

    @Query(value = "SELECT egr FROM event AS e JOIN event_guest_relation AS egr ON egr.event_id = e.id WHERE e.id = :eventId", nativeQuery = true)
    public List<EventGuestRelation> findByEvent(@Param(value = "eventId") Integer eventId);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 2018-07-20
      相关资源
      最近更新 更多