jpa - JPA 继承:查询因未知列而失败
问题描述
在使用 EclipseLink v2.7.4 时执行以下 JPA 查询:
SELECT pr FROM AbstractProduct pr WHERE pr.shelve.superMarket.id = :1 ORDER BY pr.sortOrder
给出以下错误:
Unknown column 't0.SORTORDER' in 'order clause'
Error Code: 1054
Call: SELECT t2.ID, t2.SORTORDER, t2.SHELVE_ID FROM APPLE t2, SHELVE t1 WHERE ((t1.SUPERMARKET_ID = ?) AND (t1.ID = t2.SHELVE_ID)) ORDER BY t0.SORTORDER
bind => [12]
该查询引用 t0 但在生成的查询中没有任何地方定义 t0 是哪个表。
这些是我正在使用的实体:
@Entity
public class SuperMarket {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@OneToMany(mappedBy = "superMarket")
List<Shelve> shelves;
}
@Entity
public class Shelve {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
protected SuperMarket superMarket;
@OneToMany(mappedBy = "shelve")
protected List<AbstractProduct> products;
}
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractProduct {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
protected Shelve shelve;
protected long sortOrder;
}
@Entity
public class Apple extends AbstractProduct {
}
@Entity
public class Banana extends AbstractProduct {
}
这会导致以下查询:
CREATE TABLE SUPERMARKET (ID BIGINT NOT NULL, PRIMARY KEY (ID));
CREATE TABLE SHELVE (ID BIGINT NOT NULL, SUPERMARKET_ID BIGINT, PRIMARY KEY (ID));
CREATE TABLE APPLE (ID BIGINT NOT NULL, SORTORDER BIGINT, SHELVE_ID BIGINT, PRIMARY KEY (ID));
CREATE TABLE BANANA (ID BIGINT NOT NULL, SORTORDER BIGINT, SHELVE_ID BIGINT, PRIMARY KEY (ID));
CREATE TABLE ABSTRACTPRODUCT (SHELVE_ID BIGINT);
最后一个表 ABSTRACTPRODUCT 不应该创建,因为它是一个抽象 Java 实体,我使用的是每个类继承样式的表。这似乎是 eclipselink 中的一个错误,它也在这个问题中进行了讨论:Understanding of TABLE_PER_CLASS with keys in eclipselink它是继承与 OneToMany 关系的组合似乎触发了 create table 语句。不确定此错误是否与我在开始时提到的查询错误有关。我认为不是,因为该表甚至没有排序顺序字段。
当我删除 ORDER BY 子句时,查询将成功执行。当我将查询更改为仅向上一级时,它也会成功执行:
SELECT pr FROM AbstractProduct pr WHERE pr.shelve.id = :1 ORDER BY pr.sortOrder
对于测试,我摆脱了继承,让 Shelve 实体直接与 Apple 建立 OneToMany 关系,其中 Apple 没有扩展任何其他类,在这种情况下,查询也成功执行。但我需要抽象类和继承。
知道为什么在这种情况下生成的查询是错误的吗?
正如下面的答案所述,我可以使用不同的继承策略以不同的方式解决这个问题。我选择每个类类型的表,因为这允许我在查询中使用抽象实体,而具体类获得一个包含所有字段的表。我希望这有助于在从具体类中进行大量插入和选择时提高性能,因为这只涉及单个数据库表。
更新我认为这是 EclipseLink 中的一个错误我创建了两个错误报告: https://bugs.eclipse.org/bugs/show_bug.cgi?id=549866用于创建表的抽象类 https://bugs.eclipse.org /bugs/show_bug.cgi?id=549868查询中的错误
解决方案
我能够用继承策略重现您的问题TABLE_PER_CLASS
。一旦我将查询更改为InheritanceType.JOINED
并重新创建数据库的模式(在我的例子中:PostgreSQL 10.9),查询就会按预期执行。
所以代码应该改成:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class AbstractProduct {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@ManyToOne
protected Shelve shelve;
protected long sortOrder;
}
请注意:
- 我将缺少的
@ManyToOne
注释添加到属性shelve
中。 @ManyToOne
也应该添加到protected SuperMarket superMarket;
实体中Shelve
。
生成的数据库架构如下所示:
CREATE TABLE public.abstractproduct
(
id bigint NOT NULL,
dtype character varying(31) COLLATE pg_catalog."default",
sortorder bigint,
shelve_id bigint,
CONSTRAINT abstractproduct_pkey PRIMARY KEY (id),
-- FK definitions left out for brevity
)
并且Apple
,例如,变为:
CREATE TABLE public.apple
(
id bigint NOT NULL,
CONSTRAINT apple_pkey PRIMARY KEY (id),
-- FK definitions left out for brevity
)
希望能帮助到你。
推荐阅读
- python-3.x - 如何在 python split 中获取像 www.example.com 这样的基本 url
- apache-spark - SparkSQL如何从时间字段中加减
- python - 是否可以从仅在 python 运行时知道的类动态继承?
- c# - 如何从另一个表单访问一个表单中的类的变量?
- database - 在频繁变化的前缀(~200,000)的基础上以优化的方式对十亿条记录进行分桶
- python - 如何在 IPython 提示符中重用现有的 sys.ps1 格式化程序?
- python - 当输入向量中有一些零时,运行 biLstm 模型将得到“浮动错误 8”
- java - 无法使用 IntelliJ 从 github 拉取项目
- jquery - 引导表单上的 JQuery UI 可排序
- azure - 是否可以在 Azure 应用服务中为来自同一 IP 地址的多个请求创建警报?