【发布时间】:2014-02-01 22:29:22
【问题描述】:
我正在测试 JPA2.1 和新的“模式生成”功能。为此,我在 HyperSQL 数据库下测试了两个实现:
- EclipseLink 2.5.2-M1,它是参考实现。
- 休眠 4.3
我对实现没有任何偏好(甚至对性能也没有)。我测试了 EclipseLink,因为它是第一个可用的 JPA2.1 实现,但是现在,Hibernate 4.3 就在这里并且符合 JPA2.1。我唯一想要的就是从 JPA 提供者那里获得一些独立的东西——除了配置(比如缓存、日志记录、静态编织......)。
至于模式生成,有几个方面让我很感兴趣:
- 我对 EclipseLink 的默认命名策略不满意:实体类名或字段/属性名大写,使其不可读。而且我不会扩展会话定制器(我尝试过一次,我认为放置注释更容易,更危险......)。
- 我不喜欢在查询中使用大写;好吧,这是个人喜好,但我在 linux 上也遇到了 mySQL 的问题,因为它们不遵循 标识符,并且关键字不区分大小写,除非你双引号它们 SQL 成语。
- 默认情况下,Hibernate 并没有好多少,但可以使用
ImprovedNamingStrategy改进命名策略。遗憾的是,它没有用明确的名称命名外键:FK_8gc2pk9u5bsbhpi91x93c77o不是明确的,而fk_foobar_sample是。
因此,我添加了@Table、@JoinColumn 和@Column 注释来强制我的命名策略,现在我被外键生成阻止了,它的支持似乎很差(符合 JPA2.1 时):
- Hibernate 希望我使用
@org.hibernate.annotations.ForeignKey,为此我需要注释字段或属性。但它是一个休眠注解,因此它不符合 JPA2.1。 - EclipseLink 从不生成外键约束,除非我将
@JoinColumn和foreignKey与@ForeignKey(name="...")放在一起。但是,虽然它生成了一个外键,但缺少定义(即:ALTER TABLE foobar ADD CONSTRAINT fk_foobar_zorg FOREIGN KEY () REFERENCES ()),而根据 Javadoc,它应该存在。 -
@ManyToOne是 Hibernate 生成外键所必需的(抛出异常),而 EclipseLink 不需要。我不明白为什么需要它:如果引用的类型注释为@Entity,那么当它可以完美地从引用的类中推断出来时,我为什么要放置@OneToOne、@ManyToOne、@OneToMany和@ManyToMany。 - EclipseLink 不会为使用
@JoinColumn注释但未设置foreignKey的字段生成外键约束。
我应该怎么做才能以纯 JPA2.1 的方式完成工作?
来源
由于我的示例案例太大而无法放在 Stackoverflow 上,你会发现 an archive 有 4 个 maven 3 项目:
- jpa2.1-parent : 父项目 (POM)
- jpa2.1-eclipselink :带有
@Table和@JoinColumn注释的EclipseLink 2.5.2-M1。 - jpa2.1-eclipselink-default : EclipseLink 2.5.2-M1 没有
@Table和@JoinColumn注释和默认命名策略 - jpa2.1-hibernate:具有自定义名称的 Hibernate 4.3。
- jpa2.1-hibernate-default : Hibernate 4.3 没有
@Table和@JoinColumn注释和默认命名策略
只需在根项目上运行mvn test,然后运行您喜欢的任何差异工具:
colordiff ./jpa2.1-eclipselink/database-create.sql ./jpa2.1-hibernate/database-create.sql
vimdiff ./jpa2.1-eclipselink/database-create.sql ./jpa2.1-hibernate/database-create.sql
diff ./jpa2.1-eclipselink/database-create.sql ./jpa2.1-hibernate/database-create.sql
kdiff3 ./jpa2.1-eclipselink/database-create.sql ./jpa2.1-hibernate/database-create.sql
也可以使用 Eclipse 的 Maven 插件将 POM 导入 Eclipse(在 Kepler 上测试)。
生成的 SQL
供参考,这里是不同SQL文件的结果(drop文件也是错误的,只是因为约束名称没有重载)。
EclipseLink
如您所见,外键约束在语法上是无效的; foobar 上缺少两个约束(一个到 zorg,另一个到 grumph)。
CREATE TABLE foobar (ID BIGINT NOT NULL, grumph_id BIGINT, sample_id BIGINT, zorg_id BIGINT, PRIMARY KEY (ID))
CREATE TABLE foobar_getter (ID BIGINT NOT NULL, grumph_id BIGINT, sample_id BIGINT, zorg_id BIGINT, PRIMARY KEY (ID))
CREATE TABLE sample (ID BIGINT NOT NULL, PRIMARY KEY (ID))
CREATE TABLE zorg (ID BIGINT NOT NULL, PRIMARY KEY (ID))
CREATE TABLE grumph (ID BIGINT NOT NULL, PRIMARY KEY (ID))
ALTER TABLE foobar ADD CONSTRAINT fk_foobar_zorg FOREIGN KEY () REFERENCES ()
ALTER TABLE foobar_getter ADD CONSTRAINT fk_foobar_getter_zorg FOREIGN KEY () REFERENCES ()
ALTER TABLE foobar_getter ADD CONSTRAINT fk_foobar_getter_sample FOREIGN KEY () REFERENCES ()
EclipseLink(无@Table、@JoinColumn)
这并不奇怪:如果 EclipseLink 不能生成至少正确的东西,它就不会被使用。
CREATE TABLE FOOBAR (ID BIGINT NOT NULL, GRUMPH_ID BIGINT, SAMPLE_ID BIGINT, ZORG_ID BIGINT, PRIMARY KEY (ID))
CREATE TABLE FOOBARGETTER (ID BIGINT NOT NULL, GRUMPH_ID BIGINT, SAMPLE_ID BIGINT, ZORG_ID BIGINT, PRIMARY KEY (ID))
CREATE TABLE SAMPLE (ID BIGINT NOT NULL, PRIMARY KEY (ID))
CREATE TABLE ZORG (ID BIGINT NOT NULL, PRIMARY KEY (ID))
CREATE TABLE GRUMPH (ID BIGINT NOT NULL, PRIMARY KEY (ID))
ALTER TABLE FOOBAR ADD CONSTRAINT FK_FOOBAR_SAMPLE_ID FOREIGN KEY (SAMPLE_ID) REFERENCES SAMPLE (ID)
ALTER TABLE FOOBAR ADD CONSTRAINT FK_FOOBAR_GRUMPH_ID FOREIGN KEY (GRUMPH_ID) REFERENCES GRUMPH (ID)
ALTER TABLE FOOBAR ADD CONSTRAINT FK_FOOBAR_ZORG_ID FOREIGN KEY (ZORG_ID) REFERENCES ZORG (ID)
ALTER TABLE FOOBARGETTER ADD CONSTRAINT FK_FOOBARGETTER_SAMPLE_ID FOREIGN KEY (SAMPLE_ID) REFERENCES SAMPLE (ID)
ALTER TABLE FOOBARGETTER ADD CONSTRAINT FK_FOOBARGETTER_ZORG_ID FOREIGN KEY (ZORG_ID) REFERENCES ZORG (ID)
ALTER TABLE FOOBARGETTER ADD CONSTRAINT FK_FOOBARGETTER_GRUMPH_ID FOREIGN KEY (GRUMPH_ID) REFERENCES GRUMPH (ID)
休眠
Hibernate 会忽略我的自定义外键名称,除非我使用它们的注释。
create table foobar (id bigint not null, grumph_id bigint, sample_id bigint, zorg_id bigint, primary key (id))
create table foobar_getter (id bigint not null, grumph_id bigint, sample_id bigint, zorg_id bigint, primary key (id))
create table grumph (id bigint not null, primary key (id))
create table sample (id bigint not null, primary key (id))
create table zorg (id bigint not null, primary key (id))
alter table foobar add constraint FK_45nw30c81ae209hokgmrs9gyy foreign key (grumph_id) references grumph
alter table foobar add constraint FK_b3pwyt79opfaopbjwaf23h11f foreign key (sample_id) references sample
alter table foobar add constraint hb_foobar_zorg foreign key (zorg_id) references zorg
alter table foobar_getter add constraint FK_1s2755a8mgvune6lhpfw8cifr foreign key (grumph_id) references grumph
alter table foobar_getter add constraint FK_slbhet4s26lh9ma4vh63ltctj foreign key (sample_id) references sample
alter table foobar_getter add constraint hb_foobar_getter_zorg foreign key (zorg_id) references zorg
【问题讨论】:
-
休眠部分似乎是一个合法的错误:hibernate.atlassian.net/browse/HHH-8783
-
当指定 ForeignKey 时,EclipseLink 将使用那里的内容来完全替换它将生成的内容。看起来您为此问题提交了错误 bugs.eclipse.org/bugs/show_bug.cgi?id=425656。
-
是的,我提交了错误。 @ForeignKey 的有效用法(对我来说)是重命名它,并且仅在极少数情况下覆盖它的生成方式(而不是“数据库可移植”)。
-
刚刚遇到了您报告的这个 EclipseLink 问题,所以在这里给您一个很好的解释。不幸的是,我看到没有人发现你的错误。确定这是一个错误。
标签: hibernate eclipselink java-7 jpa-2.1