带有@OneToMany的JPA EmbeddedId-无法通过JOIN进行查询工作

时间:2019-03-19 10:14:04

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

我们正在构建约会计划程序。我们有很多客人,每个客人都可以访问许多事件:实体“来宾”和“事件”。中间实体很多,称为“ EventGuestRelation”。它具有@EmbeddedId和两个Integer外键列,该列可以很好地运行,并且内置JPArepository方法的行为正常。

问题是当我查询EventGuestRelation的存储库时。 我无法让程序返回包含特定事件或特定来宾的EventGuestRelations。仅为零。为了简洁起见,我在这里显示有关事件的查询。

我尝试过

@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。 一些吉祥物只是拒绝变得晦涩难懂。

2 个答案:

答案 0 :(得分:0)

我从未与@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);

答案 1 :(得分:0)

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

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

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