【问题标题】:Hibernate generates wrong inner join query for MySQLHibernate 为 MySQL 生成错误的内部连接查询
【发布时间】:2015-07-22 05:53:07
【问题描述】:

我正在使用 JPA 开发我的第一个项目,使用 MySQL 作为我的数据库和 Hibernate 4.3.8 作为 Spring 4 Web 项目中的 JPA 提供程序。

在我的 Spring 配置中,我设置了数据库和方言:

HibernateJpaVendorAdapter hjpaVA = new HibernateJpaVendorAdapter();
hjpaVA.setDatabase(Database.MYSQL);
hjpaVA.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");

我试图得到这个给我带来麻烦的查询:

TypedQuery<KundeDTO> query = entityManager.createQuery("select new zdb.dto.KundeDTO(k.id, k.firma.firmenname, k.regnr, k.kategorie) 
from Kunde k where k.id = :id", KundeDTO.class);

这是 Hibernate 生成的 SQL:

select kunde0_.`id` as col_0_0_, firma1_.`firmenname` as col_1_0_, kunde0_.`regnr` as col_2_0_, kunde0_.id_kategorie as col_3_0_ 
from `zdb_e`.`Kunde` kunde0_, `zdb_e`.`Firma` firma1_ 
inner join `zdb_e`.`Kategorie` kategorie2_ on kunde0_.id_kategorie=kategorie2_.`id` 
where kunde0_.id_firma=firma1_.`id` and kunde0_.`id`=1;

注意,内连接上没有括号!

运行此语句会导致以下错误:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 
Unknown column 'kunde0_.id_kategorie' in 'on clause'

这里详细说明了异常的原因: mysql-unknown-column-in-on-clause

当我将括号添加到 where 和内部连接子句并直接针对数据库运行该语句时,它可以工作:

select kunde0_.`id` as col_0_0_, firma1_.`firmenname` as col_1_0_, kunde0_.`regnr` as col_2_0_, kunde0_.id_kategorie as col_3_0_ 
from (`zdb_e`.`Kunde` kunde0_, `zdb_e`.`Firma` firma1_ )
inner join `zdb_e`.`Kategorie` kategorie2_ on 
( kunde0_.id_kategorie=kategorie2_.`id` ) 
where kunde0_.id_firma=firma1_.`id` and kunde0_.`id`=1;

那么,我怎样才能说服 Hibernate 生成这样的查询呢?

更新:这里是实体

昆德

@Entity
public class Kunde implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Integer id;

    private Integer regnr;

    @OneToOne(optional=false)
    @JoinColumn(name="id_firma", nullable = false)
    private Firma firma;

    @OneToOne(optional=false)
    @JoinColumn(name="id_kategorie", nullable = false)
    private Kategorie kategorie;

    @OneToOne(optional=false)
    @JoinColumn(name="id_lieferregion", nullable = false)
    private Lieferregion lieferregion;

    // getters and setters....
}

公司

@Entity
@Table(name = "Firma")
public class Firma implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    private Integer id;

    @Column(name="firmenname")
    private String firmenname;
    @Column(name="uid")
    private String uid;

    @OneToOne(optional=false)
    @JoinColumn(name="id_anschrift", nullable = false)
    private Anschrift anschrift;

    @OneToMany(mappedBy="id_firma", fetch=FetchType.EAGER)
    private List<Person> personen;

    public Firma() {
        personen = new ArrayList<Person>();
    }
    // getters and setters....
}

类别

@Entity
public class Kategorie implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Integer id;

    private Integer nummer;
    private String bezeichnung;

    public Kategorie() {
    }

    public Kategorie(int kategorieId, int kategorieNummer, String kategorieBezeichnung) {
        this.id = kategorieId;
        this.nummer = kategorieNummer;
        this.bezeichnung = kategorieBezeichnung;
    }
    // getters and setters....
}

数据库架构

CREATE TABLE kategorie 
    (id INTEGER NOT NULL AUTO_INCREMENT, 
    nummer INTEGER NOT NULL, 
    bezeichnung VARCHAR(100) NOT NULL,
    PRIMARY KEY (id),        
    UNIQUE (nummer, bezeichnung)
    );

CREATE TABLE firma
    (ID INTEGER NOT NULL AUTO_INCREMENT, 
    firmenname VARCHAR(50) NOT NULL,
    uid VARCHAR(20) NOT NULL,
    url VARCHAR(100) NOT NULL,
    id_anschrift INTEGER NOT NULL,
    id_logo INTEGER,
    PRIMARY KEY (id),
    UNIQUE (uid),
    UNIQUE (firmenname),
    UNIQUE (id_anschrift),
    CONSTRAINT firma_fk1 FOREIGN KEY (id_anschrift) REFERENCES ANSCHRIFT (ID),
    CONSTRAINT firma_fk2 FOREIGN KEY (id_logo) REFERENCES logo (ID));

