1

我想在 PostgreSQL 中执行以下操作(使用 Hibernate):

 ALTER TABLE fruits ADD CONSTRAINTS id ON DELETE CASCADE;

显然,我上面的代码不起作用,所以我正在寻找正确的语句。

如果我不能这样做,那么以下内容如何:

我的表中有一堆数据fruitsidin 字段fruits被 table 用作外键grapes。我需要删除一个特定的行,fruits并且我希望删除级联到并删除其中具有指定的grapes所有条目。我怎么做?grapesid

delete from fruits where id = 1 cascade; 

注意:我不想加入并删除grape. 这只是一个例子。在实际应用中,大量表依赖于fruits.

由于我使用的是 Hibernate,对于我使用 delete 语句的情况,hibernate 可以帮助做到吗?
或者我可以使用 PostgreSQL 中的信息模式或系统目录来执行此操作吗?

4

4 回答 4

4

您描述的是使用该选项的教科书外键约束。ON DELETE CASCADE

SQLgrapes中,您可以在场景中创建表时隐式创建它:

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在您的情况下)并强制引用完整性

于 2012-07-20T16:28:33.950 回答
1

这是一种单向的父子关系,您希望父级的更改向下级联到子级,反之则不行。使用注解,我们可以做到这一点。在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子级。

于 2012-07-18T02:54:09.183 回答
1

我找到了答案:

    //in Fruit object
    @OneToMany(mappedBy = "fruit", orphanRemoval=true)
    private List<Grape> grapes;

   //in Grape object
   @OneToOne
   private Fruit fruit;
于 2012-07-23T05:10:47.840 回答
0

动机

这对我不起作用,我设置了

<property name="show_sql">true</property> 

并且输出没有说明任何类似的内容...ON DELETE CASCADE...

我找到了另一个对我有用的解决方案:

假设您有一个作者类和一个作者书籍类,并且您希望在删除作者时自动删除所有书籍(通过休眠,sql-query,...),并且您不能(总是)删除的原因是会话.删除()。

也许:

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 设置——并且您必须实施一个策略来处理会话中对象的删除!

于 2014-10-17T15:22:42.777 回答