【问题标题】:Clause 'where' with nested join not working using hql query带有嵌套连接的子句“where”无法使用 hql 查询
【发布时间】:2021-06-16 21:40:50
【问题描述】:

我有 3 个实体:

@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "event")
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Event {

    @Id
    @GeneratedValue
    @Column(name = "id")
    UUID id;

    @Column(name = "name", nullable = false, unique = true)
    String name;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "event_id")
    Set<Session> sessions;
}
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "session")
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Session {
    @Id
    @GeneratedValue
    @Column(name = "id")
    UUID id;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "session_id")
    Set<SessionHistory> sessionHistory;
}
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "session_history")
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SessionHistory {

    @Id
    @GeneratedValue
    @Column(name = "id")
    UUID id;

    @Column(name = "status", nullable = false)
    @Enumerated(EnumType.STRING)
    Status status;

}

事件存储库:

@Repository
public interface EventRepo extends JpaRepository<Event, UUID> {
    Optional<Event> findByExternalId(Long externalId);

    @Query("SELECT e FROM Event e " +
            "JOIN e.sessions s " +
            "JOIN s.sessionHistory sh WHERE sh.status = 'SALE'")
    List<Event> findAllBy();
}

所以我想获取只有 SALE 状态的会话历史记录。测试:

        SessionHistory sessionHistory1 = SessionHistory.builder()
                .status(Status.SOON)
                .build();

        SessionHistory sessionHistory2 = SessionHistory.builder()
                .status(Status.SALE)
                .build();

        Session session = Session.builder()
                .sessionHistory(Sets.newSet(sessionHistory1, sessionHistory2))
                .build();

        Event event = Event.builder()
                .name("SOMENAME")
                .sessions(Collections.singleton(session))

        eventRepo.save(event);

        Optional<Event> event = eventRepo.findAllBy().stream().findAny();

        assertEquals(1, eventByExternalId.get().getSessions()
                            .stream().findAny().get().getSessionHistory().size());


选择查询:

    ...
    from
        event event0_ 
    inner join
        session sessions1_ 
            on event0_.id=sessions1_.event_id 
    inner join
        session_history sessionhis2_ 
            on sessions1_.id=sessionhis2_.session_id 
    where
        sessionhis2_.status='SALE'

但测试失败并输出:

org.opentest4j.AssertionFailedError: 
Expected :1
Actual   :2

有什么问题?如果我们尝试在查询中对 Session 或 Event 使用“where”,它就可以正常工作。也尝试过加入 fetch。我没有找到 OneToMany 关联的解决方案。甚至可能吗?我不想编写本机查询。如果您对这个问题有一些复杂的方法,那就没问题了(比如 EntityGraph)

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa hql


    【解决方案1】:

    您的加入只是“随机加入”,不会影响会话历史关联的内容。如果您只想获取它,但我不建议这样做(请点击链接了解更多说明),您可以使用以下查询:

    @Query("SELECT e FROM Event e " +
            "JOIN FETCH e.sessions s " +
            "JOIN FETCH s.sessionHistory sh WHERE sh.status = 'SALE'")
    List<Event> findAllBy();
    

    有关更详细的答案和基于 DTO 的替代解决方案,请查看以下答案:Return ResultSet with intact joins in Hibernate / JPA

    【讨论】:

      【解决方案2】:

      由于连接,您获得了两次相同的实体。

      添加不同的

       @Query("SELECT distinct e FROM Event e " +
              "JOIN e.sessions s " +
              "JOIN s.sessionHistory sh WHERE sh.status = 'SALE'")
      List<Event> findAllBy();
      

      【讨论】:

      • 不幸的是,没有。我得到不同的实体
      猜你喜欢
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-12
      相关资源
      最近更新 更多