Spring Boot JPA:加入

时间:2018-01-11 19:36:59

标签: hibernate jpa spring-boot spring-data

请注意:不是this one的欺骗......我得到了相同的例外,但原因不同!

JPA / Hibernate,由Groovy编写的Spring Boot应用程序使用(Groovy应该不重要;只需提及它就可以了。)我有以下3个实体:

@Entity(name = 'accounts')
class Account {
    @Id
    @Column(name='account_id')
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id

    @Column(name='account_ref_id')
    String refId

    @Column(name = 'account_email')
    @NotEmpty
    String email

    @Column(name = 'account_username')
    String username
}

@Entity(name = 'security_token_types')
class SecurityTokenType {
  @Id
  @Column(name='security_token_type_id')
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  Long id

  @Column(name='security_token_type_ref_id')
  String refId

  @Column(name='security_token_type_name')
  String name

  @Column(name='security_token_type_label')
  String label

  @Column(name='security_token_type_description')
  String description
}

@Entity(name = 'security_tokens')
class SecurityToken {
    @Id
    @Column(name='security_token_id')
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id

    @Column(name='security_token_ref_id')
    String refId

    @OneToOne(fetch = FetchType.EAGER, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
    @JoinColumn(name = 'account_id', referencedColumnName = 'account_id')
    Account account

    @Column(name = 'security_token')
    String token

    @OneToOne(fetch = FetchType.EAGER, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
    @JoinColumn(name = 'security_token_type_id', referencedColumnName = 'security_token_type_id')
    SecurityTokenType type

    @Column(name = 'security_token_generated_on')
    Date generatedOn
}

SecurityPersistor(DAO)存储库:

interface SecurityTokenPersistor extends CrudRepository<SecurityToken, Long> {
    @Query("FROM security_tokens st INNER JOIN security_token_types stt ON st.security_token_type_id = stt.security_token_type_id WHERE stt.security_token_type_label = :type AND st.account_id = :accountId")
    Set<SecurityToken> findTokensByAccountAndType(@Param('accountId') Long accountId, @Param('type') String type)
}

在运行时我得到了这些:

Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join! [FROM com.armbet.ws.domain.entities.SecurityToken st INNER JOIN security_token_types stt ON st.security_token_type_id = stt.security_token_type_id WHERE stt.security_token_type_label = :type AND st.account_id = :accountId]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74)
    at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:91)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:268)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76)

我觉得SecurityPersistor#findTokensByAccountAndType方法中的JOIN语法错误。我有什么想法会出错吗?

2 个答案:

答案 0 :(得分:1)

如果您有toOne映射关系,则不需要加入。

此查询应该有效:

@Query("FROM security_tokens st WHERE st.type.label = :type AND st.account.id = :accountId")

您应该阅读有关JPQL的信息。一个很好的来源是Hibernate文档:

http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql

答案 1 :(得分:1)

另外,如果要指向具有不同名称的表然后使用实体,请不要更改实体名称:

@Entity
@Table(name = "security_tokens")
class SecurityToken {
}

而不是

@Entity(name = 'security_tokens')
class SecurityToken {
}

然后查询:

@Query("FROM SecurityToken st where st.type.label = :type AND st.account.id = :accountId")