Hibernate 使用错误的表名进行三级继承的 order by 表达式

2024-04-01

在我们的项目中,我们有不同类别呈现的不同用户类型。 我们有一个 BaseEntity 类作为@MappedSuperclass。 当我们尝试将用户类与 InheritanceType.JOINED 一起使用时,hibernate 会创建一条我们认为错误的 sql。

基础实体:

@MappedSuperclass
public abstract class BaseEntity implements java.io.Serializable {


private Integer id;

private Date createdDate = new Date();


public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED_DATE", nullable = true)
public Date getCreatedDate() {
    return createdDate;
}

public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
}

}

基础用户

@Entity
@Table(name = "BASE_USER")
@Inheritance(strategy = InheritanceType.JOINED)
@AttributeOverride(name = "id", column = @Column(name = "ID", nullable = false, insertable = false, updatable = false))
public abstract class BaseUser extends BaseEntity{


@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
@SequenceGenerator(name = "seq", sequenceName = "USER_SEQ", allocationSize = 1)
public Integer getId() {
    return super.getId();
}

}

User

@Entity
@Table(name = "FIRM_USER")
public class FirmUser extends BaseUser {

private String name;

@Column(name = "name")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

示例代码

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
    try {
        sessionFactory = new AnnotationConfiguration()
                .addAnnotatedClass(FirmUser.class)
                .addAnnotatedClass(BaseUser.class)
                .addAnnotatedClass(BaseEntity.class)
                .configure()
                .buildSessionFactory();
    } catch (Throwable ex) {
        throw new ExceptionInInitializerError(ex);
    }
}

public static Session getSession() throws HibernateException {
    return sessionFactory.openSession();
}

public static void main(String[] args) {
    getSession().save(new FirmUser());

    Query query = getSession().createQuery("select distinct a from FirmUser a ORDER BY a.id");
    query.list();

}
}

对于这个hql

select distinct a from FirmUser a ORDER BY a.id

hibernate创建这个sql

select distinct firmuser0_.ID as ID1_0_,
       firmuser0_1_.CREATED_DATE as CREATED_2_0_,
       firmuser0_.name as name1_1_
from   FIRM_USER firmuser0_ 
       inner join BASE_USER firmuser0_1_ on firmuser0_.ID=firmuser0_1_.ID
order by firmuser0_1_.ID

“按firmuser0_1_.ID 排序”原因

 HSQLDB  : ORDER BY item should be in the SELECT DISTINCT list:

or

 ORACLE : ORA-01791: not a SELECTed expression

但是firmuser0_.ID位于select子句中,我们实际上尝试按FirmUser(firmuser0_)的ID而不是BaseUser(firmuser0_1_)的ID进行排序

如果我们不使用 BaseEntity,它会按预期工作。

为什么hibernate使用连接类来排序,如果它也继承自另一个类?


我复制了你的测试用例,你可以在GitHub https://github.com/vladmihalcea/hibernate-master-class/blob/master/core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/inheritance/InheritanceGroupByTest.java.

肯定存在 Hibernate bug,因为当使用别名时,select 子句使用子类 ID,而 ORDER BY 使用基类 id,由于它不在 select 子句中,因此会抛出异常:

SELECT inheritanc0_.id             AS ID1_0_,
       inheritanc0_1_.created_date AS CREATED_2_0_,
       inheritanc0_.NAME           AS name1_1_
FROM   firm_user inheritanc0_
       INNER JOIN base_user inheritanc0_1_
               ON inheritanc0_.id = inheritanc0_1_.id
ORDER  BY inheritanc0_1_.id 

注意ORDER BY inheritanc0_1_.id,本来应该是ORDER BY inheritanc0_.id反而。

解决方法1:

重写不带别名的查询:

List<FirmUser> result1 = (List<FirmUser>) session.createQuery("from FirmUser order by id").list(); 

正确生成的 SQL:

SELECT inheritanc0_.id             AS ID1_0_,
       inheritanc0_1_.created_date AS CREATED_2_0_,
       inheritanc0_.NAME           AS name1_1_
FROM   firm_user inheritanc0_
       INNER JOIN base_user inheritanc0_1_
               ON inheritanc0_.id = inheritanc0_1_.id
ORDER  BY inheritanc0_1_.id 

解决方法2:

或者也指定 subclass.id,但这会产生子类和子类实体元组的数组:

List<Object[]> result2 = (List<Object[]>) session.createQuery("select distinct a, a.id from FirmUser a order by id").list();

给出以下 SQL:

SELECT DISTINCT inheritanc0_1_.id           AS col_0_0_,
                inheritanc0_1_.id           AS col_1_0_,
                inheritanc0_.id             AS ID1_0_,
                inheritanc0_1_.created_date AS CREATED_2_0_,
                inheritanc0_.NAME           AS name1_1_
