我想在 PostgreSQL 中执行以下操作(使用 Hibernate):
ALTER TABLE fruits ADD CONSTRAINTS id ON DELETE CASCADE;
显然,我上面的代码不起作用,所以我正在寻找正确的语句。
如果我做不到,那么以下怎么样:
我的表中有一堆数据
fruits
。 id
中的fruits
字段被表grapes
用作外键。我需要删除 fruits
中的特定行,并且希望删除级联到 grapes
并删除 grapes
中具有指定 id
的所有条目。我该怎么做?
delete from fruits where id = 1 cascade;
注意:我不想进行连接并删除
grape
中的相应数据。这只是一个例子。实际应用中大量的表依赖于fruits
。
由于我使用的是Hibernate,对于使用delete语句的情况,hibernate可以帮助完成吗?
或者我可以使用 PostgreSQL 中的信息模式或系统目录来完成此操作吗?
您所描述的是教科书外键约束使用
ON DELETE CASCADE
选项。
在 SQL 中,您可以在场景中创建表
grapes
时隐式创建它:
CREATE TABLE grapes (
grape_id int PRIMARY KEY
fruit_id int REFERENCES fruits(fruit_id) ON DELETE CASCADE
);
或者您可以稍后添加:
ALTER TABLE grapes
ADD CONSTRAINT grapes_fruit_id_fkey FOREIGN KEY (fruit_id)
REFERENCES fruits (fruit_id) ON DELETE CASCADE;
切勿为此直接编辑系统目录。使用专用的 DDL 命令。
请注意,外键约束需要引用列上的唯一索引或主索引(在您的情况下是
fruits.fruit_id
)并强制执行引用完整性。
这是一种单向的父子关系,您希望父级的更改能够级联到子级,但反之则不然。使用注释,我们可以实现这一点。在
fruits
实体中:
@Cascade(value = { org.hibernate.annotations.CascadeType.ALL,
org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
@OneToMany(fetch = FetchType.LAZY, mappedBy = "fruit")
public Set<Grape> getGrapes() {
return grapes;
}
在“葡萄”实体中:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fruit_id")
public Fruit getFruit() {
return fruit;
}
当您更新或删除父级
fruit
时,更改将自动级联到子级 grape
。
我找到了答案:
//in Fruit object
@OneToMany(mappedBy = "fruit", orphanRemoval=true)
private List<Grape> grapes;
//in Grape object
@OneToOne
private Fruit fruit;
动机
这对我不起作用,我设置了
<property name="show_sql">true</property>
并且输出没有声明类似
...ON DELETE CASCADE...
之类的内容。
我找到了另一个对我有用的解决方案:
假设您有一个作者类和一个作者书籍类,并且您希望在删除作者时自动删除所有书籍(通过 hibernate、sql-query...),并且有一些原因您不能(总是)删除通过 session.delete().
也许:
session.createSQLQuery("DELETE FROM author").executeUpdate();
解决方案
所以你的作者类可能看起来像这样:
@Entity
@Table(name = "author")
public class Author {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
@Column(name = "ID")
private Integer id;
@Column(name = "NAME")
private String name;
@OneToMany(mappedBy = "author")
private Set<Book> books;
...
课本看起来像这样:
@Entity
@Table(name = "book")
public class Book {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
@Column(name = "ID")
private Integer id;
@Column(name = "TITLE")
private String title;
@ManyToOne
@JoinColumn(name = "AUTHOR_ID", foreignKey = @ForeignKey(name = "FK_BOOK_author_AUTHOR_ID"))
private Author author;
...
技巧是使用
自行命名外键约束foreignKey = @ForeignKey(name = "FK_BOOK_author_AUTHOR_ID")
然后添加
<property name="hibernate.hbm2ddl.import_files">update.sql</property>
到您的hibernate.cfg.xml(不要忘记hibernate.hbm2ddl.auto)。然后,update.sql包含表约束的更新:
ALTER TABLE `book` DROP FOREIGN KEY `FK_BOOK_author_AUTHOR_ID`;
ALTER TABLE `book` ADD CONSTRAINT `FK_BOOK_author_AUTHOR_ID` FOREIGN KEY (`AUTHOR_ID`) REFERENCES `author`(`ID`) ON DELETE CASCADE;
所以 hibernate 总是能够删除/更改约束,因为它知道约束的名称 - 您还应该检查 @Cascade 设置 - 并且您必须实施一个关于如何处理会话中对象删除的策略!