CREATE TABLE kunde 
    (id INTEGER NOT NULL AUTO_INCREMENT, 
    regnr INTEGER NOT NULL,
    id_kategorie INTEGER NOT NULL,
    id_firma INTEGER NOT NULL,
    id_benutzer INTEGER,
    id_lieferregion INTEGER NOT NULL,
    PRIMARY KEY (id), 
    UNIQUE (regnr, id_kategorie),
    UNIQUE (id_firma),
    UNIQUE (id_benutzer),
    CONSTRAINT kunde_fk1 FOREIGN KEY (id_firma) REFERENCES firma (id),
    CONSTRAINT kunde_fk2 FOREIGN KEY (id_benutzer) REFERENCES benutzer (id),
    CONSTRAINT kunde_fk3 FOREIGN KEY (id_kategorie) REFERENCES kategorie (id),
    CONSTRAINT kunde_fk4 FOREIGN KEY (id_lieferregion) REFERENCES lieferregion (id)
    );

进一步测试

问题在于 from 子句中缺少括号。

直接针对数据库:

select k.id, k.regnr, f.firmenname from (Kunde k, Firma f) JOIN kategorie kat on k.id_kategorie = kat.id where k.id = 1 and k.id_firma = f.id;

有效!

select k.id, k.regnr, f.firmenname from Kunde k, Firma f JOIN kategorie kat on k.id_kategorie = kat.id where k.id = 1 and k.id_firma = f.id;

不起作用:“on 子句”中的未知列“k.id_kategorie”

为什么我什至需要在 from 子句上加上括号?
我怎样才能让 Hibernate 把它们放进去?

【问题讨论】:

  • 该错误与您链接的错误不同。查询中的 ON 子句后面没有 AND,并且该错误清楚地说明了不存在的列。检查您的数据库架构。
  • @JBNizet OP 说当他添加括号时该语句有效......强烈暗示列确实存在。
  • 粘贴您的昆德语和类别课程。你也可以这样尝试“select new zdb.dto.KundeDTO(k.id, k.firma.firmenname, k.regnr, kat) from Kunde k JOIN k.kategorie kat where k.id = :id”跨度>
  • @JBNizet 架构似乎正确,所有列都存在。
  • @jgr 试过了。 (相应地编辑了我的问题)问题是 from 子句上的括号。

标签: java mysql spring hibernate jpa


【解决方案1】:

我没有让它与 JPQL 一起工作,所以我按照 jgr 在 cmets 中的建议做了,并编写了我自己的 sql 本机查询:

String sql = "select k.id, f.firmenname, k.regnr, kat.id, kat.nummer, kat.bezeichnung from (zdb_e.Kunde k, zdb_e.Firma f) JOIN zdb_e.kategorie kat on k.id_kategorie = kat.id where k.id = :id and k.id_firma = f.id;";
Query query =  entityManager.createNativeQuery(sql, schemaName), "KundenListeRow");
query.setParameter("id", id);
return (KundeDTO) query.getSingleResult();

为了映射到我的 Pojo KundeDTO,我将 @SqlResultSetMapping 添加到 Kunde 实体:

@Entity
@SqlResultSetMapping(name = "KundenListeRow",
classes = {
    @ConstructorResult(targetClass = KundeDTO.class,
            columns = {
                    @ColumnResult(name = "id"),
                    @ColumnResult(name = "firmenname"),
                    @ColumnResult(name = "regnr"),
                    @ColumnResult(name = "kat.id"),
                    @ColumnResult(name = "kat.nummer"),
                    @ColumnResult(name = "kat.bezeichnung")
                    }
            )
  })
public class Kunde implements Serializable {
     ....
}

以及DTO中对应的构造函数:

public class KundeDTO {
    int id;
    String firmenname;
    Kategorie k;
    int regnr;

    public KundeDTO(int id, String firmenname, int regnr, int kategorieId, int kategorieNummer, String kategorieBezeichnung) {
        this.id = id;
        this.firmenname = firmenname;
        this.regnr = regnr;
        this.k = new Kategorie(kategorieId, kategorieNummer, kategorieBezeichnung);
    }
    public KundeDTO() {
    }
}

正如我所说,它有效。不过这是不理想的。使用 JPQL,我可以使用 TypedQuery 而不必处理 resultSetMapping。

当然,我仍然不知道为什么我的 JPQL 不起作用。 :-)

【讨论】:

    猜你喜欢
    • 2013-08-11
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    相关资源
    最近更新 更多