JPA和Hibernate缺少INNER JOIN ON子句

时间:2018-08-15 19:34:48

标签: java hibernate jpa

我正在尝试弄清JPA / Hibernate在做什么。

我有一个包含两个表的数据库:banner和bannerlinks。

 banner
 +-------------------------------------------+
 | id | logo | studyId | textColor | bgColor |
 +-------------------------------------------+
 |  1 | xx   |  17     |  green    | red     |
 +-------------------------------------------+

 bannerlink
 +----------------------------------------+
 | id | bannerId| label | text | image    |
 +----------------------------------------+
 |  1 | 1       |  About| Abt..| xxx      |
 +----------------------------------------+
 |  2 | 1       |  Beta | Bet..| xxx      |
 +----------------------------------------+
 |  2 | 1       |  Cont | Ctc..| xxx      |
 +----------------------------------------+

以及每个实体的类

@Entity
@Table(name="bannerlink")
public class BannerLink{
    @Id
    @GeneratedValue
    private int id;
    private String label;

    @ManyToOne
    @JoinColumn(name = "bannerId")
    private Banner banner;
    ...
}


@Entity
@Table(name = "banner")
public class Banner {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String logo;
    private String textColor;
    private String backgroundColor;
    private int studyId;

    @OneToMany(
        mappedBy = "banner",
        cascade = CascadeType.ALL,
        fetch=FetchType.LAZY,
        targetEntity = BannerLink.class
    )
    private List<BannerLink> links;

    public Banner() {
    }
    ...
 } 

我还定义了一个DAO。

public interface BannerDAO extends JpaRepository<Banner, Integer> {

    @Query("select distinct banner FROM Banner banner join BannerLink bl where banner.studyId = :studyId")
    Banner getBannerByStudyId(@Param("studyId") int studyId);
}

但是,当我运行DAO方法getBannerByStudyId时,出现异常     “ com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:您的SQL语法有错误;请查看与您的MariaDB服务器版本相对应的手册,以在第1行的'where banner0_.studyId = 17'附近使用正确的语法“

打印出Hibernate生成的RAW SQL会显示INNER JOIN ON子句中缺少参数。

 Hibernate: 
     select
         distinct banner0_.id as id1_0_,
         banner0_.backgroundColor as backgrou2_0_,
         banner0_.logo as logo3_0_,
         banner0_.studyId as studyId4_0_,
         banner0_.textColor as textColo5_0_ 
     from
         banner banner0_ 
     inner join
         bannerlink bannerlink1_ 
             on 
     where
         banner0_.studyId=?

有什么想法我在做什么错吗?

4 个答案:

答案 0 :(得分:2)

您的查询错误。正确的查询是>

"select distinct banner FROM Banner banner fetch join banner.links where banner.studyId = :studyId"

我理解您的问题的方式是,您希望获取studyId的所有横幅及其对应的链接。如果我错了,请纠正我。上面的查询正在完成这项工作。

答案 1 :(得分:0)

您为什么需要Join,这是某种隐式过滤器吗?如我所见,studyId位于Banner中,因此只需删除查询并将函数名称更改为findOneByStudyId。同时删除参数注释。然后,如果您需要链接信息,则只需调用getter即可,因为它会延迟获取。 但是,如果您需要该连接,我会这样写(未经测试):     从Banner b,BannerLink bl中选择DISTINCT b。b.studyId =:studyId

答案 2 :(得分:0)

同意@kSp-如果您使用的是Spring Data JPA,则没有理由自己编写此查询,也无需使用它的功能来基于方法名称生成查询。否则,如果您需要自己编写,请尝试使用适当的JPQL连接(例如,

)编写查询

SELECT b from Banner b JOIN b.links WHERE b.studyId = :studyId

答案 3 :(得分:0)

是的!花了我很长时间才弄清楚!

有两种加入方式。如果要按原样加入,则必须在实体之间指定要加入的属性。 JPA不会猜测。

所以您必须这样做:

@Query("select distinct b FROM Banner b join BannerLink bl ON b.id = bl.bannerId WHERE b.studyId = :studyId") Banner getBannerByStudyId(@Param("studyId") int studyId);

但是,您几乎应该始终指定用于进行联接的父级属性,即该属性是子级的集合。 这样,您就可以告诉JPA如何联接表,并且只需为其提供Where子句即可:

@Query("select distinct b FROM Banner b join b.links bl WHERE b.studyId = :studyId") Banner getBannerByStudyId(@Param("studyId") int studyId);

参考:https://www.objectdb.com/java/jpa/query/jpql/from