【问题标题】:JPA and Hibernate with missing INNER JOIN ON clauseJPA 和 Hibernate 缺少 INNER JOIN ON 子句
【发布时间】:2018-08-15 19:34:48
【问题描述】:

我正试图找出我在使用 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 行的 'wherebanner0_.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=?

任何想法我做错了什么?

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      是的!我花了很长时间才弄明白!

      有两种加入方式。如果您按原样加入,则在实体之间,您必须指定要加入的属性。 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

      【讨论】:

        【解决方案3】:

        为什么需要加入,这是某种隐式过滤器吗?正如我所见,studyId 在横幅中,所以只需删除查询并将函数名称更改为 findOneByStudyId。同时删除 Param 注释。然后,如果您需要链接信息,只需调用 getter,而不是懒惰地获取它。 但是,如果您需要该加入,我会这样写(未经测试): SELECT DISTINCT b FROM Banner b, BannerLink bl WHERE b.studyId = :studyId

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            猜你喜欢
            • 2015-07-31
            • 2010-11-04
            • 1970-01-01
            • 2014-02-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-10
            相关资源
            最近更新 更多