我想在PostgreSQL中(使用Hibernate)执行以下操作:
ALTER TABLE fruits ADD CONSTRAINTS id ON DELETE CASCADE;
显然,我上面的代码不起作用,所以我正在寻找正确的语句。
如果我不能做到这一点,那么下面的怎么样:
我的表fruits
中有一堆数据。fruits
中的id
字段被表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>
并且输出没有任何类似CCD_ 17的状态。
我找到了另一个对我有效的解决方案:
假设你有一个作者类和一个作者书籍类,并且你想在删除作者时自动删除所有书籍(通过hibernate、sql查询…),并且有一些原因你不能(总是)通过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设置-并且你必须实现一个关于如何处理会话中对象删除的策略!