2

我遇到了一个问题,即休眠尝试删除不存在的外键而不是存在的外键。我的场景看起来像这样。

我想运行一个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 是什么?

4

1 回答 1

3

据我了解,您的问题是您自己的脚本和休眠不使用相同的约束名称。

您可以在关系上使用此注释指定 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 使用约束的名称来操作它。它不会比较与表关联的约束中编码的“规则”,以查看约束是否已经存在。

于 2013-10-23T11:08:42.850 回答