Spring数据JPA,hql查询在select请求中加入@ManyToMany关系

时间:2018-04-03 13:44:03

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

收入明细:

帐户

@Entity
@Table(name = "account_table")
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "account_seq_gen")
    @SequenceGenerator(name = "account_seq_gen", sequenceName = "ACCOUNT_SEQ")
    private Long id;
    @ManyToMany(cascade = CascadeType.REMOVE)
    @JoinTable(name = "account_calendar_relation",
            joinColumns = @JoinColumn(name = "account_id"),
            inverseJoinColumns = @JoinColumn(name = "calendar_id")
    )
    private List<Calendar> calendars = new ArrayList<>();

    @ManyToOne
    @JoinColumn(columnDefinition = "user_id")
    private User user;

//...
}

日历

相关
@Entity
@Table(name = "calendar")
public class Calendar {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "calendar_seq_gen")
    @SequenceGenerator(name = "calendar_seq_gen", sequenceName = "CALENDAR_SEQ")
    private Long id;
    @ManyToMany(mappedBy = "calendars")
    private List<Account> accounts;
//...
}

manyToMany

我需要通过 userId userId 是帐户字段)使用Spring数据JPA存储库从DB加载轻型日历集合的实现请求。

我试过了:

@Query(value = "SELECT new com.nextiva.calendar.model.CalendarsCoreInfo(c.id, c.email, c.originalCalendar.id," +
        " c.readOnly, c.deleted)" +
        " FROM Calendar c " +
        " JOIN Account a ON c.accounts IN (a)" +
        " WHERE a.user.id = :userId")
Set<CalendarsCoreInfo> findCalendarsCoreInfoByUserId(@Param("userId") Long usedId);

但是应用程序没有以异常开始:

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.Set com.nextiva.calendar.dao.jpa.CalendarRepository.findCalendarsCoreInfoByUserId(java.lang.Long)!

我尝试应用原生查询:

@Query(value = "SELECT new com.nextiva.calendar.model.CalendarsCoreInfo(c.id, c.email, c.originalCalendar.id," +
        " c.readOnly, c.deleted)" +
        " FROM {h-schema}.calendar c" +
        " JOIN {h-schema}.account_calendar_relation atr ON atr.calendar_id = c.id" +
        " JOIN {h-schema}.account_table account ON account.id = atr.account_id" +
        " WHERE account.user_id = :userId", nativeQuery = true)
Set<CalendarsCoreInfo> findCalendarsCoreInfoByUserId(@Param("userId") Long usedId);

但是原生查询不支持自定义结果(在我的情况下是 CalendarsCoreInfo )。

问题

据我所知,我可以使用 jdbcTemplate 或用 OneToMany ManyToOne 替换 ManyToMany 实体映射来解决此问题。但我希望有人知道当前结构修复 HQL 的优雅解决方案。

1 个答案:

答案 0 :(得分:1)

我的查询部分:

@NamedNativeQueries( {
        @NamedNativeQuery(name = "findCalendarsCoreInfoById",
                query = "SELECT c.id, c.email, c.original_id, c.read_only, c.deleted" +
                        " FROM {h-schema}calendar c" +
                        " JOIN {h-schema}account_calendar_relation atr ON atr.calendar_id = c.id" +
                        " JOIN {h-schema}account_table a ON a.id = atr.account_id" +
                        " WHERE a.user_id = ? ",
                resultSetMapping = "calendarsCoreInfoMapping"
        ),
})

使用对应的映射器到查询的目标对象:

@SqlResultSetMappings( {
        @SqlResultSetMapping(
                name = "calendarsCoreInfoMapping",
                classes = {
                        @ConstructorResult(
                                targetClass = CalendarsCoreInfo.class,
                                columns = {
                                        @ColumnResult(name = "id", type = Long.class),
                                        @ColumnResult(name = "email", type = String.class),
                                        @ColumnResult(name = "original_id", type = String.class),
                                        @ColumnResult(name = "read_only"),
                                        @ColumnResult(name = "deleted")
                                }
                        )
                }
        ),
})

我已将它们放到 Calendar 实体(由于不同JPA供应商的不同行为,因此会提出一些建议)。

为了使我的存储库正常工作,我声明 Query 指定准备好的查询:

@Query(name = "findCalendarsCoreInfoById", nativeQuery = true)
Set<CalendarsCoreInfo> findCalendarsCoreInfoByUserId(Long userId);

请关注 @Query 。如果方法名称与查询名称相同并且标记为 nativeQuery = true ,那么在查询上映射方法是不够的(这种方式对我来说没有用)。如果我将 name =“findCalendarsCoreInfoById”添加到 @Query 中,则会修复此问题。