Hibernate 找不到正确的外键
Posted
技术标签:
【中文标题】Hibernate 找不到正确的外键【英文标题】:Hibernate cant find the correct foreign key 【发布时间】:2013-10-23 09:28:14 【问题描述】:我遇到了一个问题,即休眠尝试删除不存在的外键而不是存在的外键。我的场景是这样的。
我想运行一个 junit 测试,在测试之前我想创建数据库,在测试之后我想删除它。为此,我使用 hibernate create-drop 属性。然而,棘手的部分是我想创建自己的表作为测试新添加的 sql 并验证一旦我将其部署到生产数据库服务器后它会正常运行的方式。那么会发生什么
Hibernate 自动创建表 Hibernate 创建外键关系 Hibernate 运行我的删除表脚本(由于没有数据因此成功,因此没有破坏外键规则) Hibernate 运行我的创建表脚本 Hibernate 运行我的添加外部约束脚本 Hibernate 运行我的插入数据脚本 测试已执行 Hibernate 尝试删除外键但失败。hibernate 无法删除它的原因是它试图删除 hibernate 创建的那个,而不是我的脚本创建的那个。
知道如何强制休眠找出实际的外键吗?有什么办法可以解决这个问题?
谢谢大家
hibernate 为其创建表的类
TodoGroup.java
@Entity
@Table(name = "ToDoGroups")
public class ToDoGroup implements Serializable
@Id
@GeneratedValue
private Long id;
@Column(name = "Name", length = 50)
private String name;
@ManyToOne
@JoinColumn(name = "UserSettingsId")
@XmlTransient
private UserSettings userSettings;
@OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private List<ToDoItem> items;
休眠添加约束
alter table ToDoGroups
add constraint FK790BA1FAFE315596
foreign key (UserSettingsId)
references UserSettings
运行我自己的表,因为没有数据,所以我可以删除 hibernate 创建的内容以验证我的 sql
DROP TABLE IF EXISTS ToDoGroups;
CREATE TABLE ToDoGroups (ID BIGINT NOT NULL IDENTITY, Name VARCHAR(50) NOT NULL, UserSettingsId BIGINT NOT NULL, PRIMARY KEY (ID));
ALTER TABLE ToDoGroups ADD FOREIGN KEY (UserSettingsID) REFERENCES UserSettings (ID);
drop fk 它试图执行
alter table ToDoGroups drop constraint FK790BA1FAFE315596
java.sql.SQLException: Constraint not found FK790BA1FAFE315596 in table: TODOGROUPS in statement [alter table ToDoGroups drop constraint FK790BA1FAFE315596]
尝试删除由于我在 create.sql 脚本中设置的约束而失败的表
drop table ToDoGroups if exists
java.sql.SQLException: Table is referenced by a constraint in table SYS_REF_SYS_FK_808_810 table: TODOITEMS in statement [drop table ToDoGroups if exists]
更新
我还注意到,当它在创建表之前首次启动时休眠(所以这是在我的脚本运行之前的方式),尝试删除外键以删除任何存在的表。
那么hibernate是如何知道使用什么外键的呢?它使用与
相同的密钥它执行的第一条语句
alter table ToDoGroups drop constraint FK790BA1FAFE315596
然后它会删除所有表
drop table ToDoGroups if exists
然后它创建表
create table ToDoGroups (
id bigint generated by default as identity (start with 1),
Name varchar(50),
UserSettingsId bigint,
primary key (id)
)
然后它添加相同的 FK
alter table ToDoGroups
add constraint FK790BA1FAFE315596
foreign key (UserSettingsId)
references UserSettings
我想我的问题是hibernate如何知道使用什么FK。当甚至没有表时,它在第一个 drop 语句中使用了相同的 FK。后来它使用一些FK来创建关系。 hibernate不应该先检查表是否存在,然后再尝试确定FK是什么?
【问题讨论】:
为此使用junit不是一个好主意。 使用junit测试恰好将结果写入数据库的业务逻辑不是一个好主意吗?怎么来的? 您的业务逻辑不应依赖于数据库行为。 JUnit 适用于业务逻辑,但您不应该将它用于数据库测试。还有其他框架,例如 dbunit。 好吧,我的业务级别将结果保存到数据库中,所以我需要访问数据库来验证结果。我想我可以将它分成两部分,并在上面使用一种方法来获取业务层的结果并将其传递给 db,但可以说现在我会坚持这一点(即使我改变它并使我的层更多复杂我会遇到同样的问题,那就是如何强制休眠使用正确的外键来伪造它创建的外键) 你能添加一些关于外键的代码来帮助我理解问题吗? 【参考方案1】:据我了解,您的问题是您自己的脚本和休眠不使用相同的约束名称。
你可以通过这个注解在你的关系上指定一个hibernate使用的约束名称:
@ForeignKey(name = "fk_UserSettings")
此外,在您的 create.sql 中:
ALTER TABLE ToDoGroups ADD CONSTRAINT fk_UserSettings FOREIGN KEY (UserSettingsID) REFERENCES UserSettings (ID);
我想我的问题是hibernate如何知道使用什么FK。当甚至没有表时,它在第一个 drop 语句中使用了相同的 FK。后来它使用一些FK来创建关系。 hibernate不应该先检查表是否存在,然后再尝试确定FK是什么?
hibernate使用的外键名是
的串联"FK_" + hashcode of referenced entity name + hash code of referenced columns name on that entity.
所以它不是一个随机生成的密钥(你会看到如果你改变你的实体名称它会改变)。这就是 hibernate 知道要删除的 fk 的名称的方式(hibernate 期望约束是由 hibernate 使用这种众所周知的命名策略创建的)。
Hibernate 使用约束的名称来操作它。它不会比较与表关联的约束中编码的“规则”来查看约束是否已经存在。
【讨论】:
那么hibernate没有办法自己解决这个问题吗? 你的意思是你希望hibernate能够看到你已经在你的数据库上运行了一个自定义脚本并在其中指定了约束名称? (我仍然不确定是否真的理解这个问题) 请阅读最后的更新,也许它会更有意义。但简而言之,是的,我希望 hibernate 能够检查 FK 使用的是什么,而不是使用它想要的任何东西。 好吧,这是有道理的。为了使用自定义 fk,我需要指定它,如果没有,休眠将尝试使用它自己的。 Tnx以上是关于Hibernate 找不到正确的外键的主要内容,如果未能解决你的问题,请参考以下文章
使用windows打开一个文本时,鼠标右键找不到notepad