FROM   firm_user inheritanc0_
       INNER JOIN base_user inheritanc0_1_
               ON inheritanc0_.id = inheritanc0_1_.id
ORDER  BY inheritanc0_1_.id 

解决方法 3:

与往常一样,本机查询使您可以最终控制任何元组关联:

List<FirmUser> result3 = (List<FirmUser>) session.createSQLQuery(
        "select * " +
        "from FIRM_USER a " +
        "LEFT JOIN BASE_USER b ON a.id = b.id " +
        "order by a.id"
)
.addEntity("a", FirmUser.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();

您应该针对此问题填写 Hibernate 问题,因为它的行为不正常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hibernate 使用错误的表名进行三级继承的 order by 表达式 的相关文章

  • 如何测试 JUnit 测试的 Comparator?

    我需要测试 Compare 方法 但我对如何测试感到困惑 我可以看看该怎么做吗 public class MemberComparator implements Comparator
  • 如何查找 Android 设备中的所有文件并将它们放入列表中?

    我正在寻求帮助来列出 Android 外部存储设备中的所有文件 我想查找所有文件夹 包括主文件夹的子文件夹 有办法吗 我已经做了一个基本的工作 但我仍然没有得到想要的结果 这不起作用 这是我的代码 File files array file
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • 在浏览器中点击应用程序时播放框架挂起

    我正在 Play 中运行一个应用程序activator run 也许 5 次中有 3 次 它会挂起 当我去http localhost 9000 它就永远坐在那里旋转 我看到很多promise timed out错误也 我应该去哪里寻找这个
  • Java 页面爬行和解析之 Crawler4j 与 Jsoup

    我想获取页面的内容并提取其中的特定部分 据我所知 此类任务至少有两种解决方案 爬虫4j https github com yasserg crawler4j and Jsoup http jsoup org 它们都能够检索页面的内容并提取其
  • 如何在jsp代码中导入java库?

    我有以下jsp代码 我想添加 java io 等库 我怎样才能做到这一点
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Microsoft Graph 身份验证 - 委派权限

    我可以使用 Microsoft Graph 访问资源无需用户即可访问 https developer microsoft com en us graph docs concepts auth v2 service 但是 此方法不允许我访问需
  • Clip 在 Java 中播放 WAV 文件时出现严重延迟

    我编写了一段代码来读取 WAV 文件 大小约为 80 mb 并播放该文件 问题是声音播放效果很差 极度滞后 你能告诉我有什么问题吗 这是我的代码 我称之为doPlayJframe 构造函数内的函数 private void doPlay f
  • 反思 Groovy 脚本中声明的函数

    有没有一种方法可以获取 Groovy 脚本中声明的函数的反射数据 该脚本已通过GroovyShell目的 具体来说 我想枚举脚本中的函数并访问附加到它们的注释 Put this到 Groovy 脚本的最后一行 它将作为脚本的返回值 a la
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l
  • 检查 protobuf 消息 - 如何按名称获取字段值?

    我似乎无法找到一种方法来验证 protobuf 消息中字段的值 而无需显式调用其 getter 我看到周围的例子使用Descriptors FieldDescriptor实例到达消息映射内部 但它们要么基于迭代器 要么由字段号驱动 一旦我有
  • Java直接内存:在自定义类中使用sun.misc.Cleaner

    在 Java 中 NIO 直接缓冲区分配的内存通过以下方式释放 sun misc Cleaner实例 一些比对象终结更有效的特殊幻像引用 这种清洁器机制是否仅针对直接缓冲区子类硬编码在 JVM 中 或者是否也可以在自定义组件中使用清洁器 例
  • Tomcat 6找不到mysql驱动

    这里有一个类似的问题 但关于类路径 ClassNotFoundException com mysql jdbc Driver https stackoverflow com questions 1585811 classnotfoundex
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • 如何测试 spring-security-oauth2 资源服务器安全性?

    随着 Spring Security 4 的发布改进了对测试的支持 http docs spring io spring security site docs 4 0 x reference htmlsingle test我想更新我当前的
  • 休眠以持久保存日期

    有没有办法告诉 Hibernate java util Date 应该持久保存 我需要这个来解决 MySQL 中缺少的毫秒分辨率问题 您能想到这种方法有什么缺点吗 您可以自己创建字段long 或者使用自定义的UserType 实施后User
  • 如何修复“sessionFactory”或“hibernateTemplate”是必需的问题

    我正在使用 Spring Boot JPA WEB 和 MYSQL 创建我的 Web 应用程序 它总是说 sessionFactory or hibernateTemplate是必需的 我该如何修复它 我已经尝试过的东西 删除了本地 Mav
  • com.jcraft.jsch.JSchException:身份验证失败

    当我从本地磁盘上传文件到远程服务器时 出现这样的异常 com jcraft jsch JSchException Auth fail at org apache tools ant taskdefs optional ssh Scp exe
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